Add threadsafety assertions to plugin code
authorBen Turner <bent.mozilla@gmail.com>
Thu, 08 Oct 2009 12:11:13 -0700
changeset 35971 91ae1b1cf67e209c00af05669ae5b296ea195177
parent 35970 1f27a6cf5117e7eb4ecb765ebcbd45d573857fdd
child 35972 9c07ee9a5fbe40d651b6d044092c74e0286d86fd
push id10694
push userbsmedberg@mozilla.com
push dateMon, 14 Dec 2009 15:23:10 +0000
treeherdermozilla-central@683dfdc4adf0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.3a1pre
Add threadsafety assertions to plugin code
dom/plugins/BrowserStreamChild.cpp
dom/plugins/PluginInstanceChild.cpp
dom/plugins/PluginMessageUtils.h
dom/plugins/PluginModuleChild.cpp
dom/plugins/PluginScriptableObjectChild.cpp
dom/plugins/PluginScriptableObjectParent.cpp
dom/plugins/PluginStreamChild.cpp
ipc/glue/AsyncChannel.cpp
ipc/glue/AsyncChannel.h
ipc/glue/RPCChannel.cpp
ipc/glue/SyncChannel.cpp
--- a/dom/plugins/BrowserStreamChild.cpp
+++ b/dom/plugins/BrowserStreamChild.cpp
@@ -52,16 +52,18 @@ BrowserStreamChild::BrowserStreamChild(P
                                        const bool& seekable,
                                        NPError* rv,
                                        uint16_t* stype)
   : mInstance(instance)
   , mClosed(false)
   , mURL(url)
   , mHeaders(headers)
 {
+  AssertPluginThread();
+
   memset(&mStream, 0, sizeof(mStream));
   mStream.ndata = static_cast<AStream*>(this);
   if (!mURL.IsEmpty())
     mStream.url = mURL.get();
   mStream.end = length;
   mStream.lastmodified = lastmodified;
   if (notifyData)
     mStream.notifyData =
@@ -75,75 +77,85 @@ BrowserStreamChild::BrowserStreamChild(P
   if (*rv != NPERR_NO_ERROR)
     mClosed = true;
 }
 
 bool
 BrowserStreamChild::AnswerNPP_WriteReady(const int32_t& newlength,
                                          int32_t *size)
 {
+  AssertPluginThread();
+
   if (mClosed) {
     *size = 0;
     return true;
   }
 
   mStream.end = newlength;
 
   *size = mInstance->mPluginIface->writeready(&mInstance->mData, &mStream);
   return true;
 }
 
 bool
 BrowserStreamChild::AnswerNPP_Write(const int32_t& offset,
                                     const Buffer& data,
                                     int32_t* consumed)
 {
+  _MOZ_LOG(__FUNCTION__);
+  AssertPluginThread();
+
   if (mClosed) {
     *consumed = -1;
     return true;
   }
 
   *consumed = mInstance->mPluginIface->write(&mInstance->mData, &mStream,
                                              offset, data.Length(),
                                              const_cast<char*>(data.get()));
   return true;
 }
 
 bool
 BrowserStreamChild::AnswerNPP_StreamAsFile(const nsCString& fname)
 {
   _MOZ_LOG(__FUNCTION__);
+  AssertPluginThread();
   printf("mClosed: %i\n", mClosed);
 
   if (mClosed)
     return true;
 
   mInstance->mPluginIface->asfile(&mInstance->mData, &mStream,
                                   fname.get());
   return true;
 }
 
 NPError
 BrowserStreamChild::NPN_RequestRead(NPByteRange* aRangeList)
 {
+  AssertPluginThread();
+
   IPCByteRanges ranges;
   for (; aRangeList; aRangeList = aRangeList->next) {
     IPCByteRange br = {aRangeList->offset, aRangeList->length};
     ranges.push_back(br);
   }
 
   NPError result;
   CallNPN_RequestRead(ranges, &result);
   // TODO: does failure in NPN_RequestRead affect stream state at all?
   return result;
 }
 
 void
 BrowserStreamChild::NPP_DestroyStream(NPError reason)
 {
+  AssertPluginThread();
+
   if (mClosed)
     return;
 
   mInstance->mPluginIface->destroystream(&mInstance->mData, &mStream, reason);
   mClosed = true;
 }
 
 } /* namespace plugins */
