Bug 578868: Only load plugin libraries into the main process when absolutely necessary. r=benwa sr=bsmedberg
☠☠ backed out by 60a5b0d62bcc ☠ ☠
authorJosh Aas <joshmoz@gmail.com>
Fri, 13 Aug 2010 02:42:42 -0400
changeset 50387 452db8c688bad65a1003ff00b2606d28410c5373
parent 50386 33f8c2bb77ca11f13bf368a193cfe51b569263cd
child 50388 60a5b0d62bccef4bae84b063b392246c1007de15
child 50564 6a52899cc5b2331a8cfa540192511712445c5ad6
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbenwa, bsmedberg
bugs578868
milestone2.0b4pre
first release with
nightly win64
452db8c688ba / 4.0b4pre / 20100813011122 / files
nightly linux32
nightly linux64
nightly mac
nightly win32
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly win64
Bug 578868: Only load plugin libraries into the main process when absolutely necessary. r=benwa sr=bsmedberg
dom/plugins/PluginModuleChild.cpp
modules/plugin/base/public/npfunctions.h
modules/plugin/base/public/nsIPlugin.idl
modules/plugin/base/src/PluginPRLibrary.cpp
modules/plugin/base/src/PluginPRLibrary.h
modules/plugin/base/src/nsNPAPIPlugin.cpp
modules/plugin/base/src/nsNPAPIPlugin.h
modules/plugin/base/src/nsPluginHost.cpp
modules/plugin/base/src/nsPluginsDir.h
modules/plugin/base/src/nsPluginsDirBeOS.cpp
modules/plugin/base/src/nsPluginsDirDarwin.cpp
modules/plugin/base/src/nsPluginsDirOS2.cpp
modules/plugin/base/src/nsPluginsDirUnix.cpp
modules/plugin/base/src/nsPluginsDirWin.cpp
--- a/dom/plugins/PluginModuleChild.cpp
+++ b/dom/plugins/PluginModuleChild.cpp
@@ -184,17 +184,17 @@ PluginModuleChild::Init(const std::strin
     pluginFile->Exists(&exists);
     NS_ASSERTION(exists, "plugin file ain't there");
 
     nsCOMPtr<nsIFile> pluginIfile;
     pluginIfile = do_QueryInterface(pluginFile);
 
     nsPluginFile lib(pluginIfile);
 
-    nsresult rv = lib.LoadPlugin(mLibrary);
+    nsresult rv = lib.LoadPlugin(&mLibrary);
     NS_ASSERTION(NS_OK == rv, "trouble with mPluginFile");
     NS_ASSERTION(mLibrary, "couldn't open shared object");
 
     if (!Open(aChannel, aParentProcessHandle, aIOLoop))
         return false;
 
     memset((void*) &mFunctions, 0, sizeof(mFunctions));
     mFunctions.size = sizeof(mFunctions);
--- a/modules/plugin/base/public/npfunctions.h
+++ b/modules/plugin/base/public/npfunctions.h
@@ -262,43 +262,55 @@ typedef struct _NPPluginData {   /* Alte
   char *pMimeTypes;
   char *pFileExtents;
   char *pFileOpenTemplate;
   char *pProductName;
   char *pProductDescription;
   unsigned long dwProductVersionMS;
   unsigned long dwProductVersionLS;
 } NPPluginData;
-NPError OSCALL NP_GetPluginData(NPPluginData * pPluginData);
+typedef NPError (*NP_GetPluginDataFunc)(NPPluginData*);
+NPError OSCALL  NP_GetPluginData(NPPluginData * pPluginData);
 #endif
-NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs);
-NPError OSCALL NP_Initialize(NPNetscapeFuncs* bFuncs);
-NPError OSCALL NP_Shutdown();
-char*          NP_GetMIMEDescription();
+typedef NPError (*NP_GetEntryPointsFunc)(NPPluginFuncs*);
+NPError OSCALL  NP_GetEntryPoints(NPPluginFuncs* pFuncs);
+typedef NPError (*NP_InitializeFunc)(NPNetscapeFuncs*);
+NPError OSCALL  NP_Initialize(NPNetscapeFuncs* bFuncs);
+typedef NPError (*NP_ShutdownFunc)();
+NPError OSCALL  NP_Shutdown();
+typedef char*   (*NP_GetMIMEDescriptionFunc)();
+char*           NP_GetMIMEDescription();
 #ifdef __cplusplus
 }
 #endif
 #endif
 
 #if defined(__OS2__)
 #pragma pack()
 #endif
 
 #ifdef XP_UNIX
 #ifdef __cplusplus
 extern "C" {
 #endif
+typedef char*      (*NP_GetPluginVersionFunc)();
 NP_EXPORT(char*)   NP_GetPluginVersion();
+typedef char*      (*NP_GetMIMEDescriptionFunc)();
 NP_EXPORT(char*)   NP_GetMIMEDescription();
 #ifdef XP_MACOSX
+typedef NPError    (*NP_InitializeFunc)(NPNetscapeFuncs*);
 NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs);
+typedef NPError    (*NP_GetEntryPointsFunc)(NPPluginFuncs*);
 NP_EXPORT(NPError) NP_GetEntryPoints(NPPluginFuncs* pFuncs);
 #else
+typedef NPError    (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*);
 NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs);
 #endif
+typedef NPError    (*NP_ShutdownFunc)();
 NP_EXPORT(NPError) NP_Shutdown();
+typedef NPError    (*NP_GetValueFunc)(void *, NPPVariable, void *);
 NP_EXPORT(NPError) NP_GetValue(void *future, NPPVariable aVariable, void *aValue);
 #ifdef __cplusplus
 }
 #endif
 #endif
 
 #endif /* npfunctions_h_ */
--- a/modules/plugin/base/public/nsIPlugin.idl
+++ b/modules/plugin/base/public/nsIPlugin.idl
@@ -42,17 +42,17 @@
 #include "npapi.h"
 
 #define MOZ_PLUGIN_CONTRACTID \
   "@mozilla.org/plugin/plugin;1"
 %}
 
 interface nsIPluginInstance;
 
-[uuid(843D6092-2BB0-4A21-8827-0510A52CA795)]
+[uuid(94C32FEA-5C50-49D3-9D3D-9047CD342777)]
 interface nsIPlugin : nsISupports
 {
   /**
    * Creates a new plugin instance, based on a MIME type. This
    * allows different impelementations to be created depending on
    * the specified MIME type.
    */
   void createPluginInstance(out nsIPluginInstance aResult);
@@ -61,34 +61,9 @@ interface nsIPlugin : nsISupports
    * Called when the browser is done with the plugin factory, or when
    * the plugin is disabled by the user.
    *
    * (Corresponds to NPP_Shutdown.)
    *
    * @result - NS_OK if this operation was successful
    */
   void shutdown();
-
-  /**
-   * Returns the MIME description for the plugin. The MIME description 
-   * is a colon-separated string containg the plugin MIME type, plugin
-   * data file extension, and plugin name, e.g.:
-   *
-   * "application/x-simple-plugin:smp:Simple Sample Plug-in"
-   *
-   * (Corresponds to NPP_GetMIMEDescription.)
-   *
-   * @param aMIMEDescription - the resulting MIME description 
-   * @result                 - NS_OK if this operation was successful
-   */
-  void getMIMEDescription(out constCharPtr aMIMEDescription);
-
-  /**
-   * Returns the value of a variable associated with the plugin.
-   *
-   * (Corresponds to NPP_GetValue.)
-   *
-   * @param aVariable - the plugin variable to get
-   * @param aValue    - the address of where to store the resulting value
-   * @result          - NS_OK if this operation was successful
-   */
-  void getValue(in NPPVariable aVariable, in voidPtr aValue);
 };
--- a/modules/plugin/base/src/PluginPRLibrary.cpp
+++ b/modules/plugin/base/src/PluginPRLibrary.cpp
@@ -132,27 +132,29 @@ PluginPRLibrary::NP_GetMIMEDescription(c
 
   return NS_OK;
 }
 
 nsresult
 PluginPRLibrary::NP_GetValue(void *future, NPPVariable aVariable,
 			     void *aValue, NPError* error)
 {
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
   if (mNP_GetValue) {
     *error = mNP_GetValue(future, aVariable, aValue);
   } else {
-    NP_GetValueFunc pfNP_GetValue = (NP_GetValueFunc)
-      PR_FindFunctionSymbol(mLibrary, "NP_GetValue");
+    NP_GetValueFunc pfNP_GetValue = (NP_GetValueFunc)PR_FindFunctionSymbol(mLibrary, "NP_GetValue");
     if (!pfNP_GetValue)
       return NS_ERROR_FAILURE;
     *error = pfNP_GetValue(future, aVariable, aValue);
   }
-
   return NS_OK;
+#else
+  return NS_ERROR_NOT_IMPLEMENTED;
+#endif
 }
 
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_OS2)
 nsresult
 PluginPRLibrary::NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error)
 {
   CALLING_CONVENTION_HACK
 
--- a/modules/plugin/base/src/PluginPRLibrary.h
+++ b/modules/plugin/base/src/PluginPRLibrary.h
@@ -36,43 +36,34 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef PluginPRLibrary_h
 #define PluginPRLibrary_h 1
 
 #include "mozilla/PluginLibrary.h"
 #include "nsNPAPIPlugin.h"
+#include "npfunctions.h"
 
 namespace mozilla {
 
 class PluginPRLibrary : public PluginLibrary
 {
-#if defined(XP_UNIX) && !defined(XP_MACOSX)
-    typedef NPError (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*);
-#else
-    typedef NPError (OSCALL *NP_InitializeFunc)(NPNetscapeFuncs*);
-#endif
-    typedef NPError (OSCALL *NP_ShutdownFunc)();
-    typedef char* (*NP_GetMIMEDescriptionFunc)();
-    typedef NPError (*NP_GetValueFunc)(void *, NPPVariable, void*);
-#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_OS2)
-    typedef NPError (OSCALL *NP_GetEntryPointsFunc)(NPPluginFuncs*);
-#endif
-
 public:
     PluginPRLibrary(const char* aFilePath, PRLibrary* aLibrary) :
 #if defined(XP_UNIX) && !defined(XP_MACOSX)
         mNP_Initialize(nsnull),
 #else
         mNP_Initialize(nsnull),
 #endif
         mNP_Shutdown(nsnull),
         mNP_GetMIMEDescription(nsnull),
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
         mNP_GetValue(nsnull),
+#endif
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_OS2)
         mNP_GetEntryPoints(nsnull),
 #endif
         mNPP_New(nsnull),
         mLibrary(aLibrary)
     {
         NS_ASSERTION(mLibrary, "need non-null lib");
         // addref here??
@@ -98,19 +89,19 @@ public:
 
         mNP_GetMIMEDescription = (NP_GetMIMEDescriptionFunc)
             PR_FindFunctionSymbol(mLibrary, "NP_GetMIMEDescription");
 #ifndef XP_MACOSX
         if (!mNP_GetMIMEDescription)
             return false;
 #endif
 
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
         mNP_GetValue = (NP_GetValueFunc)
             PR_FindFunctionSymbol(mLibrary, "NP_GetValue");
-#ifndef XP_MACOSX
         if (!mNP_GetValue)
             return false;
 #endif
 
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_OS2)
         mNP_GetEntryPoints = (NP_GetEntryPointsFunc)
             PR_FindFunctionSymbol(mLibrary, "NP_GetEntryPoints");
         if (!mNP_GetEntryPoints)
@@ -141,17 +132,19 @@ public:
                              uint16_t mode, int16_t argc, char* argn[],
                              char* argv[], NPSavedData* saved,
                              NPError* error);
 
 private:
     NP_InitializeFunc mNP_Initialize;
     NP_ShutdownFunc mNP_Shutdown;
     NP_GetMIMEDescriptionFunc mNP_GetMIMEDescription;
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
     NP_GetValueFunc mNP_GetValue;
+#endif
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_OS2)
     NP_GetEntryPointsFunc mNP_GetEntryPoints;
 #endif
     NPP_NewProcPtr mNPP_New;
     PRLibrary* mLibrary;
 };
 
 
