diff --git a/dom/plugins/PluginInstanceChild.cpp b/dom/plugins/PluginInstanceChild.cpp
--- a/dom/plugins/PluginInstanceChild.cpp
+++ b/dom/plugins/PluginInstanceChild.cpp
@@ -280,40 +280,43 @@ PluginInstanceChild::AnswerNPP_GetValue_
     NS_RUNTIMEABORT("shouldn't be called on non-linux platforms");
     return false;               // not reached
 
 #endif
 }
 
 bool
 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginScriptableNPObject(
-                                           PPluginScriptableObjectChild** value,
-                                           NPError* result)
+                                          PPluginScriptableObjectChild** aValue,
+                                          NPError* aResult)
 {
     AssertPluginThread();
 
     NPObject* object;
-    *result = mPluginIface->getvalue(GetNPP(), NPPVpluginScriptableNPObject,
-                                     &object);
-    if (*result != NPERR_NO_ERROR) {
-        return true;
+    NPError result = mPluginIface->getvalue(GetNPP(),
+                                            NPPVpluginScriptableNPObject,
+                                            &object);
+    if (result == NPERR_NO_ERROR && object) {
+        PluginScriptableObjectChild* actor = GetActorForNPObject(object);
+
+        // If we get an actor then it has retained. Otherwise we don't need it
+        // any longer.
+        PluginModuleChild::sBrowserFuncs.releaseobject(object);
+        if (actor) {
+            *aValue = actor;
+            *aResult = NPERR_NO_ERROR;
+            return true;
+        }
+
+        NS_ERROR("Failed to get actor!");
+        result = NPERR_GENERIC_ERROR;
     }
 
-    PluginScriptableObjectChild* actor = GetActorForNPObject(object);
-
-    // If we get an actor then it has retained. Otherwise we don't need it any
-    // longer.
-    PluginModuleChild::sBrowserFuncs.releaseobject(object);
-
-    if (!actor) {
-        *result = NPERR_GENERIC_ERROR;
-        return true;
-    }
-
-    *value = actor;
+    *aValue = nsnull;
+    *aResult = result;
     return true;
 }
 
 bool
 PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event,
                                            int16_t* handled)
 {
     _MOZ_LOG(__FUNCTION__);
diff --git a/dom/plugins/PluginInstanceParent.cpp b/dom/plugins/PluginInstanceParent.cpp
--- a/dom/plugins/PluginInstanceParent.cpp
+++ b/dom/plugins/PluginInstanceParent.cpp
@@ -159,44 +159,33 @@ PluginInstanceParent::AnswerNPN_GetValue
 bool
 PluginInstanceParent::InternalGetValueForNPObject(
                                          NPNVariable aVariable,
                                          PPluginScriptableObjectParent** aValue,
                                          NPError* aResult)
 {
     NPObject* npobject;
     NPError result = mNPNIface->getvalue(mNPP, aVariable, (void*)&npobject);
-    if (result != NPERR_NO_ERROR || !npobject) {
-        *aValue = nsnull;
-        *aResult = result;
-        return true;
+    if (result == NPERR_NO_ERROR) {
+        NS_ASSERTION(npobject, "Shouldn't return null and NPERR_NO_ERROR!");
+
+        PluginScriptableObjectParent* actor = GetActorForNPObject(npobject);
+        mNPNIface->releaseobject(npobject);
+        if (actor) {
+            *aValue = actor;
+            *aResult = NPERR_NO_ERROR;
+            return true;
+        }
+
+        NS_ERROR("Failed to get actor!");
+        result = NPERR_GENERIC_ERROR;
     }
 
-    PluginScriptableObjectParent* actor =
-      static_cast<PluginScriptableObjectParent*>(
-        AllocPPluginScriptableObject());
-
-    if (!actor) {
-        mNPNIface->releaseobject(npobject);
-        *aValue = nsnull;
-        *aResult = NPERR_OUT_OF_MEMORY_ERROR;
-        return true;
-    }
-
-    if (!CallPPluginScriptableObjectConstructor(actor)) {
-        mNPNIface->releaseobject(npobject);
-        DeallocPPluginScriptableObject(actor);
-        *aValue = nsnull;
-        *aResult = NPERR_GENERIC_ERROR;
-        return true;
-    }
-
-    actor->Initialize(const_cast<PluginInstanceParent*>(this), npobject);
-    *aValue = actor;
-    *aResult = NPERR_NO_ERROR;
+    *aValue = nsnull;
+    *aResult = result;
     return true;
 }
 
 bool
 PluginInstanceParent::AnswerNPN_GetValue_NPNVWindowNPObject(
                                          PPluginScriptableObjectParent** aValue,
                                          NPError* aResult)
 {
diff --git a/dom/plugins/PluginModuleChild.cpp b/dom/plugins/PluginModuleChild.cpp
--- a/dom/plugins/PluginModuleChild.cpp
+++ b/dom/plugins/PluginModuleChild.cpp
@@ -40,16 +40,17 @@
 #include "mozilla/plugins/PluginModuleChild.h"
 
 #ifdef OS_LINUX
 #include <gtk/gtk.h>
 #endif
 
 #include "nsILocalFile.h"
 
+#include "pratom.h"
 #include "nsDebug.h"
 #include "nsCOMPtr.h"
 #include "nsPluginsDir.h"
 
 #include "mozilla/plugins/PluginInstanceChild.h"
 #include "mozilla/plugins/StreamNotifyChild.h"
 #include "mozilla/plugins/BrowserStreamChild.h"
 #include "mozilla/plugins/PluginStreamChild.h"
@@ -233,23 +234,52 @@ PluginModuleChild::GetActorForNPObject(N
     AssertPluginThread();
     NS_ASSERTION(mObjectMap.IsInitialized(), "Not initialized!");
     NS_ASSERTION(aObject, "Null pointer!");
     PluginScriptableObjectChild* actor;
     return mObjectMap.Get(aObject, &actor) ? actor : nsnull;
 }
 
 #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)
+PluginModuleChild::NPObjectIsRegisteredForActor(
+                                            PluginScriptableObjectChild* aActor)
 {
     AssertPluginThread();
     NS_ASSERTION(mObjectMap.IsInitialized(), "Not initialized!");
-    NS_ASSERTION(aObject, "Null pointer!");
-    return mObjectMap.Get(aObject, nsnull);
+    NS_ASSERTION(aActor, "Null actor!");
+
+    SearchInfo info = { aActor, false };
+    mObjectMap.EnumerateRead(ActorSearch, &info);
+    return info.found;
 }
 #endif
 
 //-----------------------------------------------------------------------------
 // FIXME/cjones: just getting this out of the way for the moment ...
 
 // FIXME
 typedef void (*PluginThreadCallback)(void*);
@@ -897,43 +927,49 @@ _createobject(NPP aNPP,
     }
     else {
         newObject = reinterpret_cast<NPObject*>(_memalloc(sizeof(NPObject)));
     }
 
     if (newObject) {
         newObject->_class = aClass;
         newObject->referenceCount = 1;
+        NS_LOG_ADDREF(newObject, 1, "ChildNPObject", sizeof(NPObject));
     }
     return newObject;
 }
 
 NPObject* NP_CALLBACK
 _retainobject(NPObject* aNPObj)
 {
     AssertPluginThread();
 
 #ifdef DEBUG
     printf("[PluginModuleChild] %s: object %p, refcnt %d\n", __FUNCTION__,
            aNPObj, aNPObj->referenceCount + 1);
 #endif
-    ++aNPObj->referenceCount;
+    int32_t refCnt = PR_AtomicIncrement((PRInt32*)&aNPObj->referenceCount);
+    NS_LOG_ADDREF(aNPObj, refCnt, "ChildNPObject", sizeof(NPObject));
+
     return aNPObj;
 }
 
 void NP_CALLBACK
 _releaseobject(NPObject* aNPObj)
 {
     AssertPluginThread();
 
 #ifdef DEBUG
     printf("[PluginModuleChild] %s: object %p, refcnt %d\n", __FUNCTION__,
            aNPObj, aNPObj->referenceCount - 1);
 #endif
-    if (--aNPObj->referenceCount == 0) {
+    int32_t refCnt = PR_AtomicDecrement((PRInt32*)&aNPObj->referenceCount);
+    NS_LOG_RELEASE(aNPObj, refCnt, "ChildNPObject");
+
+    if (refCnt == 0) {
         if (aNPObj->_class && aNPObj->_class->deallocate) {
             aNPObj->_class->deallocate(aNPObj);
         } else {
             _memfree(aNPObj);
         }
     }
     return;
 }
diff --git a/dom/plugins/PluginModuleChild.h b/dom/plugins/PluginModuleChild.h
--- a/dom/plugins/PluginModuleChild.h
+++ b/dom/plugins/PluginModuleChild.h
@@ -144,17 +144,17 @@ public:
     bool RegisterNPObject(NPObject* aObject,
                           PluginScriptableObjectChild* aActor);
 
     void UnregisterNPObject(NPObject* aObject);
 
     PluginScriptableObjectChild* GetActorForNPObject(NPObject* aObject);
 
 #ifdef DEBUG
-    bool NPObjectIsRegistered(NPObject* aObject);
+    bool NPObjectIsRegisteredForActor(PluginScriptableObjectChild* aActor);
 #endif
 
 private:
     bool InitGraphics();
 
     std::string mPluginFilename;
     PRLibrary* mLibrary;
 
diff --git a/dom/plugins/PluginScriptableObjectChild.cpp b/dom/plugins/PluginScriptableObjectChild.cpp
--- a/dom/plugins/PluginScriptableObjectChild.cpp
+++ b/dom/plugins/PluginScriptableObjectChild.cpp
@@ -648,19 +648,20 @@ PluginScriptableObjectChild::~PluginScri
       if (!static_cast<ChildNPObject*>(mObject)->invalidated) {
         NS_WARNING("This should have happened already!");
         ScriptableInvalidate(mObject);
       }
     }
     else {
       PluginModuleChild::sBrowserFuncs.releaseobject(mObject);
     }
-    NS_ASSERTION(!PluginModuleChild::current()->NPObjectIsRegistered(mObject),
-                 "NPObject still registered!");
   }
+  NS_ASSERTION(!PluginModuleChild::current()->
+               NPObjectIsRegisteredForActor(this),
+               "NPObjects still registered for this actor!");
 }
 
 void
 PluginScriptableObjectChild::Initialize(PluginInstanceChild* aInstance,
                                         NPObject* aObject)
 {
   AssertPluginThread();
 
@@ -672,16 +673,17 @@ PluginScriptableObjectChild::Initialize(
     NS_ASSERTION(!object->parent, "Bad object!");
     object->parent = const_cast<PluginScriptableObjectChild*>(this);
 
     // We don't want to have the actor own this object but rather let the object
     // own this actor. Set the reference count to 0 here so that when the object
     // dies we will send the destructor message to the parent.
     NS_ASSERTION(aObject->referenceCount == 1, "Some kind of live object!");
     aObject->referenceCount = 0;
+    NS_LOG_RELEASE(aObject, 0, "ChildNPObject");
   }
   else {
     // Plugin-provided object, retain here. This should be the only reference we
     // ever need.
     PluginModuleChild::sBrowserFuncs.retainobject(aObject);
   }
 
   mInstance = aInstance;
diff --git a/dom/plugins/PluginScriptableObjectParent.cpp b/dom/plugins/PluginScriptableObjectParent.cpp
--- a/dom/plugins/PluginScriptableObjectParent.cpp
+++ b/dom/plugins/PluginScriptableObjectParent.cpp
@@ -781,33 +781,31 @@ PluginScriptableObjectParent::Initialize
     NS_ASSERTION(!object->parent, "Bad object!");
     object->parent = const_cast<PluginScriptableObjectParent*>(this);
 
     // We don't want to have the actor own this object but rather let the object
     // own this actor. Set the reference count to 0 here so that when the object
     // dies we will send the destructor message to the child.
     NS_ASSERTION(aObject->referenceCount == 1, "Some kind of live object!");
     object->referenceCount = 0;
+    NS_LOG_RELEASE(aObject, 0, "BrowserNPObject");
   }
   else {
     aInstance->GetNPNIface()->retainobject(aObject);
   }
 
   mInstance = aInstance;
   mObject = aObject;
 }
 
 bool
 PluginScriptableObjectParent::AnswerInvalidate()
 {
   if (mObject) {
     NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
-    if (mObject->_class && mObject->_class->invalidate) {
-      mObject->_class->invalidate(mObject);
-    }
     const NPNetscapeFuncs* npn = GetNetscapeFuncs(GetInstance());
     if (npn) {
       npn->releaseobject(mObject);
     }
     mObject = nsnull;
   }
   return true;
 }