--- a/dom/plugins/PluginInstanceChild.cpp
+++ b/dom/plugins/PluginInstanceChild.cpp
@@ -65,16 +65,17 @@ PluginInstanceChild::~PluginInstanceChil
 }
 
 NPError
 PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
                                   void* aValue)
 {
     printf ("[PluginInstanceChild] NPN_GetValue(%s)\n",
             NPNVariableToString(aVar));
+    AssertPluginThread();
 
     switch(aVar) {
 
     case NPNVSupportsWindowless:
 #if defined(OS_LINUX)
         *((NPBool*)aValue) = true;
 #else
         *((NPBool*)aValue) = false;
@@ -174,16 +175,17 @@ PluginInstanceChild::NPN_GetValue(NPNVar
 }
 
 
 NPError
 PluginInstanceChild::NPN_SetValue(NPPVariable aVar, void* aValue)
 {
     printf ("[PluginInstanceChild] NPN_SetValue(%s, %ld)\n",
             NPPVariableToString(aVar), reinterpret_cast<intptr_t>(aValue));
+    AssertPluginThread();
 
     switch (aVar) {
     case NPPVpluginWindowBool: {
         NPError rv;
         bool windowed = (NPBool) (intptr_t) aValue;
 
         if (!CallNPN_SetValue_NPPVpluginWindow(windowed, &rv))
             return NPERR_GENERIC_ERROR;
@@ -207,38 +209,44 @@ PluginInstanceChild::NPN_SetValue(NPPVar
     }
 }
 
 
 bool
 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginWindow(
     bool* windowed, NPError* rv)
 {
+    AssertPluginThread();
+
     NPBool isWindowed;
     *rv = mPluginIface->getvalue(GetNPP(), NPPVpluginWindowBool,
                                  reinterpret_cast<void*>(&isWindowed));
     *windowed = isWindowed;
     return true;
 }
 
 bool
 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginTransparent(
     bool* transparent, NPError* rv)
 {
+    AssertPluginThread();
+
     NPBool isTransparent;
     *rv = mPluginIface->getvalue(GetNPP(), NPPVpluginTransparentBool,
                                  reinterpret_cast<void*>(&isTransparent));
     *transparent = isTransparent;
     return true;
 }
 
 bool
 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(
     bool* needs, NPError* rv)
 {
+    AssertPluginThread();
+
 #ifdef OS_LINUX
 
     NPBool needsXEmbed;
     *rv = mPluginIface->getvalue(GetNPP(), NPPVpluginNeedsXEmbed,
                                  reinterpret_cast<void*>(&needsXEmbed));
     *needs = needsXEmbed;
     return true;
 
@@ -250,16 +258,17 @@ PluginInstanceChild::AnswerNPP_GetValue_
 #endif
 }
 
 bool
 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginScriptableNPObject(
                                            PPluginScriptableObjectChild** value,
                                            NPError* result)
 {
+    AssertPluginThread();
 
     NPObject* object;
     *result = mPluginIface->getvalue(GetNPP(), NPPVpluginScriptableNPObject,
                                      &object);
     if (*result != NPERR_NO_ERROR) {
         return true;
     }
 
@@ -278,16 +287,17 @@ PluginInstanceChild::AnswerNPP_GetValue_
     return true;
 }
 
 bool
 PluginInstanceChild::AnswerNPP_HandleEvent(const NPEvent& event,
                                            int16_t* handled)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
 #if defined(OS_LINUX) && defined(DEBUG_cjones)
     if (GraphicsExpose == event.type)
         printf("  received drawable 0x%lx\n",
                event.xgraphicsexpose.drawable);
 #endif
 
     // plugins might be fooling with these, make a copy
@@ -329,16 +339,17 @@ XVisualIDToInfo(Display* aDisplay, Visua
 bool
 PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow,
                                          NPError* rv)
 {
     printf("[PluginInstanceChild] NPP_SetWindow(0x%lx, %d, %d, %d x %d)\n",
            aWindow.window,
            aWindow.x, aWindow.y,
            aWindow.width, aWindow.height);
+    AssertPluginThread();
 
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
     // The minimum info is sent over IPC to allow this
     // code to determine the rest.
 
     mWindow.window = reinterpret_cast<void*>(aWindow.window);
     mWindow.x = aWindow.x;
     mWindow.y = aWindow.y;
@@ -558,30 +569,34 @@ PluginInstanceChild::PluginWindowProc(HW
     return res;
 }
 
 #endif // OS_WIN
 
 PPluginScriptableObjectChild*
 PluginInstanceChild::AllocPPluginScriptableObject()
 {
+    AssertPluginThread();
+
     nsAutoPtr<PluginScriptableObjectChild>* object =
         mScriptableObjects.AppendElement();
     NS_ENSURE_TRUE(object, nsnull);
 
     *object = new PluginScriptableObjectChild();
     NS_ENSURE_TRUE(*object, nsnull);
 
     return object->get();
 }
 
 bool
 PluginInstanceChild::DeallocPPluginScriptableObject(
                                           PPluginScriptableObjectChild* aObject)
 {
+    AssertPluginThread();
+
     PluginScriptableObjectChild* object =
         reinterpret_cast<PluginScriptableObjectChild*>(aObject);
 
     NPObject* npobject = object->GetObject();
     if (npobject &&
         npobject->_class != PluginScriptableObjectChild::GetClass()) {
         PluginModuleChild::current()->UnregisterNPObject(npobject);
     }
@@ -596,16 +611,18 @@ PluginInstanceChild::DeallocPPluginScrip
     NS_NOTREACHED("An actor we don't know about?!");
     return false;
 }
 
 bool
 PluginInstanceChild::AnswerPPluginScriptableObjectConstructor(
                                            PPluginScriptableObjectChild* aActor)
 {
+    AssertPluginThread();
+
     // This is only called in response to the parent process requesting the
     // creation of an actor. This actor will represent an NPObject that is
     // created by the browser and returned to the plugin.
     NPClass* npclass =
         const_cast<NPClass*>(PluginScriptableObjectChild::GetClass());
 
     ChildNPObject* object = reinterpret_cast<ChildNPObject*>(
         PluginModuleChild::sBrowserFuncs.createobject(GetNPP(), npclass));
@@ -627,35 +644,38 @@ PluginInstanceChild::AllocPBrowserStream
                                          const uint32_t& lastmodified,
                                          const PStreamNotifyChild* notifyData,
                                          const nsCString& headers,
                                          const nsCString& mimeType,
                                          const bool& seekable,
                                          NPError* rv,
                                          uint16_t *stype)
 {
+    AssertPluginThread();
     return new BrowserStreamChild(this, url, length, lastmodified, notifyData,
                                   headers, mimeType, seekable, rv, stype);
 }
 
 bool
 PluginInstanceChild::AnswerPBrowserStreamDestructor(PBrowserStreamChild* stream,
                                                     const NPError& reason,
                                                     const bool& artificial)
 {
+    AssertPluginThread();
     if (!artificial)
         static_cast<BrowserStreamChild*>(stream)->NPP_DestroyStream(reason);
     return true;
 }
 
 bool
 PluginInstanceChild::DeallocPBrowserStream(PBrowserStreamChild* stream,
                                            const NPError& reason,
                                            const bool& artificial)
 {
+    AssertPluginThread();
     delete stream;
     return true;
 }
 
 PPluginStreamChild*
 PluginInstanceChild::AllocPPluginStream(const nsCString& mimeType,
                                         const nsCString& target,
                                         NPError* result)
@@ -664,57 +684,63 @@ PluginInstanceChild::AllocPPluginStream(
     return NULL;
 }
 
 bool
 PluginInstanceChild::AnswerPPluginStreamDestructor(PPluginStreamChild* stream,
                                                    const NPReason& reason,
                                                    const bool& artificial)
 {
+    AssertPluginThread();
     if (!artificial) {
         static_cast<PluginStreamChild*>(stream)->NPP_DestroyStream(reason);
     }
     return true;
 }
 
 bool
 PluginInstanceChild::DeallocPPluginStream(PPluginStreamChild* stream,
                                           const NPError& reason,
                                           const bool& artificial)
 {
+    AssertPluginThread();
     delete stream;
     return true;
 }
 
 PStreamNotifyChild*
 PluginInstanceChild::AllocPStreamNotify(const nsCString& url,
                                         const nsCString& target,
                                         const bool& post,
                                         const nsCString& buffer,
                                         const bool& file,
                                         NPError* result)
 {
+    AssertPluginThread();
     NS_RUNTIMEABORT("not reached");
     return NULL;
 }
 
 bool
 PluginInstanceChild::DeallocPStreamNotify(PStreamNotifyChild* notifyData,
                                           const NPReason& reason)
 {
+    AssertPluginThread();
+
     StreamNotifyChild* sn = static_cast<StreamNotifyChild*>(notifyData);
     mPluginIface->urlnotify(&mData, sn->mURL.get(), reason, sn->mClosure);
     delete sn;
 
     return true;
 }
 
 PluginScriptableObjectChild*
 PluginInstanceChild::GetActorForNPObject(NPObject* aObject)
 {
+    AssertPluginThread();
   NS_ASSERTION(aObject, "Null pointer!");
 
   if (aObject->_class == PluginScriptableObjectChild::GetClass()) {
       // One of ours! It's a browser-provided object.
       ChildNPObject* object = static_cast<ChildNPObject*>(aObject);
       NS_ASSERTION(object->parent, "Null actor!");
       return object->parent;
   }
@@ -740,16 +766,18 @@ PluginInstanceChild::GetActorForNPObject
 
   return actor;
 }
 
 NPError
 PluginInstanceChild::NPN_NewStream(NPMIMEType aMIMEType, const char* aWindow,
                                    NPStream** aStream)
 {
+    AssertPluginThread();
+
     PluginStreamChild* ps = new PluginStreamChild(this);
 
     NPError result;
     CallPPluginStreamConstructor(ps, nsDependentCString(aMIMEType),
                                  NullableString(aWindow), &result);
     if (NPERR_NO_ERROR != result) {
         *aStream = NULL;
         CallPPluginStreamDestructor(ps, NPERR_GENERIC_ERROR, true);
--- a/dom/plugins/PluginMessageUtils.h
+++ b/dom/plugins/PluginMessageUtils.h
@@ -40,16 +40,17 @@
 #define DOM_PLUGINS_PLUGINMESSAGEUTILS_H
 
 #include "IPC/IPCMessageUtils.h"
 
 #include "npapi.h"
 #include "npruntime.h"
 #include "nsAutoPtr.h"
 #include "nsStringGlue.h"
+#include "nsThreadUtils.h"
 
 namespace mozilla {
 
 // XXX might want to move these to nscore.h or something, they can be
 // generally useful
 struct void_t { };
 struct null_t { };
 
@@ -156,16 +157,22 @@ NPNVariableToString(NPNVariable aVar)
         VARSTR(NPNVprivateModeBool);
 
     default: return "???";
     }
 }
 #undef VARSTR
 
 
+inline void AssertPluginThread()
+{
+  NS_ASSERTION(NS_IsMainThread(), "should be on the plugin's main thread!");
+}
+
+
 } /* namespace plugins */
 
 } /* namespace mozilla */
 
 
 namespace {
 
 // in NPAPI, char* == NULL is sometimes meaningful.  the following is
--- a/dom/plugins/PluginModuleChild.cpp
+++ b/dom/plugins/PluginModuleChild.cpp
@@ -190,36 +190,39 @@ PluginModuleChild::CleanUp()
 {
     // FIXME/cjones: destroy all instances
 }
 
 bool
 PluginModuleChild::RegisterNPObject(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);
 }
 
 void
 PluginModuleChild::UnregisterNPObject(NPObject* aObject)
 {
+    AssertPluginThread();
     NS_ASSERTION(mObjectMap.IsInitialized(), "Not initialized!");
     NS_ASSERTION(aObject, "Null pointer!");
     NS_ASSERTION(mObjectMap.Get(aObject, nsnull),
                  "Unregistering an object that was never added!");
     mObjectMap.Remove(aObject);
 }
 
 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;
 }
 
 //-----------------------------------------------------------------------------
 // FIXME/cjones: just getting this out of the way for the moment ...
@@ -473,80 +476,88 @@ InstCast(NPP aNPP)
     return static_cast<PluginInstanceChild*>(aNPP->ndata);
 }
 
 NPError NP_CALLBACK
 _requestread(NPStream* aStream,
              NPByteRange* aRangeList)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
+
     BrowserStreamChild* bs =
         static_cast<BrowserStreamChild*>(static_cast<AStream*>(aStream->ndata));
     bs->EnsureCorrectStream(aStream);
     return bs->NPN_RequestRead(aRangeList);
 }
 
 NPError NP_CALLBACK
 _geturlnotify(NPP aNPP,
               const char* aRelativeURL,
               const char* aTarget,
               void* aNotifyData)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     nsCString url = NullableString(aRelativeURL);
     NPError err;
     InstCast(aNPP)->CallPStreamNotifyConstructor(
         new StreamNotifyChild(url, aNotifyData),
         url, NullableString(aTarget), false, nsCString(), false, &err);
     // TODO: what if this fails?
     return err;
 }
 
 NPError NP_CALLBACK
 _getvalue(NPP aNPP,
           NPNVariable aVariable,
           void* aValue)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     return InstCast(aNPP)->NPN_GetValue(aVariable, aValue);
 }
 
 
 NPError NP_CALLBACK
 _setvalue(NPP aNPP,
           NPPVariable aVariable,
           void* aValue)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     return InstCast(aNPP)->NPN_SetValue(aVariable, aValue);
 }
 
 NPError NP_CALLBACK
 _geturl(NPP aNPP,
         const char* aRelativeURL,
         const char* aTarget)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