--- a/modules/plugin/base/src/nsNPAPIPlugin.cpp
+++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp
@@ -261,18 +261,16 @@ void
 nsNPAPIPlugin::PluginCrashed(const nsAString& pluginDumpID,
                              const nsAString& browserDumpID)
 {
   nsRefPtr<nsPluginHost> host = dont_AddRef(nsPluginHost::GetInst());
   host->PluginCrashed(this, pluginDumpID, browserDumpID);
 }
 #endif
 
-namespace {
-
 #ifdef MOZ_IPC
 
 #ifdef XP_MACOSX
 static PRInt32 OSXVersion()
 {
   static PRInt32 gOSXVersion = 0x0;
   if (gOSXVersion == 0x0) {
     OSErr err = ::Gestalt(gestaltSystemVersion, (SInt32*)&gOSXVersion);
@@ -305,18 +303,18 @@ static PRBool GMA9XXGraphics()
       }
     }
     ::CGLDestroyRendererInfo(renderer);
   }
   return hasIntelGMA9XX;
 }
 #endif
 
-inline PRBool
-RunPluginOOP(const char* aFilePath, const nsPluginTag *aPluginTag)
+PRBool
+nsNPAPIPlugin::RunPluginOOP(const char* aFilePath, const nsPluginTag *aPluginTag)
 {
   if (PR_GetEnv("MOZ_DISABLE_OOP_PLUGINS")) {
     return PR_FALSE;
   }
 
 #ifdef XP_MACOSX
   // Only allow on Mac OS X 10.6 or higher.
   if (OSXVersion() < 0x00001060) {
@@ -389,33 +387,35 @@ RunPluginOOP(const char* aFilePath, cons
 inline PluginLibrary*
 GetNewPluginLibrary(const char* aFilePath,
                     PRLibrary* aLibrary)
 {
 #ifdef MOZ_IPC
   nsRefPtr<nsPluginHost> host = dont_AddRef(nsPluginHost::GetInst());
   nsPluginTag* tag = host->FindTagForLibrary(aLibrary);
   if (tag) {
-    if (aFilePath && RunPluginOOP(aFilePath, tag)) {
+    if (aFilePath && nsNPAPIPlugin::RunPluginOOP(aFilePath, tag)) {
       return PluginModuleParent::LoadModule(aFilePath);
     }
   }
 #endif
   return new PluginPRLibrary(aFilePath, aLibrary);
 }
 
-} /* anonymous namespace */
-
 // Creates an nsNPAPIPlugin object. One nsNPAPIPlugin object exists per plugin (not instance).
 nsresult
 nsNPAPIPlugin::CreatePlugin(const char* aFilePath, PRLibrary* aLibrary,
                             nsIPlugin** aResult)
 {
   *aResult = nsnull;
 
+  if (!aFilePath || !aLibrary) {
+    return NS_ERROR_FAILURE;
+  }
+
   CheckClassInitialized();
 
   nsRefPtr<nsNPAPIPlugin> plugin = new nsNPAPIPlugin();
   if (!plugin)
     return NS_ERROR_OUT_OF_MEMORY;
 
   PluginLibrary* pluginLib = GetNewPluginLibrary(aFilePath, aLibrary);
   if (!pluginLib) {
@@ -427,24 +427,16 @@ nsNPAPIPlugin::CreatePlugin(const char* 
     NS_WARNING("Not all necessary functions exposed by plugin, it will not load.");
     return NS_ERROR_FAILURE;
   }
 #endif
 
   plugin->mLibrary = pluginLib;
   pluginLib->SetPlugin(plugin);
 
-#if defined(XP_UNIX) && !defined(XP_MACOSX)
-  // Do not initialize if the file path is NULL.
-  if (!aFilePath) {
-    *aResult = plugin.forget().get();
-    return NS_OK;
-  }
-#endif
-
   NPError pluginCallError;
   nsresult rv;
 
 // Exchange NPAPI entry points.
 #if defined(XP_WIN) || defined(XP_OS2)
   // NP_GetEntryPoints must be called before NP_Initialize on Windows.
   rv = pluginLib->NP_GetEntryPoints(&plugin->mPluginFuncs, &pluginCallError);
   if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) {
@@ -518,39 +510,16 @@ nsNPAPIPlugin::Shutdown()
   mLibrary->NP_Shutdown(&shutdownError);
 #if defined(XP_MACOSX) && !defined(__LP64__)
   if (shutdownError == NS_OK && mPluginRefNum > 0)
     ::CloseResFile(mPluginRefNum);
 #endif
   return NS_OK;
 }
 
-nsresult
-nsNPAPIPlugin::GetMIMEDescription(const char* *resultingDesc)
-{
-  nsresult gmdResult = mLibrary->NP_GetMIMEDescription(resultingDesc);
-  if (gmdResult != NS_OK) {
-    return gmdResult;
-  }
-
-  return NS_OK;
-}
-
-nsresult
-nsNPAPIPlugin::GetValue(NPPVariable variable, void *value)
-{
-  PLUGIN_LOG(PLUGIN_LOG_NORMAL,
-  ("nsNPAPIPlugin::GetValue called: this=%p, variable=%d\n", this, variable));
-
-  NPError gvError;
-  mLibrary->NP_GetValue(nsnull, variable, value, &gvError);
-
-  return gvError;
-}
-
 // Create a new NPP GET or POST (given in the type argument) url
 // stream that may have a notify callback
 NPError
 MakeNewNPAPIStreamInternal(NPP npp, const char *relativeURL, const char *target,
                           eNPPStreamTypeInternal type,
                           PRBool bDoNotify = PR_FALSE,
                           void *notifyData = nsnull, uint32_t len = 0,
                           const char *buf = nsnull, NPBool file = PR_FALSE)
--- a/modules/plugin/base/src/nsNPAPIPlugin.h
+++ b/modules/plugin/base/src/nsNPAPIPlugin.h
@@ -99,16 +99,18 @@ public:
 
 #ifdef MOZ_IPC
   // The IPC mechanism notifies the nsNPAPIPlugin if the plugin
   // crashes and is no longer usable. pluginDumpID/browserDumpID are
   // the IDs of respective minidumps that were written, or empty if no
   // minidump was written.
   void PluginCrashed(const nsAString& pluginDumpID,
                      const nsAString& browserDumpID);
+  
+  static PRBool RunPluginOOP(const char* aFilePath, const nsPluginTag *aPluginTag);
 #endif
 
 protected:
 
 #if defined(XP_MACOSX) && !defined(__LP64__)
   short mPluginRefNum;
 #endif
 
--- a/modules/plugin/base/src/nsPluginHost.cpp
+++ b/modules/plugin/base/src/nsPluginHost.cpp
@@ -296,16 +296,32 @@ NS_IMETHODIMP nsPluginDocReframeEvent::R
 
       }
     }
   }
 
   return mDocs->Clear();
 }
 
