Bug 641685 - Make plugin object map a singleton in the plugin process (r=bsmedberg)

This patches moves the object map (which tracks the PluginScriptableObjectChild
and PluginInstanceChild for a given NPObject) from the PluginModuleChild to
a global variable. This change prepares the way for having multiple PluginModuleChild
instances in a given plugin process.
This commit is contained in:
Bill McCloskey 2014-10-29 08:04:51 -07:00
parent b51bf9c156
commit 652d9ae8c5
7 changed files with 165 additions and 132 deletions

View File

@ -2393,7 +2393,7 @@ PluginInstanceChild::GetActorForNPObject(NPObject* aObject)
}
PluginScriptableObjectChild* actor =
PluginModuleChild::current()->GetActorForNPObject(aObject);
PluginScriptableObjectChild::GetActorForNPObject(aObject);
if (actor) {
// Plugin-provided object that we've previously wrapped.
return actor;
@ -3729,7 +3729,7 @@ PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
ClearAllSurfaces();
mDeletingHash = new nsTHashtable<DeletingObjectEntry>;
PluginModuleChild::current()->FindNPObjectsForInstance(this);
PluginScriptableObjectChild::NotifyOfInstanceShutdown(this);
mDeletingHash->EnumerateEntries(InvalidateObject, nullptr);
mDeletingHash->EnumerateEntries(DeleteObject, nullptr);

View File

@ -55,7 +55,8 @@ class PluginInstanceChild : public PPluginInstanceChild
{
friend class BrowserStreamChild;
friend class PluginStreamChild;
friend class StreamNotifyChild;
friend class StreamNotifyChild;
friend class PluginScriptableObjectChild;
#ifdef OS_WIN
friend LRESULT CALLBACK PluginWindowProc(HWND hWnd,

View File

@ -732,59 +732,6 @@ PluginModuleChild::GetUserAgent()
return NullableStringGet(mUserAgent);
}
bool
PluginModuleChild::RegisterActorForNPObject(NPObject* aObject,
PluginScriptableObjectChild* aActor)
{
AssertPluginThread();
NS_ASSERTION(aObject && aActor, "Null pointer!");
NPObjectData* d = mObjectMap.GetEntry(aObject);
if (!d) {
NS_ERROR("NPObject not in object table");
return false;
}
d->actor = aActor;
return true;
}
void
PluginModuleChild::UnregisterActorForNPObject(NPObject* aObject)
{
AssertPluginThread();
NS_ASSERTION(aObject, "Null pointer!");
NPObjectData* d = mObjectMap.GetEntry(aObject);
NS_ASSERTION(d, "NPObject not in object table");
if (d) {
d->actor = nullptr;
}
}
PluginScriptableObjectChild*
PluginModuleChild::GetActorForNPObject(NPObject* aObject)
{
AssertPluginThread();
NS_ASSERTION(aObject, "Null pointer!");
NPObjectData* d = mObjectMap.GetEntry(aObject);
if (!d) {
NS_ERROR("Plugin using object not created with NPN_CreateObject?");
return nullptr;
}
return d->actor;
}
#ifdef DEBUG
bool
PluginModuleChild::NPObjectIsRegistered(NPObject* aObject)
{
return !!mObjectMap.GetEntry(aObject);
}
#endif
//-----------------------------------------------------------------------------
// FIXME/cjones: just getting this out of the way for the moment ...
@ -1549,7 +1496,7 @@ _setexception(NPObject* aNPObj,
PluginModuleChild* self = PluginModuleChild::current();
PluginScriptableObjectChild* actor = nullptr;
if (aNPObj) {
actor = self->GetActorForNPObject(aNPObj);
actor = PluginScriptableObjectChild::GetActorForNPObject(aNPObj);
if (!actor) {
NS_ERROR("Failed to get actor!");
return;
@ -2050,10 +1997,7 @@ PluginModuleChild::NPN_CreateObject(NPP aNPP, NPClass* aClass)
NS_LOG_ADDREF(newObject, 1, "NPObject", sizeof(NPObject));
}
NPObjectData* d = static_cast<PluginModuleChild*>(i->Manager())
->mObjectMap.PutEntry(newObject);
NS_ASSERTION(!d->instance, "New NPObject already mapped?");
d->instance = i;
PluginScriptableObjectChild::RegisterObject(newObject, i);
return newObject;
}
@ -2077,15 +2021,15 @@ PluginModuleChild::NPN_ReleaseObject(NPObject* aNPObj)
{
AssertPluginThread();
NPObjectData* d = current()->mObjectMap.GetEntry(aNPObj);
if (!d) {
PluginInstanceChild* instance = PluginScriptableObjectChild::GetInstanceForNPObject(aNPObj);
if (!instance) {
NS_ERROR("Releasing object not in mObjectMap?");
return;
}
DeletingObjectEntry* doe = nullptr;
if (d->instance->mDeletingHash) {
doe = d->instance->mDeletingHash->GetEntry(aNPObj);
if (instance->mDeletingHash) {
doe = instance->mDeletingHash->GetEntry(aNPObj);
if (!doe) {
NS_ERROR("An object for a destroyed instance isn't in the instance deletion hash");
return;
@ -2114,29 +2058,11 @@ PluginModuleChild::DeallocNPObject(NPObject* aNPObj)
child::_memfree(aNPObj);
}
NPObjectData* d = current()->mObjectMap.GetEntry(aNPObj);
if (d->actor)
d->actor->NPObjectDestroyed();
PluginScriptableObjectChild* actor = PluginScriptableObjectChild::GetActorForNPObject(aNPObj);
if (actor)
actor->NPObjectDestroyed();
current()->mObjectMap.RemoveEntry(aNPObj);
}
void
PluginModuleChild::FindNPObjectsForInstance(PluginInstanceChild* instance)
{
NS_ASSERTION(instance->mDeletingHash, "filling null mDeletingHash?");
mObjectMap.EnumerateEntries(CollectForInstance, instance);
}
PLDHashOperator
PluginModuleChild::CollectForInstance(NPObjectData* d, void* userArg)
{
PluginInstanceChild* instance = static_cast<PluginInstanceChild*>(userArg);
if (d->instance == instance) {
NPObject* o = d->GetKey();
instance->mDeletingHash->PutEntry(o);
}
return PL_DHASH_NEXT;
PluginScriptableObjectChild::UnregisterObject(aNPObj);
}
NPIdentifier

View File

@ -157,17 +157,6 @@ public:
static PluginModuleChild* current();
bool RegisterActorForNPObject(NPObject* aObject,
PluginScriptableObjectChild* aActor);
void UnregisterActorForNPObject(NPObject* aObject);
PluginScriptableObjectChild* GetActorForNPObject(NPObject* aObject);
#ifdef DEBUG
bool NPObjectIsRegistered(NPObject* aObject);
#endif
/**
* The child implementation of NPN_CreateObject.
*/
@ -353,26 +342,6 @@ private:
NestedLoopTimer *mNestedLoopTimerObject;
#endif
struct NPObjectData : public nsPtrHashKey<NPObject>
{
explicit NPObjectData(const NPObject* key)
: nsPtrHashKey<NPObject>(key)
, instance(nullptr)
, actor(nullptr)
{ }
// never nullptr
PluginInstanceChild* instance;
// sometimes nullptr (no actor associated with an NPObject)
PluginScriptableObjectChild* actor;
};
/**
* mObjectMap contains all the currently active NPObjects (from NPN_CreateObject until the
* final release/dealloc, whether or not an actor is currently associated with the object.
*/
nsTHashtable<NPObjectData> mObjectMap;
public: // called by PluginInstanceChild
/**
* Dealloc an NPObject after last-release or when the associated instance
@ -384,15 +353,7 @@ public: // called by PluginInstanceChild
return mFunctions.destroy(instance->GetNPP(), 0);
}
/**
* Fill PluginInstanceChild.mDeletingHash with all the remaining NPObjects
* associated with that instance.
*/
void FindNPObjectsForInstance(PluginInstanceChild* instance);
private:
static PLDHashOperator CollectForInstance(NPObjectData* d, void* userArg);
#if defined(OS_WIN)
virtual void EnteredCall() MOZ_OVERRIDE;
virtual void ExitedCall() MOZ_OVERRIDE;

View File

@ -539,7 +539,7 @@ PluginScriptableObjectChild::~PluginScriptableObjectChild()
AssertPluginThread();
if (mObject) {
PluginModuleChild::current()->UnregisterActorForNPObject(mObject);
UnregisterActor(mObject);
if (mObject->_class == GetClass()) {
NS_ASSERTION(mType == Proxy, "Wrong type!");
@ -569,8 +569,8 @@ PluginScriptableObjectChild::InitializeProxy()
return false;
}
if (!PluginModuleChild::current()->RegisterActorForNPObject(object, this)) {
NS_ERROR("RegisterActorForNPObject failed");
if (!RegisterActor(object)) {
NS_ERROR("RegisterActor failed");
return false;
}
@ -594,8 +594,8 @@ PluginScriptableObjectChild::InitializeLocal(NPObject* aObject)
NS_ASSERTION(!mProtectCount, "Should be zero!");
mProtectCount++;
if (!PluginModuleChild::current()->RegisterActorForNPObject(aObject, this)) {
NS_ERROR("RegisterActorForNPObject failed");
if (!RegisterActor(aObject)) {
NS_ERROR("RegisterActor failed");
}
mObject = aObject;
@ -688,7 +688,7 @@ PluginScriptableObjectChild::DropNPObject()
// We think we're about to be deleted, but we could be racing with the other
// process.
PluginModuleChild::current()->UnregisterActorForNPObject(mObject);
UnregisterActor(mObject);
mObject = nullptr;
SendUnprotect();
@ -1181,3 +1181,105 @@ PluginScriptableObjectChild::Evaluate(NPString* aScript,
ConvertToVariant(result, *aResult);
return true;
}
nsTHashtable<PluginScriptableObjectChild::NPObjectData>* PluginScriptableObjectChild::sObjectMap;
bool
PluginScriptableObjectChild::RegisterActor(NPObject* aObject)
{
AssertPluginThread();
MOZ_ASSERT(aObject, "Null pointer!");
NPObjectData* d = sObjectMap->GetEntry(aObject);
if (!d) {
NS_ERROR("NPObject not in object table");
return false;
}
d->actor = this;
return true;
}
void
PluginScriptableObjectChild::UnregisterActor(NPObject* aObject)
{
AssertPluginThread();
MOZ_ASSERT(aObject, "Null pointer!");
NPObjectData* d = sObjectMap->GetEntry(aObject);
MOZ_ASSERT(d, "NPObject not in object table");
if (d) {
d->actor = nullptr;
}
}
/* static */ PluginScriptableObjectChild*
PluginScriptableObjectChild::GetActorForNPObject(NPObject* aObject)
{
AssertPluginThread();
MOZ_ASSERT(aObject, "Null pointer!");
NPObjectData* d = sObjectMap->GetEntry(aObject);
if (!d) {
NS_ERROR("Plugin using object not created with NPN_CreateObject?");
return nullptr;
}
return d->actor;
}
/* static */ void
PluginScriptableObjectChild::RegisterObject(NPObject* aObject, PluginInstanceChild* aInstance)
{
AssertPluginThread();
if (!sObjectMap) {
sObjectMap = new nsTHashtable<PluginScriptableObjectChild::NPObjectData>();
}
NPObjectData* d = sObjectMap->PutEntry(aObject);
MOZ_ASSERT(!d->instance, "New NPObject already mapped?");
d->instance = aInstance;
}
/* static */ void
PluginScriptableObjectChild::UnregisterObject(NPObject* aObject)
{
AssertPluginThread();
sObjectMap->RemoveEntry(aObject);
if (!sObjectMap->Count()) {
delete sObjectMap;
sObjectMap = nullptr;
}
}
/* static */ PluginInstanceChild*
PluginScriptableObjectChild::GetInstanceForNPObject(NPObject* aObject)
{
AssertPluginThread();
NPObjectData* d = sObjectMap->GetEntry(aObject);
if (!d) {
return nullptr;
}
return d->instance;
}
/* static */ PLDHashOperator
PluginScriptableObjectChild::CollectForInstance(NPObjectData* d, void* userArg)
{
PluginInstanceChild* instance = static_cast<PluginInstanceChild*>(userArg);
if (d->instance == instance) {
NPObject* o = d->GetKey();
instance->mDeletingHash->PutEntry(o);
}
return PL_DHASH_NEXT;
}
/* static */ void
PluginScriptableObjectChild::NotifyOfInstanceShutdown(PluginInstanceChild* aInstance)
{
AssertPluginThread();
sObjectMap->EnumerateEntries(CollectForInstance, aInstance);
}

View File

@ -217,6 +217,22 @@ public:
static void ClearIdentifiers();
bool RegisterActor(NPObject* aObject);
void UnregisterActor(NPObject* aObject);
static PluginScriptableObjectChild* GetActorForNPObject(NPObject* aObject);
static void RegisterObject(NPObject* aObject, PluginInstanceChild* aInstance);
static void UnregisterObject(NPObject* aObject);
static PluginInstanceChild* GetInstanceForNPObject(NPObject* aObject);
/**
* Fill PluginInstanceChild.mDeletingHash with all the remaining NPObjects
* associated with that instance.
*/
static void NotifyOfInstanceShutdown(PluginInstanceChild* aInstance);
private:
static NPObject*
ScriptableAllocate(NPP aInstance,
@ -297,6 +313,29 @@ private:
typedef nsDataHashtable<nsCStringHashKey, nsRefPtr<StoredIdentifier>> IdentifierTable;
static IdentifierTable sIdentifiers;
struct NPObjectData : public nsPtrHashKey<NPObject>
{
explicit NPObjectData(const NPObject* key)
: nsPtrHashKey<NPObject>(key),
instance(nullptr),
actor(nullptr)
{ }
// never nullptr
PluginInstanceChild* instance;
// sometimes nullptr (no actor associated with an NPObject)
PluginScriptableObjectChild* actor;
};
static PLDHashOperator CollectForInstance(NPObjectData* d, void* userArg);
/**
* mObjectMap contains all the currently active NPObjects (from NPN_CreateObject until the
* final release/dealloc, whether or not an actor is currently associated with the object.
*/
static nsTHashtable<NPObjectData>* sObjectMap;
};
} /* namespace plugins */

View File

@ -1985,6 +1985,10 @@ scriptableRemoveProperty(NPObject* npobj, NPIdentifier name)
for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
if (name == sPluginPropertyIdentifiers[i]) {
NPN_ReleaseVariantValue(&sPluginPropertyValues[i]);
// Avoid double frees (see test_propertyAndMethod.html, which deletes a
// property that doesn't exist).
VOID_TO_NPVARIANT(sPluginPropertyValues[i]);
return true;
}
}