+
     NPError err;
     InstCast(aNPP)->CallNPN_GetURL(NullableString(aRelativeURL),
                                    NullableString(aTarget), &err);
     return err;
 }
 
 NPError NP_CALLBACK
 _posturlnotify(NPP aNPP,
                const char* aRelativeURL,
                const char* aTarget,
                uint32_t aLength,
                const char* aBuffer,
                NPBool aIsFile,
                void* aNotifyData)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     nsCString url = NullableString(aRelativeURL);
     NPError err;
     // FIXME what should happen when |aBuffer| is null?
     InstCast(aNPP)->CallPStreamNotifyConstructor(
         new StreamNotifyChild(url, aNotifyData),
         url, NullableString(aTarget), true,
         nsDependentCString(aBuffer, aLength), aIsFile, &err);
@@ -558,55 +569,62 @@ NPError NP_CALLBACK
 _posturl(NPP aNPP,
          const char* aRelativeURL,
          const char* aTarget,
          uint32_t aLength,
          const char* aBuffer,
          NPBool aIsFile)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
+
     NPError err;
     // FIXME what should happen when |aBuffer| is null?
     InstCast(aNPP)->CallNPN_PostURL(NullableString(aRelativeURL),
                                     NullableString(aTarget),
                                     nsDependentCString(aBuffer, aLength),
                                     aIsFile, &err);
     return err;
 }
 
 NPError NP_CALLBACK
 _newstream(NPP aNPP,
            NPMIMEType aMIMEType,
            const char* aWindow,
            NPStream** aStream)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     return InstCast(aNPP)->NPN_NewStream(aMIMEType, aWindow, aStream);
 }
 
 int32_t NP_CALLBACK
 _write(NPP aNPP,
        NPStream* aStream,
        int32_t aLength,
        void* aBuffer)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
+
     PluginStreamChild* ps =
         static_cast<PluginStreamChild*>(static_cast<AStream*>(aStream->ndata));
     ps->EnsureCorrectInstance(InstCast(aNPP));
     ps->EnsureCorrectStream(aStream);
     return ps->NPN_Write(aLength, aBuffer);
 }
 
 NPError NP_CALLBACK
 _destroystream(NPP aNPP,
                NPStream* aStream,
                NPError aReason)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
+
     PluginInstanceChild* p = InstCast(aNPP);
     AStream* s = static_cast<AStream*>(aStream->ndata);
     if (s->IsBrowserStream()) {
         BrowserStreamChild* bs = static_cast<BrowserStreamChild*>(s);
         bs->EnsureCorrectInstance(p);
         p->CallPBrowserStreamDestructor(bs, aReason, false);
     }
     else {
@@ -617,95 +635,107 @@ NPError NP_CALLBACK
     return NPERR_NO_ERROR;
 }
 
 void NP_CALLBACK
 _status(NPP aNPP,
         const char* aMessage)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 }
 
 void NP_CALLBACK
 _memfree(void* aPtr)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     NS_Free(aPtr);
 }
 
 uint32_t NP_CALLBACK
 _memflush(uint32_t aSize)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     return 0;
 }
 
 void NP_CALLBACK
 _reloadplugins(NPBool aReloadPages)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 }
 
 void NP_CALLBACK
 _invalidaterect(NPP aNPP,
                 NPRect* aInvalidRect)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     InstCast(aNPP)->SendNPN_InvalidateRect(*aInvalidRect);
 }
 
 void NP_CALLBACK
 _invalidateregion(NPP aNPP,
                   NPRegion aInvalidRegion)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     // Not implemented in Mozilla.
 }
 
 void NP_CALLBACK
 _forceredraw(NPP aNPP)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 }
 
 const char* NP_CALLBACK
 _useragent(NPP aNPP)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     PluginModuleChild::current()->CallNPN_UserAgent(&gUserAgent);
     return NullableStringGet(gUserAgent);
 }
 
 void* NP_CALLBACK
 _memalloc(uint32_t aSize)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     return NS_Alloc(aSize);
 }
 
 // Deprecated entry points for the old Java plugin.
 void* NP_CALLBACK /* OJI type: JRIEnv* */
 _getjavaenv(void)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     return 0;
 }
 
 void* NP_CALLBACK /* OJI type: jref */
 _getjavapeer(NPP aNPP)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     return 0;
 }
 
 NPIdentifier NP_CALLBACK
 _getstringidentifier(const NPUTF8* aName)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     NPRemoteIdentifier ident;
     if (!PluginModuleChild::current()->
              SendNPN_GetStringIdentifier(nsDependentCString(aName), &ident)) {
         NS_WARNING("Failed to send message!");
         ident = 0;
     }
 