+static PRBool UnloadPluginsASAP()
+{
+  nsresult rv;
+  nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+  if (NS_SUCCEEDED(rv)) {
+    PRBool unloadPluginsASAP = PR_FALSE;
+    rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP);
+    if (NS_SUCCEEDED(rv)) {
+      return unloadPluginsASAP;
+    }
+  }
+
+  NS_WARNING("Unable to retrieve pref: plugins.unloadASAP");
+  return PR_FALSE;
+}
+
 // helper struct for asynchronous handling of plugin unloading
 class nsPluginUnloadEvent : public nsRunnable {
 public:
   nsPluginUnloadEvent(PRLibrary* aLibrary)
     : mLibrary(aLibrary)
   {}
  
   NS_DECL_NSIRUNNABLE
@@ -412,19 +428,16 @@ nsPluginHost::GetInst()
   return sInst;
 }
 
 PRBool nsPluginHost::IsRunningPlugin(nsPluginTag * plugin)
 {
   if (!plugin)
     return PR_FALSE;
 
-  if (!plugin->mLibrary)
-    return PR_FALSE;
-
   for (int i = 0; i < plugin->mVariants; i++) {
     nsNPAPIPluginInstance *instance = FindInstance(plugin->mMimeTypeArray[i]);
     if (instance && instance->IsRunning())
       return PR_TRUE;
   }
 
   return PR_FALSE;
 }
