Bug 579516: Patch contains a number of fixes to nsPluginStreamListenerPeer memory management. Also moves storage of the stream array for cache lookups to the plugin instance rather than the instance tag. Also stops adding streams to the cached list that shouldn't be there. r=benwa

This commit is contained in:
Josh Aas 2010-07-17 19:47:29 -04:00
Родитель e084c5fc35
Коммит d9a178b62b
9 изменённых файлов: 75 добавлений и 56 удалений

Просмотреть файл

@ -969,9 +969,7 @@ nsObjectFrame::InstantiatePlugin(nsIPluginHost* aPluginHost,
nsresult rv; nsresult rv;
if (fullPageMode) { /* full-page mode */ if (fullPageMode) { /* full-page mode */
nsCOMPtr<nsIStreamListener> stream; nsCOMPtr<nsIStreamListener> stream;
rv = aPluginHost->InstantiateFullPagePlugin(aMimeType, aURI, rv = aPluginHost->InstantiateFullPagePlugin(aMimeType, aURI, mInstanceOwner, getter_AddRefs(stream));
/* resulting stream listener */ *getter_AddRefs(stream),
mInstanceOwner);
if (NS_SUCCEEDED(rv)) if (NS_SUCCEEDED(rv))
pDoc->SetStreamListener(stream); pDoc->SetStreamListener(stream);
} else { /* embedded mode */ } else { /* embedded mode */

Просмотреть файл

@ -62,10 +62,9 @@ interface nsIChannel;
interface nsIPluginStreamListener; interface nsIPluginStreamListener;
[ptr] native PRLibraryPtr(PRLibrary); [ptr] native PRLibraryPtr(PRLibrary);
[ref] native nsIStreamListenerRef(nsIStreamListener *);
[ptr] native nsPluginNativeWindowPtr(nsPluginNativeWindow); [ptr] native nsPluginNativeWindowPtr(nsPluginNativeWindow);
[scriptable, uuid(D419142E-0571-416B-B797-2A8E6624491D)] [scriptable, uuid(C198DEAA-3F93-482D-A47C-85FF6514FE07)]
interface nsIPluginHost : nsISupports interface nsIPluginHost : nsISupports
{ {
[noscript] void init(); [noscript] void init();
@ -89,8 +88,8 @@ interface nsIPluginHost : nsISupports
[noscript] void instantiateFullPagePlugin(in string aMimeType, [noscript] void instantiateFullPagePlugin(in string aMimeType,
in nsIURI aURI, in nsIURI aURI,
in nsIStreamListenerRef aStreamListener, in nsIPluginInstanceOwner aOwner,
in nsIPluginInstanceOwner aOwner); out nsIStreamListener aStreamListener);
/** /**
* Instantiate an embedded plugin for an existing channel. The caller is * Instantiate an embedded plugin for an existing channel. The caller is

Просмотреть файл

@ -176,10 +176,10 @@ NS_IMETHODIMP nsNPAPIPluginInstance::Stop()
OnPluginDestroy(&mNPP); OnPluginDestroy(&mNPP);
// clean up open streams // clean up open streams
for (unsigned int i = 0; i < mStreamListeners.Length(); i++) { for (unsigned int i = 0; i < mPStreamListeners.Length(); i++) {
mStreamListeners[i]->CleanUpStream(NPRES_USER_BREAK); mPStreamListeners[i]->CleanUpStream(NPRES_USER_BREAK);
} }
mStreamListeners.Clear(); mPStreamListeners.Clear();
NPError error = NPERR_GENERIC_ERROR; NPError error = NPERR_GENERIC_ERROR;
if (mCallbacks->destroy) { if (mCallbacks->destroy) {
@ -266,6 +266,18 @@ nsNPAPIPluginInstance::GetMode(PRInt32 *result)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
nsTArray<nsNPAPIPluginStreamListener*>*
nsNPAPIPluginInstance::PStreamListeners()
{
return &mPStreamListeners;
}
nsTArray<nsPluginStreamListenerPeer*>*
nsNPAPIPluginInstance::BStreamListeners()
{
return &mBStreamListeners;
}
nsresult nsresult
nsNPAPIPluginInstance::InitializePlugin() nsNPAPIPluginInstance::InitializePlugin()
{ {
@ -456,7 +468,7 @@ nsresult nsNPAPIPluginInstance::NewNotifyStream(nsIPluginStreamListener** listen
nsNPAPIPluginStreamListener* stream = new nsNPAPIPluginStreamListener(this, notifyData, aURL); nsNPAPIPluginStreamListener* stream = new nsNPAPIPluginStreamListener(this, notifyData, aURL);
NS_ENSURE_TRUE(stream, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(stream, NS_ERROR_OUT_OF_MEMORY);
mStreamListeners.AppendElement(stream); mPStreamListeners.AppendElement(stream);
stream->SetCallNotify(aCallNotify); // set flag in stream to call URLNotify stream->SetCallNotify(aCallNotify); // set flag in stream to call URLNotify
return stream->QueryInterface(kIPluginStreamListenerIID, (void**)listener); return stream->QueryInterface(kIPluginStreamListenerIID, (void**)listener);

Просмотреть файл

@ -50,7 +50,8 @@
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "mozilla/PluginLibrary.h" #include "mozilla/PluginLibrary.h"
class nsNPAPIPluginStreamListener; class nsPluginStreamListenerPeer; // browser-initiated stream class
class nsNPAPIPluginStreamListener; // plugin-initiated stream class
class nsIPluginInstanceOwner; class nsIPluginInstanceOwner;
class nsNPAPITimer class nsNPAPITimer
@ -126,6 +127,12 @@ public:
void UnscheduleTimer(uint32_t timerID); void UnscheduleTimer(uint32_t timerID);
NPError PopUpContextMenu(NPMenu* menu); NPError PopUpContextMenu(NPMenu* menu);
NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace); NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
// Returns the array of plugin-initiated streams.
nsTArray<nsNPAPIPluginStreamListener*> *PStreamListeners();
// Returns the array of browser-initiated streams.
nsTArray<nsPluginStreamListenerPeer*> *BStreamListeners();
protected: protected:
nsresult InitializePlugin(); nsresult InitializePlugin();
@ -168,9 +175,14 @@ public:
// True while creating the plugin, or calling NPP_SetWindow() on it. // True while creating the plugin, or calling NPP_SetWindow() on it.
PRPackedBool mInPluginInitCall; PRPackedBool mInPluginInitCall;
PluginLibrary* mLibrary; PluginLibrary* mLibrary;
nsTArray<nsNPAPIPluginStreamListener*> mStreamListeners;
private: private:
// array of plugin-initiated stream listeners
nsTArray<nsNPAPIPluginStreamListener*> mPStreamListeners;
// array of browser-initiated stream listeners
nsTArray<nsPluginStreamListenerPeer*> mBStreamListeners;
nsTArray<PopupControlState> mPopupStates; nsTArray<PopupControlState> mPopupStates;
char* mMIMEType; char* mMIMEType;

Просмотреть файл

@ -168,8 +168,9 @@ mResponseHeaderBuf(nsnull)
nsNPAPIPluginStreamListener::~nsNPAPIPluginStreamListener() nsNPAPIPluginStreamListener::~nsNPAPIPluginStreamListener()
{ {
// remove this from the plugin instance's stream list // remove this from the plugin instance's stream list
mInst->mStreamListeners.RemoveElement(this); nsTArray<nsNPAPIPluginStreamListener*> *pStreamListeners = mInst->PStreamListeners();
pStreamListeners->RemoveElement(this);
// For those cases when NewStream is never called, we still may need // For those cases when NewStream is never called, we still may need
// to fire a notification callback. Return network error as fallback // to fire a notification callback. Return network error as fallback
// reason because for other cases, notify should have already been // reason because for other cases, notify should have already been
@ -416,9 +417,10 @@ nsNPAPIPluginStreamListener::PluginInitJSLoadInProgress()
{ {
if (!mInst) if (!mInst)
return PR_FALSE; return PR_FALSE;
for (unsigned int i = 0; i < mInst->mStreamListeners.Length(); i++) { nsTArray<nsNPAPIPluginStreamListener*> *pStreamListeners = mInst->PStreamListeners();
if (mInst->mStreamListeners[i]->mIsPluginInitJSStream) { for (unsigned int i = 0; i < pStreamListeners->Length(); i++) {
if (pStreamListeners->ElementAt(i)->mIsPluginInitJSStream) {
return PR_TRUE; return PR_TRUE;
} }
} }

Просмотреть файл

@ -1127,8 +1127,8 @@ NS_IMETHODIMP nsPluginHost::InstantiateEmbeddedPlugin(const char *aMimeType,
// Called by full-page case // Called by full-page case
NS_IMETHODIMP nsPluginHost::InstantiateFullPagePlugin(const char *aMimeType, NS_IMETHODIMP nsPluginHost::InstantiateFullPagePlugin(const char *aMimeType,
nsIURI* aURI, nsIURI* aURI,
nsIStreamListener *&aStreamListener, nsIPluginInstanceOwner *aOwner,
nsIPluginInstanceOwner *aOwner) nsIStreamListener **aStreamListener)
{ {
#ifdef PLUGIN_LOGGING #ifdef PLUGIN_LOGGING
nsCAutoString urlSpec; nsCAutoString urlSpec;
@ -1147,7 +1147,7 @@ NS_IMETHODIMP nsPluginHost::InstantiateFullPagePlugin(const char *aMimeType,
if (!pluginTag || !pluginTag->mIsJavaPlugin) { if (!pluginTag || !pluginTag->mIsJavaPlugin) {
nsCOMPtr<nsIPluginInstance> instanceCOMPtr; nsCOMPtr<nsIPluginInstance> instanceCOMPtr;
aOwner->GetInstance(getter_AddRefs(instanceCOMPtr)); aOwner->GetInstance(getter_AddRefs(instanceCOMPtr));
NewFullPagePluginStream(aStreamListener, aURI, static_cast<nsNPAPIPluginInstance*>(instanceCOMPtr.get())); NewFullPagePluginStream(aURI, static_cast<nsNPAPIPluginInstance*>(instanceCOMPtr.get()), aStreamListener);
} }
return NS_OK; return NS_OK;
} }
@ -1171,7 +1171,7 @@ NS_IMETHODIMP nsPluginHost::InstantiateFullPagePlugin(const char *aMimeType,
if (window->window) if (window->window)
window->CallSetWindow(instanceCOMPtr); window->CallSetWindow(instanceCOMPtr);
rv = NewFullPagePluginStream(aStreamListener, aURI, instance); rv = NewFullPagePluginStream(aURI, instance, aStreamListener);
// If we've got a native window, the let the plugin know about it. // If we've got a native window, the let the plugin know about it.
if (window->window) if (window->window)
@ -3214,27 +3214,24 @@ nsresult nsPluginHost::NewEmbeddedPluginStream(nsIURI* aURL,
} }
// Called by InstantiateFullPagePlugin() // Called by InstantiateFullPagePlugin()
nsresult nsPluginHost::NewFullPagePluginStream(nsIStreamListener *&aStreamListener, nsresult nsPluginHost::NewFullPagePluginStream(nsIURI* aURI,
nsIURI* aURI, nsNPAPIPluginInstance *aInstance,
nsNPAPIPluginInstance *aInstance) nsIStreamListener **aStreamListener)
{ {
nsPluginStreamListenerPeer *listener = new nsPluginStreamListenerPeer(); NS_ASSERTION(aStreamListener, "Stream listener out param cannot be null");
nsRefPtr<nsPluginStreamListenerPeer> listener = new nsPluginStreamListenerPeer();
if (!listener) if (!listener)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
nsresult rv; nsresult rv = listener->InitializeFullPage(aURI, aInstance);
if (NS_FAILED(rv)) {
return rv;
}
rv = listener->InitializeFullPage(aURI, aInstance); listener.forget(aStreamListener);
aStreamListener = listener; return NS_OK;
NS_ADDREF(listener);
// add peer to list of stream peers for this instance
nsPluginInstanceTag * p = FindInstanceTag(aInstance);
if (p)
p->mStreams.AppendObject(listener);
return rv;
} }
NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject, NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,

Просмотреть файл

@ -192,7 +192,9 @@ private:
NewEmbeddedPluginStream(nsIURI* aURL, nsIPluginInstanceOwner *aOwner, nsNPAPIPluginInstance* aInstance); NewEmbeddedPluginStream(nsIURI* aURL, nsIPluginInstanceOwner *aOwner, nsNPAPIPluginInstance* aInstance);
nsresult nsresult
NewFullPagePluginStream(nsIStreamListener *&aStreamListener, nsIURI* aURI, nsNPAPIPluginInstance *aInstance); NewFullPagePluginStream(nsIURI* aURI,
nsNPAPIPluginInstance *aInstance,
nsIStreamListener **aStreamListener);
// Return an nsPluginTag for this type, if any. If aCheckEnabled is // Return an nsPluginTag for this type, if any. If aCheckEnabled is
// true, only enabled plugins will be returned. // true, only enabled plugins will be returned.

Просмотреть файл

@ -279,6 +279,9 @@ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
mFileCacheOutputStream = nsnull; mFileCacheOutputStream = nsnull;
delete mDataForwardToRequest; delete mDataForwardToRequest;
if (mPluginInstance)
mPluginInstance->BStreamListeners()->RemoveElement(this);
} }
// Called as a result of GetURL and PostURL // Called as a result of GetURL and PostURL
@ -377,16 +380,16 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
nsresult rv = NS_OK; nsresult rv = NS_OK;
PRBool useExistingCacheFile = PR_FALSE; PRBool useExistingCacheFile = PR_FALSE;
nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst()); nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst());
// Look for an existing cache file for the URI.
nsTArray< nsAutoPtr<nsPluginInstanceTag> > *instanceTags = pluginHost->InstanceTagArray(); nsTArray< nsAutoPtr<nsPluginInstanceTag> > *instanceTags = pluginHost->InstanceTagArray();
for (PRUint32 i = 0; i < instanceTags->Length(); i++) { for (PRUint32 i = 0; i < instanceTags->Length(); i++) {
nsPluginInstanceTag *instanceTag = (*instanceTags)[i]; nsPluginInstanceTag *instanceTag = (*instanceTags)[i];
// most recent streams are at the end of list // most recent streams are at the end of list
for (PRInt32 i = instanceTag->mStreams.Count() - 1; i >= 0; --i) { nsTArray<nsPluginStreamListenerPeer*> *bStreamListeners = instanceTag->mInstance->BStreamListeners();
nsPluginStreamListenerPeer *lp = for (PRInt32 i = bStreamListeners->Length() - 1; i >= 0; --i) {
static_cast<nsPluginStreamListenerPeer*>(instanceTag->mStreams[i]); nsPluginStreamListenerPeer *lp = bStreamListeners->ElementAt(i);
if (lp && lp->mLocalCachedFileHolder) { if (lp && lp->mLocalCachedFileHolder) {
useExistingCacheFile = lp->UseExistingPluginCacheFile(this); useExistingCacheFile = lp->UseExistingPluginCacheFile(this);
if (useExistingCacheFile) { if (useExistingCacheFile) {
@ -398,7 +401,8 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
break; break;
} }
} }
// Create a new cache file if one could not be found.
if (!useExistingCacheFile) { if (!useExistingCacheFile) {
nsCOMPtr<nsIFile> pluginTmp; nsCOMPtr<nsIFile> pluginTmp;
rv = nsPluginHost::GetPluginTempDir(getter_AddRefs(pluginTmp)); rv = nsPluginHost::GetPluginTempDir(getter_AddRefs(pluginTmp));
@ -438,17 +442,12 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
return rv; return rv;
// save the file. // save the file.
mLocalCachedFileHolder = new CachedFileHolder(pluginTmp); mLocalCachedFileHolder = new CachedFileHolder(pluginTmp);
} }
// add this listenerPeer to list of stream peers for this instance // add this listenerPeer to list of stream peers for this instance
// it'll delay release of listenerPeer until nsPluginInstanceTag::~nsPluginInstanceTag mPluginInstance->BStreamListeners()->AppendElement(this);
// and the temp file is going to stay alive until then
nsPluginInstanceTag *instanceTag = pluginHost->FindInstanceTag(mPluginInstance);
if (instanceTag)
instanceTag->mStreams.AppendObject(this);
return rv; return rv;
} }
@ -829,7 +828,7 @@ nsPluginStreamListenerPeer::UseExistingPluginCacheFile(nsPluginStreamListenerPee
NS_ENSURE_ARG_POINTER(psi); NS_ENSURE_ARG_POINTER(psi);
if ( psi->mLength == mLength && if (psi->mLength == mLength &&
psi->mModified == mModified && psi->mModified == mModified &&
mStreamComplete && mStreamComplete &&
mURLSpec.Equals(psi->mURLSpec)) mURLSpec.Equals(psi->mURLSpec))

Просмотреть файл

@ -129,9 +129,7 @@ struct nsPluginInstanceTag
char* mURL; char* mURL;
nsRefPtr<nsPluginTag> mPluginTag; nsRefPtr<nsPluginTag> mPluginTag;
nsNPAPIPluginInstance* mInstance; // this must always be valid nsNPAPIPluginInstance* mInstance; // this must always be valid
// Array holding all opened stream listeners for this entry
nsCOMArray<nsIPluginStreamInfo> mStreams;
nsPluginInstanceTag(nsPluginTag* aPluginTag, nsPluginInstanceTag(nsPluginTag* aPluginTag,
nsIPluginInstance* aInstance, nsIPluginInstance* aInstance,
const char * url); const char * url);