@@ -713,16 +743,17 @@ NPIdentifier NP_CALLBACK
 }
 
 void NP_CALLBACK
 _getstringidentifiers(const NPUTF8** aNames,
                       int32_t aNameCount,
                       NPIdentifier* aIdentifiers)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     if (!(aNames && aNameCount > 0 && aIdentifiers)) {
         NS_RUNTIMEABORT("Bad input! Headed for a crash!");
     }
 
     nsAutoTArray<nsCString, 10> names;
     nsAutoTArray<NPRemoteIdentifier, 10> ids;
 
@@ -750,47 +781,50 @@ void NP_CALLBACK
         aIdentifiers[index] = 0;
     }
 }
 
 bool NP_CALLBACK
 _identifierisstring(NPIdentifier aIdentifier)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     bool isString;
     if (!PluginModuleChild::current()->
              SendNPN_IdentifierIsString((NPRemoteIdentifier)aIdentifier,
                                         &isString)) {
         NS_WARNING("Failed to send message!");
         isString = false;
     }
 
     return isString;
 }
 
 NPIdentifier NP_CALLBACK
 _getintidentifier(int32_t aIntId)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     NPRemoteIdentifier ident;
     if (!PluginModuleChild::current()->
              SendNPN_GetIntIdentifier(aIntId, &ident)) {
         NS_WARNING("Failed to send message!");
         ident = 0;
     }
 
     return (NPIdentifier)ident;
 }
 
 NPUTF8* NP_CALLBACK
 _utf8fromidentifier(NPIdentifier aIdentifier)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     NPError err;
     nsCAutoString val;
     if (!PluginModuleChild::current()->
              SendNPN_UTF8FromIdentifier((NPRemoteIdentifier)aIdentifier,
                                          &err, &val)) {
         NS_WARNING("Failed to send message!");
         return 0;
@@ -798,16 +832,17 @@ NPUTF8* NP_CALLBACK
 
     return (NPERR_NO_ERROR == err) ? strdup(val.get()) : 0;
 }
 
 int32_t NP_CALLBACK
 _intfromidentifier(NPIdentifier aIdentifier)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     NPError err;
     int32_t val;
     if (!PluginModuleChild::current()->
              SendNPN_IntFromIdentifier((NPRemoteIdentifier)aIdentifier,
                                        &err, &val)) {
         NS_WARNING("Failed to send message!");
         return -1;
@@ -817,16 +852,17 @@ int32_t NP_CALLBACK
     return (NPERR_NO_ERROR == err) ? val : -1;
 }
 
 NPObject* NP_CALLBACK
 _createobject(NPP aNPP,
               NPClass* aClass)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     NPObject* newObject;
     if (aClass && aClass->allocate) {
         newObject = aClass->allocate(aNPP, aClass);
     }
     else {
         newObject = reinterpret_cast<NPObject*>(_memalloc(sizeof(NPObject)));
     }
@@ -836,27 +872,31 @@ NPObject* NP_CALLBACK
         newObject->referenceCount = 1;
     }
     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;
     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) {
         if (aNPObj->_class && aNPObj->_class->deallocate) {
             aNPObj->_class->deallocate(aNPObj);
         } else {
@@ -870,123 +910,133 @@ bool NP_CALLBACK
 _invoke(NPP aNPP,
         NPObject* aNPObj,
         NPIdentifier aMethod,
         const NPVariant* aArgs,
         uint32_t aArgCount,
         NPVariant* aResult)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->invoke)
         return false;
 
     return aNPObj->_class->invoke(aNPObj, aMethod, aArgs, aArgCount, aResult);
 }
 
 bool NP_CALLBACK
 _invokedefault(NPP aNPP,
                NPObject* aNPObj,
                const NPVariant* aArgs,
                uint32_t aArgCount,
                NPVariant* aResult)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->invokeDefault)
         return false;
 
     return aNPObj->_class->invokeDefault(aNPObj, aArgs, aArgCount, aResult);
 }
 
 bool NP_CALLBACK
 _evaluate(NPP aNPP,
           NPObject* aNPObj,
           NPString* aScript,
           NPVariant* aResult)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
+
     NS_NOTYETIMPLEMENTED("Implement me!");
     return false;
 }
 
 bool NP_CALLBACK
 _getproperty(NPP aNPP,
              NPObject* aNPObj,
              NPIdentifier aPropertyName,
              NPVariant* aResult)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->getProperty)
         return false;
 
     return aNPObj->_class->getProperty(aNPObj, aPropertyName, aResult);
 }
 
 bool NP_CALLBACK
 _setproperty(NPP aNPP,
              NPObject* aNPObj,
              NPIdentifier aPropertyName,
              const NPVariant* aValue)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->setProperty)
         return false;
 
     return aNPObj->_class->setProperty(aNPObj, aPropertyName, aValue);
 }
 
 bool NP_CALLBACK
 _removeproperty(NPP aNPP,
                 NPObject* aNPObj,
                 NPIdentifier aPropertyName)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->removeProperty)
         return false;
 
     return aNPObj->_class->removeProperty(aNPObj, aPropertyName);
 }
 
 bool NP_CALLBACK
 _hasproperty(NPP aNPP,
              NPObject* aNPObj,
              NPIdentifier aPropertyName)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->hasProperty)
         return false;
 
     return aNPObj->_class->hasProperty(aNPObj, aPropertyName);
 }
 
 bool NP_CALLBACK
 _hasmethod(NPP aNPP,
            NPObject* aNPObj,
            NPIdentifier aMethodName)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->hasMethod)
         return false;
 
     return aNPObj->_class->hasMethod(aNPObj, aMethodName);
 }
 
 bool NP_CALLBACK
 _enumerate(NPP aNPP,
            NPObject* aNPObj,
            NPIdentifier** aIdentifiers,
            uint32_t* aCount)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     if (!aNPP || !aNPObj || !aNPObj->_class)
         return false;
 
     if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(aNPObj->_class) ||
         !aNPObj->_class->enumerate) {
         *aIdentifiers = 0;
         *aCount = 0;
@@ -999,30 +1049,33 @@ bool NP_CALLBACK
 bool NP_CALLBACK
 _construct(NPP aNPP,
            NPObject* aNPObj,
            const NPVariant* aArgs,
            uint32_t aArgCount,
            NPVariant* aResult)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     if (!aNPP || !aNPObj || !aNPObj->_class ||
         !NP_CLASS_STRUCT_VERSION_HAS_CTOR(aNPObj->_class) ||
         !aNPObj->_class->construct) {
         return false;
     }
 
     return aNPObj->_class->construct(aNPObj, aArgs, aArgCount, aResult);
 }
 
 void NP_CALLBACK
 _releasevariantvalue(NPVariant* aVariant)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
+
     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);