@@ -862,26 +875,18 @@ void nsPluginHost::OnPluginInstanceDestr
   PRBool hasInstance = PR_FALSE;
   for (PRUint32 i = 0; i < mInstances.Length(); i++) {
     if (TagForPlugin(mInstances[i]->GetPlugin()) == aPluginTag) {
       hasInstance = PR_TRUE;
       break;
     }
   }
 
-  if (!hasInstance) {
-    nsresult rv;
-    nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
-    if (NS_FAILED(rv))
-      return;
-
-    PRBool unloadPluginsASAP = PR_FALSE;
-    rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP);
-    if (NS_SUCCEEDED(rv) && unloadPluginsASAP)
-      aPluginTag->TryUnloadPlugin();
+  if (!hasInstance && UnloadPluginsASAP()) {
+    aPluginTag->TryUnloadPlugin();
   }
 }
 
 nsresult
 nsPluginHost::GetPluginTempDir(nsIFile **aDir)
 {
   if (!sPluginTempDir) {
     nsCOMPtr<nsIFile> tmpDir;
@@ -1265,20 +1270,18 @@ nsPluginHost::TrySetUpPluginInstance(con
 
   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
         ("nsPluginHost::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
         aMimeType, aOwner, urlSpec.get()));
 
   PR_LogFlush();
 #endif
 
-
-  nsresult result = NS_ERROR_FAILURE;
-  nsCOMPtr<nsIPluginInstance> instance;
-  nsCOMPtr<nsIPlugin> plugin;
+  nsresult rv = NS_ERROR_FAILURE;
+  
   const char* mimetype = nsnull;
 
   // if don't have a mimetype or no plugin can handle this mimetype
   // check by file extension
   nsPluginTag* pluginTag = FindPluginForType(aMimeType, PR_TRUE);
   if (!pluginTag) {
     nsCOMPtr<nsIURL> url = do_QueryInterface(aURL);
     if (!url) return NS_ERROR_FAILURE;
@@ -1295,78 +1298,81 @@ nsPluginHost::TrySetUpPluginInstance(con
     }
   }
   else {
     mimetype = aMimeType;
   }
 
   NS_ASSERTION(pluginTag, "Must have plugin tag here!");
 
+  nsCOMPtr<nsIPlugin> plugin;
   GetPlugin(mimetype, getter_AddRefs(plugin));
 
+  nsCOMPtr<nsIPluginInstance> instance;
   if (plugin) {
 #if defined(XP_WIN) && !defined(WINCE)
     static BOOL firstJavaPlugin = FALSE;
     BOOL restoreOrigDir = FALSE;
     WCHAR origDir[_MAX_PATH];
     if (pluginTag->mIsJavaPlugin && !firstJavaPlugin) {
       DWORD dw = GetCurrentDirectoryW(_MAX_PATH, origDir);
       NS_ASSERTION(dw <= _MAX_PATH, "Failed to obtain the current directory, which may lead to incorrect class loading");
       nsCOMPtr<nsIFile> binDirectory;
-      result = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
-                                      getter_AddRefs(binDirectory));
-
-      if (NS_SUCCEEDED(result)) {
+      rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
+                                  getter_AddRefs(binDirectory));
+
+      if (NS_SUCCEEDED(rv)) {
         nsAutoString path;
         binDirectory->GetPath(path);
         restoreOrigDir = SetCurrentDirectoryW(path.get());
       }
     }
 #endif
-    result = plugin->CreatePluginInstance(getter_AddRefs(instance));
+
+    rv = plugin->CreatePluginInstance(getter_AddRefs(instance));
 
 #if defined(XP_WIN) && !defined(WINCE)
     if (!firstJavaPlugin && restoreOrigDir) {
       BOOL bCheck = SetCurrentDirectoryW(origDir);
       NS_ASSERTION(bCheck, "Error restoring directory");
       firstJavaPlugin = TRUE;
     }
 #endif
   }
 
-  if (NS_FAILED(result))
-    return result;
+  if (NS_FAILED(rv))
+    return rv;
 
   // it is adreffed here
   aOwner->SetInstance(instance);
 
   // this should not addref the instance or owner
   // except in some cases not Java, see bug 140931
   // our COM pointer will free the peer
-  result = instance->Initialize(aOwner, mimetype);
-  if (NS_FAILED(result)) {
+  rv = instance->Initialize(aOwner, mimetype);
+  if (NS_FAILED(rv)) {
     aOwner->SetInstance(nsnull);
-    return result;
+    return rv;
   }
 
   mInstances.AppendElement(static_cast<nsNPAPIPluginInstance*>(instance.get()));
 
 #ifdef PLUGIN_LOGGING
   nsCAutoString urlSpec2;
   if (aURL)
     aURL->GetSpec(urlSpec2);
 
   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
         ("nsPluginHost::TrySetupPluginInstance Finished mime=%s, rv=%d, owner=%p, url=%s\n",
-        aMimeType, result, aOwner, urlSpec2.get()));
+        aMimeType, rv, aOwner, urlSpec2.get()));
 
   PR_LogFlush();
 #endif
 
