Diff
Modified: trunk/Source/WebKit2/ChangeLog (93554 => 93555)
--- trunk/Source/WebKit2/ChangeLog 2011-08-22 23:08:36 UTC (rev 93554)
+++ trunk/Source/WebKit2/ChangeLog 2011-08-22 23:08:37 UTC (rev 93555)
@@ -1,3 +1,29 @@
+2011-08-22 Oliver Hunt <[email protected]>
+
+ 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 <[email protected]>
Move code from PageClientImpl::doneWithKeyEvent to WKView
Modified: trunk/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.cpp (93554 => 93555)
--- trunk/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.cpp 2011-08-22 23:08:36 UTC (rev 93554)
+++ trunk/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.cpp 2011-08-22 23:08:37 UTC (rev 93555)
@@ -77,6 +77,16 @@
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);
Modified: trunk/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.h (93554 => 93555)
--- trunk/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.h 2011-08-22 23:08:36 UTC (rev 93554)
+++ trunk/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.h 2011-08-22 23:08:37 UTC (rev 93555)
@@ -50,6 +50,9 @@
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*);
Modified: trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp (93554 => 93555)
--- trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp 2011-08-22 23:08:36 UTC (rev 93554)
+++ trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp 2011-08-22 23:08:37 UTC (rev 93555)
@@ -30,6 +30,7 @@
#include "NPJSObject.h"
#include "NPRuntimeUtilities.h"
#include "PluginView.h"
+#include "WebProcess.h"
#include <_javascript_Core/Error.h>
#include <_javascript_Core/JSLock.h>
#include <_javascript_Core/SourceCode.h>
@@ -45,6 +46,7 @@
NPRuntimeObjectMap::NPRuntimeObjectMap(PluginView* pluginView)
: m_pluginView(pluginView)
+ , m_finalizationTimer(WebProcess::shared().runLoop(), this, &NPRuntimeObjectMap::invalidateQueuedObjects)
{
}
@@ -218,9 +220,19 @@
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 @@
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
Modified: trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.h (93554 => 93555)
--- trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.h 2011-08-22 23:08:36 UTC (rev 93554)
+++ trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.h 2011-08-22 23:08:37 UTC (rev 93555)
@@ -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 @@
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
Modified: trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.cpp (93554 => 93555)
--- trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.cpp 2011-08-22 23:08:36 UTC (rev 93554)
+++ trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.cpp 2011-08-22 23:08:37 UTC (rev 93555)
@@ -93,6 +93,23 @@
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);
Modified: trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.h (93554 => 93555)
--- trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.h 2011-08-22 23:08:36 UTC (rev 93554)
+++ trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.h 2011-08-22 23:08:37 UTC (rev 93555)
@@ -54,6 +54,14 @@
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*);