https://bugs.webkit.org/show_bug.cgi?id=21609
Make MessagePorts protect their peers across heaps
JavaScriptCore:
* JavaScriptCore.exp:
* kjs/JSGlobalObject.cpp:
(JSC::JSGlobalObject::markCrossHeapDependentObjects):
* kjs/JSGlobalObject.h:
* kjs/collector.cpp:
(JSC::Heap::collect):
Before GC sweep phase, a function supplied by global object is now called for all global
objects in the heap, making it possible to implement cross-heap dependencies.
WebCore:
* dom/MessagePort.cpp:
(WebCore::MessagePort::MessagePort):
* dom/MessagePort.h:
(WebCore::MessagePort::setJSWrapperIsKnownToBeInaccessible):
(WebCore::MessagePort::jsWrapperIsKnownToBeInaccessible):
Track objects whose JS wrappers are no longer reachable in MessagePort. Unfortunately, this
means that the implementation object knows about JS bindings - but it is not possible to
access JS wrappers from another heap/thread.
* bindings/js/JSDOMBinding.cpp:
(WebCore::markCrossHeapDependentObjectsForDocument):
* bindings/js/JSDOMBinding.h:
* bindings/js/JSDOMWindowBase.cpp:
(WebCore::JSDOMWindowBase::markCrossHeapDependentObjects):
* bindings/js/JSDOMWindowBase.h:
Implement cross-heap dependency tracking for entangled MessagePorts. If a wrapper object
hasn't been marked normally, it is marked as inaccessible. It is then marked manually,
as long as its entangled port is accessible itself.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@37631
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2008-10-15 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21609
+ Make MessagePorts protect their peers across heaps
+
+ * JavaScriptCore.exp:
+ * kjs/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::markCrossHeapDependentObjects):
+ * kjs/JSGlobalObject.h:
+ * kjs/collector.cpp:
+ (JSC::Heap::collect):
+ Before GC sweep phase, a function supplied by global object is now called for all global
+ objects in the heap, making it possible to implement cross-heap dependencies.
+
2008-10-15 Alexey Proskuryakov <ap@webkit.org>
Reviewed by Darin Adler.
__ZN3JSC14JSGlobalObject16stopTimeoutCheckEv
__ZN3JSC14JSGlobalObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEj
__ZN3JSC14JSGlobalObject17startTimeoutCheckEv
+__ZN3JSC14JSGlobalObject29markCrossHeapDependentObjectsEv
__ZN3JSC14JSGlobalObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueERNS_15PutPropertySlotE
__ZN3JSC14JSGlobalObject4initEPNS_8JSObjectE
__ZN3JSC14JSGlobalObject4markEv
}
}
+void JSGlobalObject::markCrossHeapDependentObjects()
+{
+ // Overridden by subclasses.
+}
+
JSGlobalObject* JSGlobalObject::toGlobalObject(ExecState*) const
{
return const_cast<JSGlobalObject*>(this);
virtual ~JSGlobalObject();
virtual void mark();
+ virtual void markCrossHeapDependentObjects();
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable);
m_globalData->machine->registerFile().markCallFrames(this);
m_globalData->smallStrings.mark();
+ JSGlobalObject* globalObject = m_globalData->head;
+ do {
+ globalObject->markCrossHeapDependentObjects();
+ globalObject = globalObject->next();
+ } while (globalObject != m_globalData->head);
+
JAVASCRIPTCORE_GC_MARKED();
size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
+2008-10-15 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21609
+ Make MessagePorts protect their peers across heaps
+
+ * dom/MessagePort.cpp:
+ (WebCore::MessagePort::MessagePort):
+ * dom/MessagePort.h:
+ (WebCore::MessagePort::setJSWrapperIsKnownToBeInaccessible):
+ (WebCore::MessagePort::jsWrapperIsKnownToBeInaccessible):
+ Track objects whose JS wrappers are no longer reachable in MessagePort. Unfortunately, this
+ means that the implementation object knows about JS bindings - but it is not possible to
+ access JS wrappers from another heap/thread.
+
+ * bindings/js/JSDOMBinding.cpp:
+ (WebCore::markCrossHeapDependentObjectsForDocument):
+ * bindings/js/JSDOMBinding.h:
+ * bindings/js/JSDOMWindowBase.cpp:
+ (WebCore::JSDOMWindowBase::markCrossHeapDependentObjects):
+ * bindings/js/JSDOMWindowBase.h:
+ Implement cross-heap dependency tracking for entangled MessagePorts. If a wrapper object
+ hasn't been marked normally, it is marked as inaccessible. It is then marked manually,
+ as long as its entangled port is accessible itself.
+
2008-10-15 Jon Honeycutt <jhoneycutt@apple.com>
Remove unneeded check of whether a Page defers loading before running it
}
}
+void markCrossHeapDependentObjectsForDocument(JSGlobalData& globalData, Document* document)
+{
+ const HashSet<MessagePort*>& messagePorts = document->messagePorts();
+ HashSet<MessagePort*>::const_iterator portsEnd = messagePorts.end();
+ for (HashSet<MessagePort*>::const_iterator iter = messagePorts.begin(); iter != portsEnd; ++iter) {
+ MessagePort* port = *iter;
+ RefPtr<MessagePort> entangledPort = port->entangledPort();
+ if (entangledPort) {
+ // No wrapper, or wrapper is already marked - no need to examine cross-heap dependencies.
+ DOMObject* wrapper = getCachedDOMObjectWrapper(globalData, port);
+ if (!wrapper || wrapper->marked())
+ continue;
+
+ // If the wrapper hasn't been marked during the mark phase of GC, then the port shouldn't protect its entangled one.
+ // It's important not to call this when there is no wrapper. E.g., if GC is triggered after a MessageChannel is created, but before its ports are used from JS,
+ // irreversibly telling the object that its (not yet existing) wrapper is inaccessible would be wrong. Similarly, ports posted via postMessage() may not
+ // have wrappers until delivered.
+ port->setJSWrapperIsInaccessible();
+
+ // If the port is protected by its entangled one, mark it.
+ // This is an atomic read of a boolean value, no synchronization between threads is required (at least on platforms that guarantee cache coherency).
+ if (!entangledPort->jsWrapperIsInaccessible())
+ wrapper->mark();
+ }
+ }
+}
+
void updateDOMNodeDocument(Node* node, Document* oldDocument, Document* newDocument)
{
ASSERT(oldDocument != newDocument);
void updateDOMNodeDocument(Node*, Document* oldDocument, Document* newDocument);
void markDOMNodesForDocument(Document*);
void markActiveObjectsForDocument(JSC::JSGlobalData&, Document*);
+ void markCrossHeapDependentObjectsForDocument(JSC::JSGlobalData&, Document*);
JSC::StructureID* getCachedDOMStructure(JSC::ExecState*, const JSC::ClassInfo*);
JSC::StructureID* cacheDOMStructure(JSC::ExecState*, PassRefPtr<JSC::StructureID>, const JSC::ClassInfo*);
return toJS(exec, collection.get());
}
+void JSDOMWindowBase::markCrossHeapDependentObjects()
+{
+ Document* document = impl()->document();
+ if (!document)
+ return;
+
+ markCrossHeapDependentObjectsForDocument(*globalData(), document);
+}
+
bool JSDOMWindowBase::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
// Check for child frames by name before built-in properties to
void disconnectFrame();
+ virtual void markCrossHeapDependentObjects();
+
virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);
virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue*, JSC::PutPropertySlot&);
, m_queueIsOpen(false)
, m_document(document)
, m_pendingActivity(0)
+ , m_jsWrapperIsInaccessible(false)
{
document->createdMessagePort(this);
}
#include <wtf/HashMap.h>
#include <wtf/MessageQueue.h>
#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
+#include <wtf/Threading.h>
#include <wtf/Vector.h>
namespace WebCore {
class Frame;
class String;
- class MessagePort : public RefCounted<MessagePort>, public EventTarget {
+ class MessagePort : public ThreadSafeShared<MessagePort>, public EventTarget {
public:
static PassRefPtr<MessagePort> create(Document* document) { return adoptRef(new MessagePort(document)); }
~MessagePort();
typedef HashMap<AtomicStringImpl*, ListenerVector> EventListenersMap;
EventListenersMap& eventListeners() { return m_eventListeners; }
- using RefCounted<MessagePort>::ref;
- using RefCounted<MessagePort>::deref;
+ using ThreadSafeShared<MessagePort>::ref;
+ using ThreadSafeShared<MessagePort>::deref;
bool hasPendingActivity() { return m_pendingActivity; }
void setOnclose(PassRefPtr<EventListener> eventListener) { m_onCloseListener = eventListener; }
EventListener* onclose() const { return m_onCloseListener.get(); }
+ void setJSWrapperIsInaccessible() { m_jsWrapperIsInaccessible = true; }
+ bool jsWrapperIsInaccessible() const { return m_jsWrapperIsInaccessible; }
+
private:
friend class CloseMessagePortTimer;
EventListenersMap m_eventListeners;
unsigned m_pendingActivity;
+ bool m_jsWrapperIsInaccessible;
};
} // namespace WebCore