-  return result;
+  return rv;
 }
 
 NS_IMETHODIMP
 nsPluginHost::IsPluginEnabledForType(const char* aMimeType)
 {
   nsPluginTag *plugin = FindPluginForType(aMimeType, PR_TRUE);
   if (plugin)
     return NS_OK;
@@ -1688,19 +1694,39 @@ static nsresult ConvertToNative(nsIUnico
     return NS_ERROR_OUT_OF_MEMORY;
   rv = aEncoder->Convert(utf16.get(), &len,
                          aNativeString.BeginWriting(), &outLen);
   NS_ENSURE_SUCCESS(rv, rv);
   aNativeString.SetLength(outLen);
   return NS_OK;
 }
 
-static nsresult CreateNPAPIPlugin(const nsPluginTag *aPluginTag,
+static nsresult CreateNPAPIPlugin(nsPluginTag *aPluginTag,
                                   nsIPlugin **aOutNPAPIPlugin)
 {
+  // If this is an in-process plugin we'll need to load it here if we haven't already.
+#ifdef MOZ_IPC
+  if (!aPluginTag->mLibrary &&
+      !nsNPAPIPlugin::RunPluginOOP(aPluginTag->mFileName.get(), aPluginTag)) {
+#else
+  if (!aPluginTag->mLibrary) {
+#endif
+    if (aPluginTag->mFullPath.IsEmpty())
+      return NS_ERROR_FAILURE;
+    nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
+    file->InitWithPath(NS_ConvertUTF8toUTF16(aPluginTag->mFullPath));
+    nsPluginFile pluginFile(file);
+    PRLibrary* pluginLibrary = NULL;
+
+    if (NS_FAILED(pluginFile.LoadPlugin(&pluginLibrary)) || !pluginLibrary)
+      return NS_ERROR_FAILURE;
+
+    aPluginTag->mLibrary = pluginLibrary;
+  }
+
   nsresult rv;
   nsCOMPtr <nsIPlatformCharset> pcs =
     do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCAutoString charset;
   rv = pcs->GetCharset(kPlatformCharsetSel_FileName, charset);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1761,38 +1787,22 @@ NS_IMETHODIMP nsPluginHost::GetPlugin(co
     ("nsPluginHost::GetPlugin Begin mime=%s, plugin=%s\n",
     aMimeType, pluginTag->mFileName.get()));
 
 #ifdef NS_DEBUG
     if (aMimeType && !pluginTag->mFileName.IsEmpty())
       printf("For %s found plugin %s\n", aMimeType, pluginTag->mFileName.get());
 #endif
 
-    if (!pluginTag->mLibrary) { // if we haven't done this yet
-      if (pluginTag->mFullPath.IsEmpty())
-        return NS_ERROR_FAILURE;
-      nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
-      file->InitWithPath(NS_ConvertUTF8toUTF16(pluginTag->mFullPath));
-      nsPluginFile pluginFile(file);
-      PRLibrary* pluginLibrary = NULL;
-
-      if (pluginFile.LoadPlugin(pluginLibrary) != NS_OK || pluginLibrary == NULL)
-        return NS_ERROR_FAILURE;
-
-      pluginTag->mLibrary = pluginLibrary;
-    }
-
+    // Create a plugin object if necessary
     nsCOMPtr<nsIPlugin> plugin = pluginTag->mEntryPoint;
     if (!plugin) {
-      // Now lets try to get the entry point from an NPAPI plugin
       rv = CreateNPAPIPlugin(pluginTag, getter_AddRefs(plugin));
       if (NS_FAILED(rv))
         return rv;
-
-      NS_ASSERTION(plugin, "CreateNPAPIPlugin succeeded without setting 'plugin'");
       pluginTag->mEntryPoint = plugin;
     }
 
     NS_ADDREF(*aPlugin = plugin);
     return NS_OK;
   }
 
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
@@ -2036,41 +2046,34 @@ nsresult nsPluginHost::ScanPluginsDirect
         return NS_OK;
       else
         continue;
     }
 
     // if it is not found in cache info list or has been changed, create a new one
     if (!pluginTag) {
       nsPluginFile pluginFile(file);
-      PRLibrary* pluginLibrary = nsnull;
-
-      // load the plugin's library so we can ask it some questions, but not for Windows
-#ifndef XP_WIN
-      if (pluginFile.LoadPlugin(pluginLibrary) != NS_OK || pluginLibrary == nsnull)
-        continue;
-#endif
 
       // create a tag describing this plugin.
+      PRLibrary *library = nsnull;
       nsPluginInfo info;
       memset(&info, 0, sizeof(info));
-      nsresult res = pluginFile.GetPluginInfo(info);
+      nsresult res = pluginFile.GetPluginInfo(info, &library);
       // if we don't have mime type don't proceed, this is not a plugin
       if (NS_FAILED(res) || !info.fMimeTypeArray) {
         pluginFile.FreePluginInfo(info);
         continue;
       }
 
       pluginTag = new nsPluginTag(&info);
       pluginFile.FreePluginInfo(info);
-
-      if (pluginTag == nsnull)
+      if (!pluginTag)
         return NS_ERROR_OUT_OF_MEMORY;
 
-      pluginTag->mLibrary = pluginLibrary;
+      pluginTag->mLibrary = library;
       pluginTag->mLastModifiedTime = fileModTime;
 
       nsCOMPtr<nsIBlocklistService> blocklist = do_GetService("@mozilla.org/extensions/blocklist;1");
       if (blocklist) {
         PRUint32 state;
         rv = blocklist->GetPluginBlocklistState(pluginTag, EmptyString(),
                                                 EmptyString(), &state);
 
@@ -2095,16 +2098,23 @@ nsresult nsPluginHost::ScanPluginsDirect
       NS_ASSERTION(!pluginTag->HasFlag(NS_PLUGIN_FLAG_UNWANTED),
                    "Brand-new tags should not be unwanted");
       if ((checkForUnwantedPlugins && isUnwantedPlugin(pluginTag)) ||
          IsDuplicatePlugin(pluginTag)) {
         pluginTag->Mark(NS_PLUGIN_FLAG_UNWANTED);
         pluginTag->mNext = mCachedPlugins;
         mCachedPlugins = pluginTag;
       }
+
+      // Plugin unloading is tag-based. If we created a new tag and loaded
+      // the library in the process then we want to attempt to unload it here.
+      // Only do this if the pref is set for aggressive unloading.
+      if (UnloadPluginsASAP()) {
+        pluginTag->TryUnloadPlugin();
+      }
     }
 
     // set the flag that we want to add this plugin to the list for now
     // and see if it remains after we check several reasons not to do so
     PRBool bAddIt = PR_TRUE;
 
     // check if this is a specific plugin we don't want
     if (checkForUnwantedPlugins && isUnwantedPlugin(pluginTag))
--- a/modules/plugin/base/src/nsPluginsDir.h
+++ b/modules/plugin/base/src/nsPluginsDir.h
@@ -88,22 +88,23 @@ public:
 	 */
 	nsPluginFile(nsIFile* spec);
 	virtual ~nsPluginFile();
 
 	/**
 	 * Loads the plugin into memory using NSPR's shared-library loading
 	 * mechanism. Handles platform differences in loading shared libraries.
 	 */
-	nsresult LoadPlugin(PRLibrary* &outLibrary);
+	nsresult LoadPlugin(PRLibrary **outLibrary);
 
 	/**
 	 * Obtains all of the information currently available for this plugin.
+	 * Has a library outparam which will be non-null if a library load was required.
 	 */
-	nsresult GetPluginInfo(nsPluginInfo &outPluginInfo);
+	nsresult GetPluginInfo(nsPluginInfo &outPluginInfo, PRLibrary **outLibrary);
 
   /**
 	 * Should be called after GetPluginInfo to free all allocated stuff
 	 */
 	nsresult FreePluginInfo(nsPluginInfo &PluginInfo);
 
 	// Open the resource fork for the plugin
 	short OpenPluginResource(void);
--- a/modules/plugin/base/src/nsPluginsDirBeOS.cpp
+++ b/modules/plugin/base/src/nsPluginsDirBeOS.cpp
@@ -134,40 +134,42 @@ nsPluginFile::~nsPluginFile()
 {
 	// nada
 }
 
 /**
  * Loads the plugin into memory using NSPR's shared-library loading
  * mechanism. Handles platform differences in loading shared libraries.
  */
-nsresult nsPluginFile::LoadPlugin(PRLibrary* &outLibrary)
+nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
 {
         nsCAutoString path;
         nsresult rv = mPlugin->GetNativePath(path);
         if (NS_OK != rv) {
             return rv;
         }
-        pLibrary = outLibrary = PR_LoadLibrary(path.get());
+        pLibrary = *outLibrary = PR_LoadLibrary(path.get());
 
 #ifdef NS_DEBUG
         printf("LoadPlugin() %s returned %lx\n",path,(unsigned long)pLibrary);
 #endif
 
         return NS_OK;
 }
 
 typedef char* (*BeOS_Plugin_GetMIMEDescription)();
 
 
 /**
  * Obtains all of the information currently available for this plugin.
  */
-nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info)
+nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary)
 {
+    *outLibrary = nsnull;
+
     info.fVersion = nsnull;
 
     nsCAutoString fullPath;
     if (NS_FAILED(rv = mPlugin->GetNativePath(fullPath)))
         return rv;
 
     nsCAutoString fileName;
     if (NS_FAILED(rv = mPlugin->GetNativeLeafName(fileName)))
--- a/modules/plugin/base/src/nsPluginsDirDarwin.cpp
+++ b/modules/plugin/base/src/nsPluginsDirDarwin.cpp
@@ -215,17 +215,17 @@ static void ParsePlistPluginInfo(nsPlugi
 
 nsPluginFile::nsPluginFile(nsIFile *spec)
     : mPlugin(spec)
 {
 }
 
 nsPluginFile::~nsPluginFile() {}
 
-nsresult nsPluginFile::LoadPlugin(PRLibrary* &outLibrary)
+nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
 {
   if (!mPlugin)
     return NS_ERROR_NULL_POINTER;
 
   // 64-bit NSPR does not (yet) support bundles.  So in 64-bit builds we need
   // (for now) to load the bundle's executable.  However this can cause
   // problems:  CFBundleCreate() doesn't run the bundle's executable's
   // initialization code, while NSAddImage() and dlopen() do run it.  So using
@@ -256,19 +256,19 @@ nsresult nsPluginFile::LoadPlugin(PRLibr
     ::CFRelease(pathRef); 
   }
 #else
   nsCAutoString bundlePath;
   mPlugin->GetNativePath(bundlePath);
   const char *executablePath = bundlePath.get();
 #endif
 
-  outLibrary = PR_LoadLibrary(executablePath);
-  pLibrary = outLibrary;
-  if (!outLibrary) {
+  *outLibrary = PR_LoadLibrary(executablePath);
+  pLibrary = *outLibrary;
+  if (!pLibrary) {
     return NS_ERROR_FAILURE;
   }
 #ifdef DEBUG
   printf("[loaded plugin %s]\n", bundlePath.get());
 #endif
   return NS_OK;
 }
 
@@ -345,27 +345,27 @@ public:
 private:
   short mRefNum;
 };
 #endif
 
 /**
  * Obtains all of the information currently available for this plugin.
  */
-nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info)
+nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary)
 {
+  *outLibrary = nsnull;
+
   nsresult rv = NS_OK;
 
   // clear out the info, except for the first field.
   memset(&info, 0, sizeof(info));
 
-  // First open up resource we can use to get plugin info.
-
 #ifndef __LP64__
-  // Try to open a resource fork.
+  // Try to open a resource fork in case we have to use it.
   nsAutoCloseResourceObject resourceObject(mPlugin);
   bool resourceOpened = resourceObject.ResourceOpened();
 #endif
 
   // Try to get a bundle reference.
   nsCAutoString path;
   if (NS_FAILED(rv = mPlugin->GetNativePath(path)))
     return rv;
@@ -423,24 +423,29 @@ nsresult nsPluginFile::GetPluginInfo(nsP
   // The last thing we need to do is get MIME data
   // fVariantCount, fMimeTypeArray, fExtensionArray, fMimeDescriptionArray
 
   // First look for data in a bundle plist
   if (bundle) {
     ParsePlistPluginInfo(info, bundle);
     ::CFRelease(bundle);
     if (info.fVariantCount > 0)
-      return NS_OK;    
+      return NS_OK;
   }
 
   // It's possible that our plugin has 2 entry points that'll give us mime type
   // info. Quicktime does this to get around the need of having admin rights to
   // change mime info in the resource fork. We need to use this info instead of
   // the resource. See bug 113464.
 
+  // Sadly we have to load the library for this to work.
+  rv = LoadPlugin(outLibrary);
+  if (NS_FAILED(rv))
+    return rv;
+
   // Try to get data from NP_GetMIMEDescription
   if (pLibrary) {
     NP_GETMIMEDESCRIPTION pfnGetMimeDesc = (NP_GETMIMEDESCRIPTION)PR_FindFunctionSymbol(pLibrary, NP_GETMIMEDESCRIPTION_NAME); 
     if (pfnGetMimeDesc)
       ParsePluginMimeDescription(pfnGetMimeDesc(), info);
     if (info.fVariantCount)
       return NS_OK;
   }
--- a/modules/plugin/base/src/nsPluginsDirOS2.cpp
+++ b/modules/plugin/base/src/nsPluginsDirOS2.cpp
@@ -194,31 +194,33 @@ PRBool nsPluginsDir::IsPluginFile(nsIFil
 nsPluginFile::nsPluginFile(nsIFile* file)
 : mPlugin(file)
 {}
 
 nsPluginFile::~nsPluginFile()
 {}
 
 // Loads the plugin into memory using NSPR's shared-library loading
-nsresult nsPluginFile::LoadPlugin( PRLibrary *&outLibrary)
+nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
 {
     if (!mPlugin)
       return NS_ERROR_NULL_POINTER;
    
     nsCAutoString temp;
     mPlugin->GetNativePath(temp);
 
-    outLibrary = PR_LoadLibrary(temp.get());
-    return outLibrary == nsnull ? NS_ERROR_FAILURE : NS_OK;
+    *outLibrary = PR_LoadLibrary(temp.get());
+    return *outLibrary == nsnull ? NS_ERROR_FAILURE : NS_OK;
 }
 
 // Obtains all of the information currently available for this plugin.
-nsresult nsPluginFile::GetPluginInfo( nsPluginInfo &info)
+nsresult nsPluginFile::GetPluginInfo(nsPluginInfo &info, PRLibrary **outLibrary)
 {
+   *outLibrary = nsnull;
+
    nsresult   rv = NS_ERROR_FAILURE;
    HMODULE    hPlug = 0; // Need a HMODULE to query resource statements
    char       failure[ CCHMAXPATH] = "";
    APIRET     ret;
 
    nsCAutoString path;
    if (NS_FAILED(rv = mPlugin->GetNativePath(path)))
      return rv;
--- a/modules/plugin/base/src/nsPluginsDirUnix.cpp
+++ b/modules/plugin/base/src/nsPluginsDirUnix.cpp
@@ -267,17 +267,17 @@ nsPluginFile::nsPluginFile(nsIFile* file
 : mPlugin(file)
 {
 }
 
 nsPluginFile::~nsPluginFile()
 {
 }
 
-nsresult nsPluginFile::LoadPlugin(PRLibrary* &outLibrary)
+nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
 {
     PRLibSpec libSpec;
     libSpec.type = PR_LibSpec_Pathname;
     PRBool exists = PR_FALSE;
     mPlugin->Exists(&exists);
     if (!exists)
         return NS_ERROR_FILE_NOT_FOUND;
 
@@ -300,87 +300,110 @@ nsresult nsPluginFile::LoadPlugin(PRLibr
     // fail to resolve Xt symbols when trying to do a dlopen
     // at runtime.  Explicitly opening Xt/Xext into the global
     // namespace before attempting to load the plug-in seems to
     // work fine.
 
 
 #if defined(SOLARIS) || defined(HPUX)
     // Acrobat/libXm: Lazy resolving might cause crash later (bug 211587)
-    pLibrary = outLibrary = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW);
+    *outLibrary = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW);
+    pLibrary = *outLibrary;
 #else
     // Some dlopen() doesn't recover from a failed PR_LD_NOW (bug 223744)
-    pLibrary = outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
+    *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
+    pLibrary = *outLibrary;
 #endif
     if (!pLibrary) {
         LoadExtraSharedLibs();
         // try reload plugin once more
-        pLibrary = outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
+        *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
+        pLibrary = *outLibrary;
         if (!pLibrary)
             DisplayPR_LoadLibraryErrorMessage(libSpec.value.pathname);
     }
 #else
-    pLibrary = outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
+    *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
+    pLibrary = *outLibrary;
 #endif  // MOZ_WIDGET_GTK2
 
 #ifdef NS_DEBUG
     printf("LoadPlugin() %s returned %lx\n", 
            libSpec.value.pathname, (unsigned long)pLibrary);
 #endif
     
     return NS_OK;
 }
 
-nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info)
+nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary)
 {
+    *outLibrary = nsnull;
+
     info.fVersion = nsnull;
 
-    // Passing NULL for a file path will prevent a call to NP_Initialize.
-    nsCOMPtr<nsIPlugin> plugin;
-    nsresult rv = nsNPAPIPlugin::CreatePlugin(NULL, pLibrary, getter_AddRefs(plugin));
+    // Sadly we have to load the library for this to work.
+    nsresult rv = LoadPlugin(outLibrary);
     if (NS_FAILED(rv))
-      return rv;
+        return rv;
+  
+    const char* (*npGetPluginVersion)() =
+        (const char* (*)()) PR_FindFunctionSymbol(pLibrary, "NP_GetPluginVersion");
+    if (npGetPluginVersion) {
+        info.fVersion = PL_strdup(npGetPluginVersion());
+    }
 
-    if (plugin) {
-        const char* (*npGetPluginVersion)() =
-          (const char* (*)()) PR_FindFunctionSymbol(pLibrary, "NP_GetPluginVersion");
-        if (npGetPluginVersion)
-            info.fVersion = PL_strdup(npGetPluginVersion());
+    const char* (*npGetMIMEDescription)() =
+        (const char* (*)()) PR_FindFunctionSymbol(pLibrary, "NP_GetMIMEDescription");
+    if (!npGetMIMEDescription) {
+        return NS_ERROR_FAILURE;
+    }
 
-        const char *mimedescr = NULL;
-        plugin->GetMIMEDescription(&mimedescr);
-#ifdef NS_DEBUG
-        printf("GetMIMEDescription() returned \"%s\"\n", mimedescr);
-#endif
-        if (NS_FAILED(rv = ParsePluginMimeDescription(mimedescr, info)))
-            return rv;
+    const char* mimedescr = npGetMIMEDescription();
+    if (!mimedescr) {
+        return NS_ERROR_FAILURE;
+    }
+
+    rv = ParsePluginMimeDescription(mimedescr, info);
+    if (NS_FAILED(rv)) {
+        return rv;
+    }
 
-        nsCAutoString path;
-        if (NS_FAILED(rv = mPlugin->GetNativePath(path)))
-            return rv;
-        info.fFullPath = PL_strdup(path.get());
+    nsCAutoString path;
+    if (NS_FAILED(rv = mPlugin->GetNativePath(path)))
+        return rv;
+    info.fFullPath = PL_strdup(path.get());
 
-        nsCAutoString fileName;
-        if (NS_FAILED(rv = mPlugin->GetNativeLeafName(fileName)))
-          return rv;
-        info.fFileName = PL_strdup(fileName.get());
+    nsCAutoString fileName;
+    if (NS_FAILED(rv = mPlugin->GetNativeLeafName(fileName)))
+        return rv;
+    info.fFileName = PL_strdup(fileName.get());
 
-        const char *name = NULL;
-        plugin->GetValue(NPPVpluginNameString, &name);
-        if (name)
-          info.fName = PL_strdup(name);
-        else
-          info.fName = PL_strdup(fileName.get());
+    NP_GetValueFunc npGetValue = (NP_GetValueFunc)PR_FindFunctionSymbol(pLibrary, "NP_GetValue");
+    if (!npGetValue) {
+        return NS_ERROR_FAILURE;
+    }
 
-        const char *description = NULL;
-        plugin->GetValue(NPPVpluginDescriptionString, &description);
-        if (!description)
-            description = "";
+    const char *name = NULL;
+    NPError nperr = npGetValue(NULL, NPPVpluginNameString, &name);
+    if (name) {
+        info.fName = PL_strdup(name);
+    }
+    else {
+        info.fName = PL_strdup(fileName.get());
+    }
+
+    const char *description = NULL;
+    nperr = npGetValue(NULL, NPPVpluginDescriptionString, &description);
+    if (description) {
         info.fDescription = PL_strdup(description);
     }
+    else {
+        info.fDescription = "";
+    }
+
     return NS_OK;
 }
 
 nsresult nsPluginFile::FreePluginInfo(nsPluginInfo& info)
 {
     if (info.fName != nsnull)
         PL_strfree(info.fName);
 
--- a/modules/plugin/base/src/nsPluginsDirWin.cpp
+++ b/modules/plugin/base/src/nsPluginsDirWin.cpp
@@ -254,17 +254,17 @@ nsPluginFile::~nsPluginFile()
 {
   // nada
 }
 
 /**
  * Loads the plugin into memory using NSPR's shared-library loading
  * mechanism. Handles platform differences in loading shared libraries.
  */
-nsresult nsPluginFile::LoadPlugin(PRLibrary* &outLibrary)
+nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
 {
   nsCOMPtr<nsILocalFile> plugin = do_QueryInterface(mPlugin);
 
   if (!plugin)
     return NS_ERROR_NULL_POINTER;
 
 #ifndef WINCE
   nsAutoString pluginFolderPath;
@@ -282,35 +282,37 @@ nsresult nsPluginFile::LoadPlugin(PRLibr
   NS_ASSERTION(dwCheck <= MAX_PATH + 1, "Error in Loading plugin");
 
   if (dwCheck <= MAX_PATH + 1) {
     restoreOrigDir = SetCurrentDirectoryW(pluginFolderPath.get());
     NS_ASSERTION(restoreOrigDir, "Error in Loading plugin");
   }
 #endif
 
-  nsresult rv = plugin->Load(&outLibrary);
+  nsresult rv = plugin->Load(outLibrary);
   if (NS_FAILED(rv))
-      outLibrary = NULL;
+      *outLibrary = NULL;
 
 #ifndef WINCE    
   if (restoreOrigDir) {
     BOOL bCheck = SetCurrentDirectoryW(aOrigDir);
     NS_ASSERTION(bCheck, "Error in Loading plugin");
   }
 #endif
 
   return rv;
 }
 
 /**
  * Obtains all of the information currently available for this plugin.
  */
-nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info)
+nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary)
 {
+  *outLibrary = nsnull;
+
   nsresult rv = NS_OK;
   DWORD zerome, versionsize;
   WCHAR* verbuf = nsnull;
 
   if (!mPlugin)
     return NS_ERROR_NULL_POINTER;
 
   nsAutoString fullPath;