@@ -1031,115 +1084,127 @@ void NP_CALLBACK
     VOID_TO_NPVARIANT(*aVariant);
 }
 
 void NP_CALLBACK
 _setexception(NPObject* aNPObj,
               const NPUTF8* aMessage)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     NS_NOTYETIMPLEMENTED("Implement me!");
 }
 
 bool NP_CALLBACK
 _pushpopupsenabledstate(NPP aNPP,
                         NPBool aEnabled)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     NS_NOTYETIMPLEMENTED("Implement me!");
     return false;
 }
 
 bool NP_CALLBACK
 _poppopupsenabledstate(NPP aNPP)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     NS_NOTYETIMPLEMENTED("Implement me!");
     return false;
 }
 
 void NP_CALLBACK
 _pluginthreadasynccall(NPP aNPP,
                        PluginThreadCallback aFunc,
                        void* aUserData)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     NS_NOTYETIMPLEMENTED("Implement me!");
 }
 
 NPError NP_CALLBACK
 _getvalueforurl(NPP npp, NPNURLVariable variable, const char *url,
                 char **value, uint32_t *len)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     NS_NOTYETIMPLEMENTED("Implement me!");
     return NPERR_GENERIC_ERROR;
 }
 
 NPError NP_CALLBACK
 _setvalueforurl(NPP npp, NPNURLVariable variable, const char *url,
                 const char *value, uint32_t len)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     NS_NOTYETIMPLEMENTED("Implement me!");
     return NPERR_GENERIC_ERROR;
 }
 
 NPError NP_CALLBACK
 _getauthenticationinfo(NPP npp, const char *protocol,
                        const char *host, int32_t port,
                        const char *scheme, const char *realm,
                        char **username, uint32_t *ulen,
                        char **password, uint32_t *plen)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     NS_NOTYETIMPLEMENTED("Implement me!");
     return NPERR_GENERIC_ERROR;
 }
 
 uint32_t NP_CALLBACK
 _scheduletimer(NPP instance, uint32_t interval, NPBool repeat,
                void (*timerFunc)(NPP npp, uint32_t timerID))
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     NS_NOTYETIMPLEMENTED("Implement me!");
     return 0;
 }
 
 void NP_CALLBACK
 _unscheduletimer(NPP instance, uint32_t timerID)
 {
+    _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     NS_NOTYETIMPLEMENTED("Implement me!");
-    _MOZ_LOG(__FUNCTION__);
 }
 
 NPError NP_CALLBACK
 _popupcontextmenu(NPP instance, NPMenu* menu)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     NS_NOTYETIMPLEMENTED("Implement me!");
     return NPERR_GENERIC_ERROR;
 }
 
 NPBool NP_CALLBACK
 _convertpoint(NPP instance, 
               double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
               double *destX, double *destY, NPCoordinateSpace destSpace)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
     NS_NOTYETIMPLEMENTED("Implement me!");
     return 0;
 }
 
 //-----------------------------------------------------------------------------
 
 bool
 PluginModuleChild::AnswerNP_Initialize(NPError* _retval)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
 #if defined(OS_LINUX)
     *_retval = mInitializeFunc(&sBrowserFuncs, &mFunctions);
     return true;
 
 #elif defined(OS_WIN)
     nsresult rv = mGetEntryPointsFunc(&mFunctions);
     if (NS_FAILED(rv)) {
@@ -1159,16 +1224,17 @@ PluginModuleChild::AnswerNP_Initialize(N
 PPluginInstanceChild*
 PluginModuleChild::AllocPPluginInstance(const nsCString& aMimeType,
                                         const uint16_t& aMode,
                                         const nsTArray<nsCString>& aNames,
                                         const nsTArray<nsCString>& aValues,
                                         NPError* rv)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     nsAutoPtr<PluginInstanceChild> childInstance(
         new PluginInstanceChild(&mFunctions));
     if (!childInstance->Initialize()) {
         *rv = NPERR_GENERIC_ERROR;
         return 0;
     }
     return childInstance.forget();
@@ -1178,16 +1244,17 @@ bool
 PluginModuleChild::AnswerPPluginInstanceConstructor(PPluginInstanceChild* aActor,
                                                     const nsCString& aMimeType,
                                                     const uint16_t& aMode,
                                                     const nsTArray<nsCString>& aNames,
                                                     const nsTArray<nsCString>& aValues,
                                                     NPError* rv)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     PluginInstanceChild* childInstance =
         reinterpret_cast<PluginInstanceChild*>(aActor);
     NS_ASSERTION(childInstance, "Null actor!");
 
     // unpack the arguments into a C format
     int argc = aNames.Length();
     NS_ASSERTION(argc == (int) aValues.Length(),
@@ -1224,27 +1291,29 @@ PluginModuleChild::AnswerPPluginInstance
     return true;
 }
 
 bool
 PluginModuleChild::DeallocPPluginInstance(PPluginInstanceChild* aActor,
                                           NPError* rv)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     delete aActor;
 
     return true;
 }
 
 bool
 PluginModuleChild::AnswerPPluginInstanceDestructor(PPluginInstanceChild* aActor,
                                                    NPError* rv)
 {
     _MOZ_LOG(__FUNCTION__);
+    AssertPluginThread();
 
     PluginInstanceChild* inst = static_cast<PluginInstanceChild*>(aActor);
     *rv = mFunctions.destroy(inst->GetNPP(), 0);
     inst->Destroy();
     inst->GetNPP()->ndata = 0;
 
     return true;
 }
--- a/dom/plugins/PluginScriptableObjectChild.cpp
+++ b/dom/plugins/PluginScriptableObjectChild.cpp
@@ -169,31 +169,35 @@ ConvertToRemoteVariant(const NPVariant& 
 
 } // anonymous namespace
 
 // static
 NPObject*
 PluginScriptableObjectChild::ScriptableAllocate(NPP aInstance,
                                                 NPClass* aClass)
 {
+  AssertPluginThread();
+
   NS_ASSERTION(aClass == PluginScriptableObjectChild::GetClass(),
                "Huh?! Wrong class!");
 
   ChildNPObject* object = reinterpret_cast<ChildNPObject*>(
     PluginModuleChild::sBrowserFuncs.memalloc(sizeof(ChildNPObject)));
   if (object) {
     memset(object, 0, sizeof(ChildNPObject));
   }
   return object;
 }
 
 // static
 void
 PluginScriptableObjectChild::ScriptableInvalidate(NPObject* aObject)
 {
+  AssertPluginThread();
+
   if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
     NS_ERROR("Don't know what kind of object this is!");
     return;
   }
 
   ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
   if (object->invalidated) {
     // This can happen more than once, and is just fine.
@@ -216,16 +220,18 @@ PluginScriptableObjectChild::ScriptableI
     NS_WARNING("Failed to send message!");
   }
 }
 
 // static
 void
 PluginScriptableObjectChild::ScriptableDeallocate(NPObject* aObject)
 {
+  AssertPluginThread();
+
   if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
     NS_ERROR("Don't know what kind of object this is!");
     return;
   }
 
   ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
   if (!object->invalidated) {
     ScriptableInvalidate(aObject);
@@ -236,16 +242,18 @@ PluginScriptableObjectChild::ScriptableD
   NS_Free(aObject);
 }
 
 // static
 bool
 PluginScriptableObjectChild::ScriptableHasMethod(NPObject* aObject,
                                                  NPIdentifier aName)
 {
+  AssertPluginThread();
+
   if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
     NS_ERROR("Don't know what kind of object this is!");
     return false;
   }
 
   ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
   if (object->invalidated) {
     NS_WARNING("Calling method on an invalidated object!");
@@ -267,16 +275,18 @@ PluginScriptableObjectChild::ScriptableH
 // static
 bool
 PluginScriptableObjectChild::ScriptableInvoke(NPObject* aObject,
                                               NPIdentifier aName,
                                               const NPVariant* aArgs,
                                               uint32_t aArgCount,
                                               NPVariant* aResult)
 {
+  AssertPluginThread();
+
   if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
     NS_ERROR("Don't know what kind of object this is!");
     return false;
   }
 
   ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
   if (object->invalidated) {
     NS_WARNING("Calling method on an invalidated object!");
@@ -318,16 +328,18 @@ PluginScriptableObjectChild::ScriptableI
 
 // static
 bool
 PluginScriptableObjectChild::ScriptableInvokeDefault(NPObject* aObject,
                                                      const NPVariant* aArgs,
                                                      uint32_t aArgCount,
                                                      NPVariant* aResult)
 {
+  AssertPluginThread();
+
   if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
     NS_ERROR("Don't know what kind of object this is!");
     return false;
   }
 
   ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
   if (object->invalidated) {
     NS_WARNING("Calling method on an invalidated object!");
@@ -366,16 +378,18 @@ PluginScriptableObjectChild::ScriptableI
   return true;
 }
 
 // static
 bool
 PluginScriptableObjectChild::ScriptableHasProperty(NPObject* aObject,
                                                    NPIdentifier aName)
 {
+  AssertPluginThread();
+
   if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
     NS_ERROR("Don't know what kind of object this is!");
     return false;
   }
 
   ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
   if (object->invalidated) {
     NS_WARNING("Calling method on an invalidated object!");
@@ -395,16 +409,18 @@ PluginScriptableObjectChild::ScriptableH
 }
 
 // static
 bool
 PluginScriptableObjectChild::ScriptableGetProperty(NPObject* aObject,
                                                    NPIdentifier aName,
                                                    NPVariant* aResult)
 {
+  AssertPluginThread();
+
   if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
     NS_ERROR("Don't know what kind of object this is!");
     return false;
   }
 
   ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
   if (object->invalidated) {
     NS_WARNING("Calling method on an invalidated object!");
@@ -430,16 +446,18 @@ PluginScriptableObjectChild::ScriptableG
 }
 
 // static
 bool
 PluginScriptableObjectChild::ScriptableSetProperty(NPObject* aObject,
                                                    NPIdentifier aName,
                                                    const NPVariant* aValue)
 {
+  AssertPluginThread();
+
   if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
     NS_ERROR("Don't know what kind of object this is!");
     return false;
   }
 
   ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
   if (object->invalidated) {
     NS_WARNING("Calling method on an invalidated object!");
@@ -464,16 +482,18 @@ PluginScriptableObjectChild::ScriptableS
   return success;
 }
 
 // static
 bool
 PluginScriptableObjectChild::ScriptableRemoveProperty(NPObject* aObject,
                                                       NPIdentifier aName)
 {
+  AssertPluginThread();
+
   if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
     NS_ERROR("Don't know what kind of object this is!");
     return false;
   }
 
   ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
   if (object->invalidated) {
     NS_WARNING("Calling method on an invalidated object!");
@@ -493,16 +513,18 @@ PluginScriptableObjectChild::ScriptableR
 }
 
 // static
 bool
 PluginScriptableObjectChild::ScriptableEnumerate(NPObject* aObject,
                                                  NPIdentifier** aIdentifiers,
                                                  uint32_t* aCount)
 {
+  AssertPluginThread();
+
   if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
     NS_ERROR("Don't know what kind of object this is!");
     return false;
   }
 
   ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
   if (object->invalidated) {
     NS_WARNING("Calling method on an invalidated object!");
@@ -544,16 +566,18 @@ PluginScriptableObjectChild::ScriptableE
 
 // static
 bool
 PluginScriptableObjectChild::ScriptableConstruct(NPObject* aObject,
                                                  const NPVariant* aArgs,
                                                  uint32_t aArgCount,
                                                  NPVariant* aResult)
 {
+  AssertPluginThread();
+
   if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
     NS_ERROR("Don't know what kind of object this is!");
     return false;
   }
 
   ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
   if (object->invalidated) {
     NS_WARNING("Calling method on an invalidated object!");
@@ -607,20 +631,23 @@ const NPClass PluginScriptableObjectChil
   PluginScriptableObjectChild::ScriptableEnumerate,
   PluginScriptableObjectChild::ScriptableConstruct
 };
 
 PluginScriptableObjectChild::PluginScriptableObjectChild()
 : mInstance(nsnull),
   mObject(nsnull)
 {
+  AssertPluginThread();
 }
 
 PluginScriptableObjectChild::~PluginScriptableObjectChild()
 {
+  AssertPluginThread();
+
   if (mObject) {
     if (mObject->_class == GetClass()) {
       if (!static_cast<ChildNPObject*>(mObject)->invalidated) {
         NS_WARNING("This should have happened already!");
         ScriptableInvalidate(mObject);
       }
     }
     else {
@@ -628,16 +655,18 @@ PluginScriptableObjectChild::~PluginScri
     }
   }
 }
 
 void
 PluginScriptableObjectChild::Initialize(PluginInstanceChild* aInstance,
                                         NPObject* aObject)
 {
+  AssertPluginThread();
+
   NS_ASSERTION(!(mInstance && mObject), "Calling Initialize class twice!");
 
   if (aObject->_class == GetClass()) {
     ChildNPObject* object = static_cast<ChildNPObject*>(aObject);
 
     NS_ASSERTION(!object->parent, "Bad object!");
     object->parent = const_cast<PluginScriptableObjectChild*>(this);
 
@@ -655,31 +684,35 @@ PluginScriptableObjectChild::Initialize(
 
   mInstance = aInstance;
   mObject = aObject;
 }
 
 bool
 PluginScriptableObjectChild::AnswerInvalidate()
 {
+  AssertPluginThread();
+
   if (mObject) {
     NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
     if (mObject->_class && mObject->_class->invalidate) {
       mObject->_class->invalidate(mObject);
     }
     PluginModuleChild::sBrowserFuncs.releaseobject(mObject);
     mObject = nsnull;
   }
   return true;
 }
 
 bool
 PluginScriptableObjectChild::AnswerHasMethod(const NPRemoteIdentifier& aId,
                                              bool* aHasMethod)
 {
+  AssertPluginThread();
+
   if (!mObject) {
     NS_WARNING("Calling AnswerHasMethod with an invalidated object!");
     *aHasMethod = false;
     return true;
   }
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
 
@@ -693,16 +726,18 @@ PluginScriptableObjectChild::AnswerHasMe
 }
 
 bool
 PluginScriptableObjectChild::AnswerInvoke(const NPRemoteIdentifier& aId,
                                           const nsTArray<Variant>& aArgs,
                                           Variant* aResult,
                                           bool* aSuccess)
 {
+  AssertPluginThread();
+
   if (!mObject) {
     NS_WARNING("Calling AnswerInvoke with an invalidated object!");
     *aResult = void_t();
     *aSuccess = false;
     return true;
   }
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
@@ -757,16 +792,18 @@ PluginScriptableObjectChild::AnswerInvok
   return true;
 }
 
 bool
 PluginScriptableObjectChild::AnswerInvokeDefault(const nsTArray<Variant>& aArgs,
                                                  Variant* aResult,
                                                  bool* aSuccess)
 {
+  AssertPluginThread();
+
   if (!mObject) {
     NS_WARNING("Calling AnswerInvokeDefault with an invalidated object!");
     *aResult = void_t();
     *aSuccess = false;
     return true;
   }
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
@@ -820,16 +857,18 @@ PluginScriptableObjectChild::AnswerInvok
   *aSuccess = true;
   return true;
 }
 
 bool
 PluginScriptableObjectChild::AnswerHasProperty(const NPRemoteIdentifier& aId,
                                                bool* aHasProperty)
 {
+  AssertPluginThread();
+
   if (!mObject) {
     NS_WARNING("Calling AnswerHasProperty with an invalidated object!");
     *aHasProperty = false;
     return true;
   }
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
 
@@ -842,16 +881,18 @@ PluginScriptableObjectChild::AnswerHasPr
   return true;
 }
 
 bool
 PluginScriptableObjectChild::AnswerGetProperty(const NPRemoteIdentifier& aId,
                                                Variant* aResult,
                                                bool* aSuccess)
 {
+  AssertPluginThread();
+
   if (!mObject) {
     NS_WARNING("Calling AnswerGetProperty with an invalidated object!");
     *aResult = void_t();
     *aSuccess = false;
     return true;
   }
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
@@ -881,16 +922,18 @@ PluginScriptableObjectChild::AnswerGetPr
   return true;
 }
 
 bool
 PluginScriptableObjectChild::AnswerSetProperty(const NPRemoteIdentifier& aId,
                                                const Variant& aValue,
                                                bool* aSuccess)
 {
+  AssertPluginThread();
+
   if (!mObject) {
     NS_WARNING("Calling AnswerSetProperty with an invalidated object!");
     *aSuccess = false;
     return true;
   }
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
 
@@ -908,16 +951,18 @@ PluginScriptableObjectChild::AnswerSetPr
   }
   return true;
 }
 
 bool
 PluginScriptableObjectChild::AnswerRemoveProperty(const NPRemoteIdentifier& aId,
                                                   bool* aSuccess)
 {
+  AssertPluginThread();
+
   if (!mObject) {
     NS_WARNING("Calling AnswerRemoveProperty with an invalidated object!");
     *aSuccess = false;
     return true;
   }
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
 
@@ -929,16 +974,18 @@ PluginScriptableObjectChild::AnswerRemov
   *aSuccess = mObject->_class->removeProperty(mObject, (NPIdentifier)aId);
   return true;
 }
 
 bool
 PluginScriptableObjectChild::AnswerEnumerate(nsTArray<NPRemoteIdentifier>* aProperties,
                                              bool* aSuccess)
 {
+  AssertPluginThread();
+
   if (!mObject) {
     NS_WARNING("Calling AnswerEnumerate with an invalidated object!");
     *aSuccess = false;
     return true;
   }
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
 
@@ -973,16 +1020,18 @@ PluginScriptableObjectChild::AnswerEnume
   return true;
 }
 
 bool
 PluginScriptableObjectChild::AnswerConstruct(const nsTArray<Variant>& aArgs,
                                              Variant* aResult,
                                              bool* aSuccess)
 {
+  AssertPluginThread();
+
   if (!mObject) {
     NS_WARNING("Calling AnswerConstruct with an invalidated object!");
     *aResult = void_t();
     *aSuccess = false;
     return true;
   }
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
--- a/dom/plugins/PluginScriptableObjectParent.cpp
+++ b/dom/plugins/PluginScriptableObjectParent.cpp
@@ -1124,29 +1124,32 @@ PluginScriptableObjectParent::AnswerSetP
     return true;
   }
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
 
   PluginInstanceParent* instance = GetInstance();
   if (!instance) {
     NS_ERROR("No instance?!");
+    *aResult = void_t();
     *aSuccess = false;
     return true;
   }
 
   const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
   if (!npn) {
     NS_ERROR("No netscape funcs?!");
+    *aResult = void_t();
     *aSuccess = false;
     return true;
   }
 
   if (!EnsureValidIdentifier(instance, (NPIdentifier)aId)) {
     NS_WARNING("Invalid NPIdentifier!");
+    *aResult = void_t();
     *aSuccess = false;
     return true;
   }
 
   NPVariant converted;
   if (!ConvertToVariant(aValue, converted, instance)) {
     *aSuccess = false;
     return true;
@@ -1169,23 +1172,25 @@ PluginScriptableObjectParent::AnswerRemo
     return true;
   }
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
 
   PluginInstanceParent* instance = GetInstance();
   if (!instance) {
     NS_ERROR("No instance?!");
+    *aResult = void_t();
     *aSuccess = false;
     return true;
   }
 
   const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
   if (!npn) {
     NS_ERROR("No netscape funcs?!");
+    *aResult = void_t();
     *aSuccess = false;
     return true;
   }
 
   if (!EnsureValidIdentifier(instance, (NPIdentifier)aId)) {
     NS_WARNING("Invalid NPIdentifier!");
     *aSuccess = false;
     return true;
@@ -1206,16 +1211,17 @@ PluginScriptableObjectParent::AnswerEnum
     return true;
   }
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
 
   PluginInstanceParent* instance = GetInstance();
   if (!instance) {
     NS_ERROR("No instance?!");
+    *aResult = void_t();
     *aSuccess = false;
     return true;
   }
 
   const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
   if (!npn) {
     NS_WARNING("No netscape funcs?!");
     *aSuccess = false;
--- a/dom/plugins/PluginStreamChild.cpp
+++ b/dom/plugins/PluginStreamChild.cpp
@@ -46,28 +46,32 @@ PluginStreamChild::PluginStreamChild(Plu
 {
   memset(&mStream, 0, sizeof(mStream));
   mStream.ndata = static_cast<AStream*>(this);
 }
 
 int32_t
 PluginStreamChild::NPN_Write(int32_t length, void* buffer)
 {
+  AssertPluginThread();
+
   int32_t written = 0;
   CallNPN_Write(nsCString(static_cast<char*>(buffer), length),
                 &written);
   if (written < 0)
     mInstance->CallPPluginStreamDestructor(this, NPERR_GENERIC_ERROR, true);
 
   return written;
 }
 
 void
 PluginStreamChild::NPP_DestroyStream(NPError reason)
 {
+  AssertPluginThread();
+
   if (mClosed)
     return;
 
   mClosed = true;
   mInstance->mPluginIface->destroystream(&mInstance->mData, &mStream, reason);
 }
 
 } // namespace plugins
--- a/ipc/glue/AsyncChannel.cpp
+++ b/ipc/glue/AsyncChannel.cpp
@@ -107,30 +107,32 @@ AsyncChannel::Close()
     // FIXME impl
 
     mChannelState = ChannelClosed;
 }
 
 bool
 AsyncChannel::Send(Message* msg)
 {
+    AssertWorkerThread();
     NS_ABORT_IF_FALSE(MSG_ROUTING_NONE != msg->routing_id(), "need a route");
 
     if (!Connected())
         // trying to Send() to a closed or error'd channel
         return false;
 
     mIOLoop->PostTask(FROM_HERE,
                       NewRunnableMethod(this, &AsyncChannel::OnSend, msg));
     return true;
 }
 
 void
 AsyncChannel::OnDispatchMessage(const Message& msg)
 {
+    AssertWorkerThread();
     NS_ASSERTION(!msg.is_reply(), "can't process replies here");
     NS_ASSERTION(!(msg.is_sync() || msg.is_rpc()), "async dispatch only");
 
     switch (mListener->OnMessageReceived(msg)) {
     case MsgProcessed:
         return;
 
     case MsgNotKnown:
@@ -150,38 +152,41 @@ AsyncChannel::OnDispatchMessage(const Me
 //
 // The methods below run in the context of the IO thread, and can proxy
 // back to the methods above
 //
 
 void
 AsyncChannel::OnMessageReceived(const Message& msg)
 {
+    AssertIOThread();
     NS_ASSERTION(mChannelState != ChannelError, "Shouldn't get here!");
 
     // wake up the worker, there's work to do
     mWorkerLoop->PostTask(FROM_HERE,
                           NewRunnableMethod(this,
                                             &AsyncChannel::OnDispatchMessage,
                                             msg));
 }
 
 void
 AsyncChannel::OnChannelConnected(int32 peer_pid)
 {
+    AssertIOThread();
     MutexAutoLock lock(mMutex);
 
     mChannelState = ChannelConnected;
 
     mCvar.Notify();
 }
 
 void
 AsyncChannel::OnChannelError()
 {
+    AssertIOThread();
     mChannelState = ChannelError;
 
     if (XRE_GetProcessType() == GeckoProcessType_Default) {
         // Parent process, one of our children died. Notify?
     }
     else {
         // Child process, initiate quit sequence.
 #ifdef DEBUG
@@ -195,22 +200,24 @@ AsyncChannel::OnChannelError()
         NS_DebugBreak(NS_DEBUG_ABORT, nsnull, nsnull, nsnull, 0);
 #endif
     }
 }
 
 void
 AsyncChannel::OnChannelOpened()
 {
+    AssertIOThread();
     mChannelState = ChannelOpening;
     /*assert*/mTransport->Connect();
 }
 
 void
 AsyncChannel::OnSend(Message* aMsg)
 {
+    AssertIOThread();
     mTransport->Send(aMsg);
     // mTransport deletes aMsg
 }
 
 
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/AsyncChannel.h
+++ b/ipc/glue/AsyncChannel.h
@@ -120,16 +120,31 @@ public:
     bool Send(Message* msg);
 
     // Implement the IPC::Channel::Listener interface
     NS_OVERRIDE virtual void OnMessageReceived(const Message& msg);
     NS_OVERRIDE virtual void OnChannelConnected(int32 peer_pid);
     NS_OVERRIDE virtual void OnChannelError();
 
 protected:
+    // Can be run on either thread
+    void AssertWorkerThread()
+    {
+        if (mWorkerLoop != MessageLoop::current()) {
+            NS_ERROR("not on worker thread!");
+        }
+    }
+
+    void AssertIOThread()
+    {
+        if (mIOLoop != MessageLoop::current()) {
+            NS_ERROR("not on IO thread!");
+        }
+    }
+
     bool Connected() {
         return ChannelConnected == mChannelState;
     }
 
     // Additional methods that execute on the worker thread
     void OnDispatchMessage(const Message& aMsg);
 
     // Additional methods that execute on the IO thread
--- a/ipc/glue/RPCChannel.cpp
+++ b/ipc/glue/RPCChannel.cpp
@@ -53,16 +53,17 @@ struct RunnableMethodTraits<mozilla::ipc
 };
 
 namespace mozilla {
 namespace ipc {
 
 bool
 RPCChannel::Call(Message* msg, Message* reply)
 {
+    AssertWorkerThread();
     NS_ABORT_IF_FALSE(!ProcessingSyncMessage(),
                       "violation of sync handler invariant");
     NS_ABORT_IF_FALSE(msg->is_rpc(),
                       "can only Call() RPC messages here");
 
     if (!Connected())
         // trying to Send() to a closed or error'd channel
         return false;
@@ -202,26 +203,28 @@ RPCChannel::Call(Message* msg, Message* 
     }
 
     return true;
 }
 
 void
 RPCChannel::OnDelegate(const Message& msg)
 {
+    AssertWorkerThread();
     if (msg.is_sync())
         return SyncChannel::OnDispatchMessage(msg);
     else if (!msg.is_rpc())
         return AsyncChannel::OnDispatchMessage(msg);
     NS_RUNTIMEABORT("fatal logic error");
 }
 
 void
 RPCChannel::OnMaybeDequeueOne()
 {
+    AssertWorkerThread();
     Message recvd;  
     {
         MutexAutoLock lock(mMutex);
 
         if (mPending.empty())
             return;
 
         NS_ABORT_IF_FALSE(mPending.size() == 1, "should only have one msg");
@@ -231,25 +234,27 @@ RPCChannel::OnMaybeDequeueOne()
         mPending.pop();
     }
     return SyncChannel::OnDispatchMessage(recvd);
 }
 
 void
 RPCChannel::OnIncall(const Message& call)
 {
+    AssertWorkerThread();
     // We only reach here from the "regular" event loop, when
     // StackDepth() == 0.  That's the "snapshot" of the state of the
     // RPCChannel we use when processing this message.
     ProcessIncall(call, 0);
 }
 
 void
 RPCChannel::ProcessIncall(const Message& call, size_t stackDepth)
 {
+    AssertWorkerThread();
     mMutex.AssertNotCurrentThreadOwns();
     NS_ABORT_IF_FALSE(call.is_rpc(),
                       "should have been handled by SyncChannel");
 
     // Race detection: see the long comment near mRemoteStackDepth 
     // in RPCChannel.h
     NS_ASSERTION(stackDepth == call.rpc_remote_stack_depth(),
                  "RPC in-calls have raced!");
@@ -293,16 +298,17 @@ RPCChannel::ProcessIncall(const Message&
 //
 // The methods below run in the context of the IO thread, and can proxy
 // back to the methods above
 //
 
 void
 RPCChannel::OnMessageReceived(const Message& msg)
 {
+    AssertIOThread();
     MutexAutoLock lock(mMutex);
 
     // regardless of the RPC stack, if we're awaiting a sync reply, we
     // know that it needs to be immediately handled to unblock us.
     // The SyncChannel will check that msg is a reply, and the right
     // kind of reply, then do its thing.
     if (AwaitingSyncReply()
         && msg.is_sync()) {
@@ -409,16 +415,17 @@ RPCChannel::OnMessageReceived(const Mess
         mCvar.Notify();
     }
 }
 
 
 void
 RPCChannel::OnChannelError()
 {
+    AssertIOThread();
     {
         MutexAutoLock lock(mMutex);
 
         mChannelState = ChannelError;
 
         if (AwaitingSyncReply()
             || 0 < StackDepth()) {
             mCvar.Notify();
--- a/ipc/glue/SyncChannel.cpp
+++ b/ipc/glue/SyncChannel.cpp
@@ -52,16 +52,17 @@ struct RunnableMethodTraits<mozilla::ipc
 };
 
 namespace mozilla {
 namespace ipc {
 
 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");
 
     if (!Connected())
         // trying to Send() to a closed or error'd channel
         return false;
 
@@ -94,16 +95,17 @@ SyncChannel::Send(Message* msg, Message*
     *reply = mRecvd;
 
     return true;
 }
 
 void
 SyncChannel::OnDispatchMessage(const Message& msg)
 {
+    AssertWorkerThread();
     NS_ABORT_IF_FALSE(msg.is_sync(), "only sync messages here");
     NS_ABORT_IF_FALSE(!msg.is_reply(), "wasn't awaiting reply");
 
     Message* reply = 0;
 
     mProcessingSyncMessage = true;
     Result rv =
         static_cast<SyncListener*>(mListener)->OnMessageReceived(msg, reply);
@@ -140,16 +142,17 @@ SyncChannel::OnDispatchMessage(const Mes
 //
 // The methods below run in the context of the IO thread, and can proxy
 // back to the methods above
 //
 
 void
 SyncChannel::OnMessageReceived(const Message& msg)
 {
+    AssertIOThread();
     if (!msg.is_sync()) {
         return AsyncChannel::OnMessageReceived(msg);
     }
 
     MutexAutoLock lock(mMutex);
 
     if (!AwaitingSyncReply()) {
         // wake up the worker, there's work to do
@@ -162,30 +165,32 @@ SyncChannel::OnMessageReceived(const Mes
         mRecvd = msg;
         mCvar.Notify();
     }
 }
 
 void
 SyncChannel::OnChannelError()
 {
+    AssertIOThread();
     {
         MutexAutoLock lock(mMutex);
 
         mChannelState = ChannelError;
 
         if (AwaitingSyncReply()) {
             mCvar.Notify();
         }
     }
 
     return AsyncChannel::OnChannelError();
 }
 
 void
 SyncChannel::OnSendReply(Message* aReply)
 {
+    AssertIOThread();
     mTransport->Send(aReply);
 }
 
 
 } // namespace ipc
 } // namespace mozilla