Changeset 84741 in webkit


Ignore:
Timestamp:
Apr 23, 2011 12:11:38 AM (13 years ago)
Author:
vitalyr@chromium.org
Message:

2011-04-19 Vitaly Repeshko <vitalyr@chromium.org>

Reviewed by Adam Barth.

[V8] Use implicit references for V8 listeners on DOM nodes.
https://bugs.webkit.org/show_bug.cgi?id=58953

Instead of allocating an auxiliary V8 array referencing V8
listener objects associated with a DOM node and using an extra
pointer in every DOM node wrapper, we can register implicit
references between nodes and their listeners during GC. This also
makes V8 bindings more aligned with JSC bindings.

No new tests because this is a refactoring.

  • bindings/scripts/CodeGeneratorV8.pm: Stopped generating the listener cache internal field for DOM nodes.
  • bindings/v8/V8AbstractEventListener.h: Exposed the lister handle to the GC. (WebCore::V8AbstractEventListener::existingListenerObjectPeristentHandle):
  • bindings/v8/V8GCController.cpp: Started using implicit references. (WebCore::GrouperVisitor::visitDOMWrapper):
  • dom/EventTarget.h: Implemented an iterator over all listeners. (WebCore::EventListenerIterator):
Location:
trunk/Source/WebCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r84740 r84741  
     12011-04-19  Vitaly Repeshko  <vitalyr@chromium.org>
     2
     3        Reviewed by Adam Barth.
     4
     5        [V8] Use implicit references for V8 listeners on DOM nodes.
     6        https://bugs.webkit.org/show_bug.cgi?id=58953
     7
     8        Instead of allocating an auxiliary V8 array referencing V8
     9        listener objects associated with a DOM node and using an extra
     10        pointer in every DOM node wrapper, we can register implicit
     11        references between nodes and their listeners during GC. This also
     12        makes V8 bindings more aligned with JSC bindings.
     13
     14        No new tests because this is a refactoring.
     15
     16        * bindings/scripts/CodeGeneratorV8.pm: Stopped generating the
     17        listener cache internal field for DOM nodes.
     18        * bindings/v8/V8AbstractEventListener.h: Exposed the lister handle
     19        to the GC.
     20        (WebCore::V8AbstractEventListener::existingListenerObjectPeristentHandle):
     21        * bindings/v8/V8GCController.cpp: Started using implicit references.
     22        (WebCore::GrouperVisitor::visitDOMWrapper):
     23        * dom/EventTarget.h: Implemented an iterator over all listeners.
     24        (WebCore::EventListenerIterator):
     25
    1262011-04-22  Jon Lee  <jonlee@apple.com>
    227
  • trunk/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm

    r84665 r84741  
    442442    my @customInternalFields = ();
    443443 
    444     # We can't ask whether a parent type has a given extendedAttribute, so special-case Node, AbstractWorker and WorkerContext to include all sub-types.
     444    # We can't ask whether a parent type has a given extendedAttribute, so special-case AbstractWorker and WorkerContext to include all sub-types.
     445    # Event listeners on DOM nodes are explicitly supported in the GC controller.
    445446    # FIXME: SVGElementInstance should probably have the EventTarget extended attribute, but doesn't.
    446     if ($dataNode->extendedAttributes->{"EventTarget"} || IsNodeSubType($dataNode) || IsSubType($dataNode, "AbstractWorker") || IsSubType($dataNode, "WorkerContext")
    447         || $name eq "SVGElementInstance") {
     447    if (!IsNodeSubType($dataNode) &&
     448        ($dataNode->extendedAttributes->{"EventTarget"} ||
     449         IsSubType($dataNode, "AbstractWorker") ||
     450         IsSubType($dataNode, "WorkerContext") ||
     451         $name eq "SVGElementInstance")) {
    448452        push(@customInternalFields, "eventListenerCacheIndex");
    449453    }
     
    9971001            my $implSetterFunctionName = $codeGenerator->WK_ucfirst($attrName);
    9981002            $implIncludes{"V8AbstractEventListener.h"} = 1;
    999             push(@implContentDecls, "    transferHiddenDependency(info.Holder(), imp->$attrName(), value, V8${interfaceName}::eventListenerCacheIndex);\n");
     1003            if (!IsNodeSubType($dataNode)) {
     1004                push(@implContentDecls, "    transferHiddenDependency(info.Holder(), imp->$attrName(), value, V8${interfaceName}::eventListenerCacheIndex);\n");
     1005            }
    10001006            if ($interfaceName eq "WorkerContext" and $attribute->signature->name eq "onerror") {
    10011007                $implIncludes{"V8EventListenerList.h"} = 1;
     
    10681074{
    10691075    my $implClassName = shift;
     1076    my $requiresHiddenDependency = shift;
    10701077    my $functionName = shift;
    10711078    my $lookupType = ($functionName eq "add") ? "OrCreate" : "Only";
     
    10801087    if (listener) {
    10811088        V8${implClassName}::toNative(args.Holder())->${functionName}EventListener(v8ValueToAtomicWebCoreString(args[0]), listener${passRefPtrHandling}, args[2]->BooleanValue());
     1089END
     1090    if ($requiresHiddenDependency) {
     1091        push(@implContentDecls, <<END);
    10821092        ${hiddenDependencyAction}HiddenDependency(args.Holder(), args[1], V8${implClassName}::eventListenerCacheIndex);
     1093END
     1094    }
     1095    push(@implContentDecls, <<END);
    10831096    }
    10841097    return v8::Undefined();
     
    11861199    # so we can generate them as a "special case".
    11871200    if ($name eq "addEventListener") {
    1188         GenerateEventListenerCallback($implClassName, "add");
     1201        GenerateEventListenerCallback($implClassName, !IsNodeSubType($dataNode), "add");
    11891202        return;
    11901203    } elsif ($name eq "removeEventListener") {
    1191         GenerateEventListenerCallback($implClassName, "remove");
     1204        GenerateEventListenerCallback($implClassName, !IsNodeSubType($dataNode), "remove");
    11921205        return;
    11931206    }
  • trunk/Source/WebCore/bindings/v8/V8AbstractEventListener.h

    r62897 r84741  
    8989        }
    9090
     91        // Provides access to the underlying handle for GC. Returned
     92        // value might be a weak handle and so not guaranteed to stay
     93        // alive.
     94        v8::Persistent<v8::Object> existingListenerObjectPersistentHandle()
     95        {
     96            return m_listener;
     97        }
     98
    9199        bool hasExistingListenerObject()
    92100        {
  • trunk/Source/WebCore/bindings/v8/V8GCController.cpp

    r84665 r84741  
    327327    void visitDOMWrapper(DOMDataStore* store, Node* node, v8::Persistent<v8::Object> wrapper)
    328328    {
     329        if (node->hasEventListeners()) {
     330            Vector<v8::Persistent<v8::Value> > listeners;
     331            EventListenerIterator iterator(node);
     332            while (EventListener* listener = iterator.nextListener()) {
     333                if (listener->type() != EventListener::JSEventListenerType)
     334                    continue;
     335                V8AbstractEventListener* v8listener = static_cast<V8AbstractEventListener*>(listener);
     336                if (!v8listener->hasExistingListenerObject())
     337                    continue;
     338                listeners.append(v8listener->existingListenerObjectPersistentHandle());
     339            }
     340            if (!listeners.isEmpty())
     341                v8::V8::AddImplicitReferences(wrapper, listeners.data(), listeners.size());
     342        }
     343
    329344        GroupId groupId = calculateGroupId(node);
    330345        if (!groupId)
  • trunk/Source/WebCore/dom/EventTarget.cpp

    r83261 r84741  
    3636#include "EventException.h"
    3737#include <wtf/StdLibExtras.h>
     38#include <wtf/Vector.h>
    3839
    3940using namespace WTF;
     
    391392}
    392393
     394EventListenerIterator::EventListenerIterator()
     395    : m_index(0)
     396{
     397}
     398
     399EventListenerIterator::EventListenerIterator(EventTarget* target)
     400    : m_index(0)
     401{
     402    EventTargetData* data = target->eventTargetData();
     403    if (!data)
     404        return;
     405    m_mapIterator = data->eventListenerMap.begin();
     406    m_mapEnd = data->eventListenerMap.end();
     407}
     408
     409EventListener* EventListenerIterator::nextListener()
     410{
     411    for (; m_mapIterator != m_mapEnd; ++m_mapIterator) {
     412        EventListenerVector& listeners = *m_mapIterator->second;
     413        if (m_index < listeners.size())
     414            return listeners[m_index++].listener.get();
     415        m_index = 0;
     416    }
     417    return 0;
     418}
     419
    393420} // namespace WebCore
  • trunk/Source/WebCore/dom/EventTarget.h

    r84556 r84741  
    186186       
    187187        void fireEventListeners(Event*, EventTargetData*, EventListenerVector&);
     188
     189        friend class EventListenerIterator;
     190    };
     191
     192    class EventListenerIterator {
     193    public:
     194        EventListenerIterator();
     195
     196        // EventTarget must not be modified while an iterator is active.
     197        EventListenerIterator(EventTarget*);
     198
     199        EventListener* nextListener();
     200
     201    private:
     202        EventListenerMap::iterator m_mapIterator;
     203        EventListenerMap::iterator m_mapEnd;
     204        unsigned m_index;
    188205    };
    189206
Note: See TracChangeset for help on using the changeset viewer.