Skip to content
Permalink
Browse files
Delay GC triggered NP object destruction to the next runloop cycle
https://bugs.webkit.org/show_bug.cgi?id=66717

Reviewed by Anders Carlsson.

Delay destruction of plugin objects caused by GC until the next
runloop cycle so that they can execute JS in their finalizers.
We do this using a zero delay timer coupled with a queue of
objects to be finalised.

* WebProcess/Plugins/Netscape/JSNPObject.cpp:
(WebKit::JSNPObject::releaseObject):
* WebProcess/Plugins/Netscape/JSNPObject.h:
* WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp:
(WebKit::NPRuntimeObjectMap::NPRuntimeObjectMap):
(WebKit::NPRuntimeObjectMap::invalidate):
(WebKit::NPRuntimeObjectMap::invalidateQueuedObjects):
(WebKit::NPRuntimeObjectMap::addToInvalidationQueue):
(WebKit::NPRuntimeObjectMap::finalize):
* WebProcess/Plugins/Netscape/NPRuntimeObjectMap.h:
* WebProcess/Plugins/Netscape/NPRuntimeUtilities.cpp:
(WebKit::trySafeReleaseNPObject):
* WebProcess/Plugins/Netscape/NPRuntimeUtilities.h:

Canonical link: https://commits.webkit.org/82534@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@93555 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
ojhunt committed Aug 22, 2011
1 parent 45c9933 commit 9bb2611b6f8be6448f9ccff88fd4795996c03957
Showing 7 changed files with 106 additions and 3 deletions.
@@ -1,3 +1,29 @@
2011-08-22 Oliver Hunt <oliver@apple.com>

Delay GC triggered NP object destruction to the next runloop cycle
https://bugs.webkit.org/show_bug.cgi?id=66717

Reviewed by Anders Carlsson.

Delay destruction of plugin objects caused by GC until the next
runloop cycle so that they can execute JS in their finalizers.
We do this using a zero delay timer coupled with a queue of
objects to be finalised.

* WebProcess/Plugins/Netscape/JSNPObject.cpp:
(WebKit::JSNPObject::releaseObject):
* WebProcess/Plugins/Netscape/JSNPObject.h:
* WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp:
(WebKit::NPRuntimeObjectMap::NPRuntimeObjectMap):
(WebKit::NPRuntimeObjectMap::invalidate):
(WebKit::NPRuntimeObjectMap::invalidateQueuedObjects):
(WebKit::NPRuntimeObjectMap::addToInvalidationQueue):
(WebKit::NPRuntimeObjectMap::finalize):
* WebProcess/Plugins/Netscape/NPRuntimeObjectMap.h:
* WebProcess/Plugins/Netscape/NPRuntimeUtilities.cpp:
(WebKit::trySafeReleaseNPObject):
* WebProcess/Plugins/Netscape/NPRuntimeUtilities.h:

2011-08-22 Anders Carlsson <andersca@apple.com>

Move code from PageClientImpl::doneWithKeyEvent to WKView
@@ -77,6 +77,16 @@ void JSNPObject::invalidate()
m_npObject = 0;
}

NPObject* JSNPObject::leakNPObject()
{
ASSERT(m_npObject);
ASSERT_GC_OBJECT_INHERITS(this, &s_info);

NPObject* object = m_npObject;
m_npObject = 0;
return object;
}