diff --git a/ipc/glue/AsyncChannel.cpp b/ipc/glue/AsyncChannel.cpp
--- a/ipc/glue/AsyncChannel.cpp
+++ b/ipc/glue/AsyncChannel.cpp
@@ -50,16 +50,38 @@ struct RunnableMethodTraits<mozilla::ipc
 {
     static void RetainCallee(mozilla::ipc::AsyncChannel* obj) { }
     static void ReleaseCallee(mozilla::ipc::AsyncChannel* obj) { }
 };
 
 namespace mozilla {
 namespace ipc {
 
+AsyncChannel::AsyncChannel(AsyncListener* aListener)
+  : mTransport(0),
+    mListener(aListener),
+    mChannelState(ChannelClosed),
+    mMutex("mozilla.ipc.AsyncChannel.mMutex"),
+    mCvar(mMutex, "mozilla.ipc.AsyncChannel.mCvar"),
+    mIOLoop(),
+    mWorkerLoop()
+{
+    MOZ_COUNT_CTOR(AsyncChannel);
+}
+
+AsyncChannel::~AsyncChannel()
+{
+    MOZ_COUNT_DTOR(AsyncChannel);
+    if (!mChild && mTransport)
+        Close();
+    // we only hold a weak ref to the transport, which is "owned"
+    // by GeckoChildProcess/GeckoThread
+    mTransport = 0;
+}
+
 bool
 AsyncChannel::Open(Transport* aTransport, MessageLoop* aIOLoop)
 {
     NS_PRECONDITION(!mTransport, "Open() called > once");
     NS_PRECONDITION(aTransport, "need transport layer");
 
     // FIXME need to check for valid channel
 
diff --git a/ipc/glue/AsyncChannel.h b/ipc/glue/AsyncChannel.h
--- a/ipc/glue/AsyncChannel.h
+++ b/ipc/glue/AsyncChannel.h
@@ -85,35 +85,18 @@ public:
     class /*NS_INTERFACE_CLASS*/ AsyncListener: protected HasResultCodes
     {
     public:
         virtual ~AsyncListener() { }
         virtual Result OnMessageReceived(const Message& aMessage) = 0;
     };
 
 public:
-    AsyncChannel(AsyncListener* aListener) :
-        mTransport(0),
-        mListener(aListener),
-        mChannelState(ChannelClosed),
-        mMutex("mozilla.ipc.AsyncChannel.mMutex"),
-        mCvar(mMutex, "mozilla.ipc.AsyncChannel.mCvar"),
-        mIOLoop(),
-        mWorkerLoop()
-    {
-    }
-
-    virtual ~AsyncChannel()
-    {
-        if (!mChild && mTransport)
-            Close();
-        // we only hold a weak ref to the transport, which is "owned"
-        // by GeckoChildProcess/GeckoThread
-        mTransport = 0;
-    }
+    AsyncChannel(AsyncListener* aListener);
+    virtual ~AsyncChannel();
 
     // Open  from the perspective of the transport layer; the underlying
     // socketpair/pipe should already be created.
     //
     // Returns true iff the transport layer was successfully connected,
     // i.e., mChannelState == ChannelConnected.
     bool Open(Transport* aTransport, MessageLoop* aIOLoop=0);
     
diff --git a/ipc/glue/RPCChannel.cpp b/ipc/glue/RPCChannel.cpp
--- a/ipc/glue/RPCChannel.cpp
+++ b/ipc/glue/RPCChannel.cpp
@@ -56,16 +56,34 @@ struct RunnableMethodTraits<mozilla::ipc
 {
     static void RetainCallee(mozilla::ipc::RPCChannel* obj) { }
     static void ReleaseCallee(mozilla::ipc::RPCChannel* obj) { }
 };
 
 namespace mozilla {
 namespace ipc {
 
+RPCChannel::RPCChannel(RPCListener* aListener,
+                       RacyRPCPolicy aPolicy)
+  : SyncChannel(aListener),
+    mPending(),
+    mStack(),
+    mDeferred(),
+    mRemoteStackDepthGuess(0),
+    mRacePolicy(aPolicy)
+{
+    MOZ_COUNT_CTOR(RPCChannel);
+}
+
+RPCChannel::~RPCChannel()
+{
+    MOZ_COUNT_DTOR(RPCChannel);
+    // FIXME/cjones: impl
+}
+
 bool
 RPCChannel::Call(Message* msg, Message* reply)
 {
     AssertWorkerThread();
     RPC_ASSERT(!ProcessingSyncMessage(),
                "violation of sync handler invariant");
     RPC_ASSERT(msg->is_rpc(), "can only Call() RPC messages here");
 
diff --git a/ipc/glue/RPCChannel.h b/ipc/glue/RPCChannel.h
--- a/ipc/glue/RPCChannel.h
+++ b/ipc/glue/RPCChannel.h
@@ -66,30 +66,19 @@ public:
 
     // What happens if RPC calls race?
     enum RacyRPCPolicy {
         RRPError,
         RRPChildWins,
         RRPParentWins
     };
 
-    RPCChannel(RPCListener* aListener, RacyRPCPolicy aPolicy=RRPChildWins) :
-        SyncChannel(aListener),
-        mPending(),
-        mStack(),
-        mDeferred(),
-        mRemoteStackDepthGuess(0),
-        mRacePolicy(aPolicy)
-    {
-    }
+    RPCChannel(RPCListener* aListener, RacyRPCPolicy aPolicy=RRPChildWins);
 
-    virtual ~RPCChannel()
-    {
-        // FIXME/cjones: impl
-    }
+    virtual ~RPCChannel();
 
     // Make an RPC to the other side of the channel
     bool Call(Message* msg, Message* reply);
 
     // Override the SyncChannel handler so we can dispatch RPC
     // messages.  Called on the IO thread only.
     NS_OVERRIDE virtual void OnMessageReceived(const Message& msg);
     NS_OVERRIDE virtual void OnChannelError();
diff --git a/ipc/glue/SyncChannel.cpp b/ipc/glue/SyncChannel.cpp
--- a/ipc/glue/SyncChannel.cpp
+++ b/ipc/glue/SyncChannel.cpp
@@ -55,16 +55,34 @@ struct RunnableMethodTraits<mozilla::ipc
 {
     static void RetainCallee(mozilla::ipc::SyncChannel* obj) { }
     static void ReleaseCallee(mozilla::ipc::SyncChannel* obj) { }
 };
 
 namespace mozilla {
 namespace ipc {
 
+SyncChannel::SyncChannel(SyncListener* aListener)
+  : AsyncChannel(aListener),
+    mPendingReply(0),
+    mProcessingSyncMessage(false)
+#ifdef OS_WIN
+  , mUIThreadId(0)
+  , mEventLoopDepth(0)
+#endif
+{
+  MOZ_COUNT_CTOR(SyncChannel);
+}
+
+SyncChannel::~SyncChannel()
+{
+    MOZ_COUNT_DTOR(SyncChannel);
+    // FIXME/cjones: impl
+}
+
 bool
 SyncChannel::Send(Message* msg, Message* reply)
 {
     AssertWorkerThread();
     NS_ABORT_IF_FALSE(!ProcessingSyncMessage(),
                       "violation of sync handler invariant");
     NS_ABORT_IF_FALSE(msg->is_sync(), "can only Send() sync messages here");
 
diff --git a/ipc/glue/SyncChannel.h b/ipc/glue/SyncChannel.h
--- a/ipc/glue/SyncChannel.h
+++ b/ipc/glue/SyncChannel.h
@@ -57,31 +57,18 @@ public:
     {
     public:
         virtual ~SyncListener() { }
         virtual Result OnMessageReceived(const Message& aMessage) = 0;
         virtual Result OnMessageReceived(const Message& aMessage,
                                          Message*& aReply) = 0;
     };
 
-    SyncChannel(SyncListener* aListener) :
-        AsyncChannel(aListener),
-        mPendingReply(0),
-        mProcessingSyncMessage(false)
-#ifdef OS_WIN
-      , mUIThreadId(0)
-      , mEventLoopDepth(0)
-#endif
-    {
-    }
-
-    virtual ~SyncChannel()
-    {
-        // FIXME/cjones: impl
-    }
+    SyncChannel(SyncListener* aListener);
+    virtual ~SyncChannel();
 
     bool Send(Message* msg) {
         return AsyncChannel::Send(msg);
     }
 
     // Synchronously send |msg| (i.e., wait for |reply|)
     bool Send(Message* msg, Message* reply);
 
diff --git a/modules/plugin/base/src/nsJSNPRuntime.cpp b/modules/plugin/base/src/nsJSNPRuntime.cpp
--- a/modules/plugin/base/src/nsJSNPRuntime.cpp
+++ b/modules/plugin/base/src/nsJSNPRuntime.cpp
@@ -483,21 +483,24 @@ ReportExceptionIfPending(JSContext *cx)
 
   return JS_FALSE;
 }
 
 
 nsJSObjWrapper::nsJSObjWrapper(NPP npp)
   : nsJSObjWrapperKey(nsnull, npp)
 {
+  MOZ_COUNT_CTOR(nsJSObjWrapper);
   OnWrapperCreated();
 }
 
 nsJSObjWrapper::~nsJSObjWrapper()
 {
+  MOZ_COUNT_DTOR(nsJSObjWrapper);
+
   // Invalidate first, since it relies on sJSRuntime and sJSObjWrappers.
   NP_Invalidate(this);
 
   OnWrapperDestroyed();
 }
 
 // static
 NPObject *
@@ -1851,16 +1854,26 @@ NPObjWrapperPluginDestroyedCallback(PLDH
     table->ops = nsnull;
 
     NPObject *npobj = entry->mNPObj;
 
     if (npobj->_class && npobj->_class->invalidate) {
       npobj->_class->invalidate(npobj);
     }
 
+#ifdef NS_BUILD_REFCNT_LOGGING
+    {
+      int32_t refCnt = npobj->referenceCount;
+      while (refCnt) {
+        --refCnt;
+        NS_LOG_RELEASE(npobj, refCnt, "BrowserNPObject");
+      }
+    }
+#endif
+
     // Force deallocation of plugin objects since the plugin they came
     // from is being torn down.
     if (npobj->_class && npobj->_class->deallocate) {
       npobj->_class->deallocate(npobj);
     } else {
       PR_Free(npobj);
     }
 
diff --git a/modules/plugin/base/src/nsNPAPIPlugin.cpp b/modules/plugin/base/src/nsNPAPIPlugin.cpp
--- a/modules/plugin/base/src/nsNPAPIPlugin.cpp
+++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp
@@ -1394,47 +1394,50 @@ _createobject(NPP npp, NPClass* aClass)
     npobj = aClass->allocate(npp, aClass);
   } else {
     npobj = (NPObject *)PR_Malloc(sizeof(NPObject));
   }
 
   if (npobj) {
     npobj->_class = aClass;
     npobj->referenceCount = 1;
+    NS_LOG_ADDREF(npobj, 1, "BrowserNPObject", sizeof(NPObject));
   }
 
   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
                  ("Created NPObject %p, NPClass %p\n", npobj, aClass));
 
   return npobj;
 }
 
 NPObject* NP_CALLBACK
 _retainobject(NPObject* npobj)
 {
   if (!NS_IsMainThread()) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_retainobject called from the wrong thread\n"));
   }
   if (npobj) {
-    PR_AtomicIncrement((PRInt32*)&npobj->referenceCount);
+    int32_t refCnt = PR_AtomicIncrement((PRInt32*)&npobj->referenceCount);
+    NS_LOG_ADDREF(npobj, refCnt, "BrowserNPObject", sizeof(NPObject));
   }
 
   return npobj;
 }
 
 void NP_CALLBACK
 _releaseobject(NPObject* npobj)
 {
   if (!NS_IsMainThread()) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_releaseobject called from the wrong thread\n"));
   }
   if (!npobj)
     return;
 
   int32_t refCnt = PR_AtomicDecrement((PRInt32*)&npobj->referenceCount);
+  NS_LOG_RELEASE(npobj, refCnt, "BrowserNPObject");
 
   if (refCnt == 0) {
     nsNPObjWrapper::OnDestroy(npobj);
 
     NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
                    ("Deleting NPObject %p, refcount hit 0\n", npobj));
 
     if (npobj->_class && npobj->_class->deallocate) {