JSValue JSNPObject::callMethod(ExecState* exec, NPIdentifier methodName)
{
ASSERT_GC_OBJECT_INHERITS(this, &s_info);
@@ -50,6 +50,9 @@ class JSNPObject : public JSC::JSObjectWithGlobalObject {

void invalidate();

// Used to invalidate an NPObject asynchronously.
NPObject* leakNPObject();

JSC::JSValue callMethod(JSC::ExecState*, NPIdentifier methodName);
JSC::JSValue callObject(JSC::ExecState*);
JSC::JSValue callConstructor(JSC::ExecState*);
@@ -30,6 +30,7 @@
#include "NPJSObject.h"
#include "NPRuntimeUtilities.h"
#include "PluginView.h"
#include "WebProcess.h"
#include <JavaScriptCore/Error.h>
#include <JavaScriptCore/JSLock.h>
#include <JavaScriptCore/SourceCode.h>
@@ -45,6 +46,7 @@ namespace WebKit {

NPRuntimeObjectMap::NPRuntimeObjectMap(PluginView* pluginView)
: m_pluginView(pluginView)
, m_finalizationTimer(WebProcess::shared().runLoop(), this, &NPRuntimeObjectMap::invalidateQueuedObjects)
{
}

@@ -218,9 +220,19 @@ void NPRuntimeObjectMap::invalidate()
ASSERT(m_npJSObjects.isEmpty());

HashMap<NPObject*, JSC::Weak<JSNPObject> >::iterator end = m_jsNPObjects.end();
Vector<Strong<JSNPObject> > objects;
for (HashMap<NPObject*, JSC::Weak<JSNPObject> >::iterator ptr = m_jsNPObjects.begin(); ptr != end; ++ptr)
ptr->second.get()->invalidate();
objects.append(Strong<JSNPObject>(globalObject()->globalData(), ptr->second));
m_jsNPObjects.clear();
for (size_t i = 0; i < objects.size(); ++i)
objects[i]->invalidate();

// Deal with any objects that were scheduled for delayed destruction
if (m_npObjectsToFinalize.isEmpty())
return;
ASSERT(m_finalizationTimer.isActive());
m_finalizationTimer.stop();
invalidateQueuedObjects();
}

JSGlobalObject* NPRuntimeObjectMap::globalObject() const
@@ -265,14 +277,34 @@ void NPRuntimeObjectMap::moveGlobalExceptionToExecState(ExecState* exec)
globalExceptionString() = String();
}

void NPRuntimeObjectMap::invalidateQueuedObjects()
{
ASSERT(m_npObjectsToFinalize.size());
// We deliberately re-request m_npObjectsToFinalize.size() as custom dealloc
// functions may execute JS and so get more objects added to the dealloc queue
for (size_t i = 0; i < m_npObjectsToFinalize.size(); ++i)
deallocateNPObject(m_npObjectsToFinalize[i]);
m_npObjectsToFinalize.clear();
}

void NPRuntimeObjectMap::addToInvalidationQueue(NPObject* npObject)
{
if (trySafeReleaseNPObject(npObject))
return;
if (m_npObjectsToFinalize.isEmpty())
m_finalizationTimer.startOneShot(0);
ASSERT(m_finalizationTimer.isActive());
m_npObjectsToFinalize.append(npObject);
}

void NPRuntimeObjectMap::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
{
HashMap<NPObject*, JSC::Weak<JSNPObject> >::iterator found = m_jsNPObjects.find(static_cast<NPObject*>(context));
ASSERT(found != m_jsNPObjects.end());
ASSERT_UNUSED(handle, asObject(handle.get()) == found->second);

found->second.get()->invalidate();
JSNPObject* object = found->second.get();
m_jsNPObjects.remove(found);
addToInvalidationQueue(object->leakNPObject());
}

} // namespace WebKit
@@ -26,6 +26,9 @@
#ifndef NPJSObjectWrapperMap_h
#define NPJSObjectWrapperMap_h


#include "RunLoop.h"

#include <heap/Weak.h>
#include <wtf/Forward.h>
#include <wtf/HashMap.h>
@@ -87,11 +90,15 @@ class NPRuntimeObjectMap : private JSC::WeakHandleOwner {
private:
// WeakHandleOwner
virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
void addToInvalidationQueue(NPObject*);
void invalidateQueuedObjects();

PluginView* m_pluginView;

HashMap<JSC::JSObject*, NPJSObject*> m_npJSObjects;
HashMap<NPObject*, JSC::Weak<JSNPObject> > m_jsNPObjects;
Vector<NPObject*> m_npObjectsToFinalize;
RunLoop::Timer<NPRuntimeObjectMap> m_finalizationTimer;
};

} // namespace WebKit
@@ -93,6 +93,23 @@ void retainNPObject(NPObject* npObject)
npObject->referenceCount++;
}

bool trySafeReleaseNPObject(NPObject* npObject)
{
ASSERT(npObject);
if (!npObject)
return true;

ASSERT(npObject->referenceCount >= 1);

npObject->referenceCount--;
if (npObject->referenceCount)
return true;
if (npObject->_class->deallocate)
return false;
deallocateNPObject(npObject);
return true;
}

void releaseNPObject(NPObject* npObject)
{
ASSERT(npObject);
@@ -54,6 +54,14 @@ void deallocateNPObject(NPObject*);

void retainNPObject(NPObject*);
void releaseNPObject(NPObject*);

// This function decrements the refcount of the specified object. If the
// refcount reaches 0 it will attempt to destroy the object. If the object has
// a custom deallocate function it will fail and return false, so it will be
// up to the caller to call deallocateNPObject.
// This function is used to implement the delayed finalization of NPObjects
// released during GC.
bool trySafeReleaseNPObject(NPObject*);

void releaseNPVariantValue(NPVariant*);

0 comments on commit 9bb2611

Please sign in to comment.