2011-04-18 Geoffrey Garen <ggaren@apple.com>
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Apr 2011 22:41:06 +0000 (22:41 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Apr 2011 22:41:06 +0000 (22:41 +0000)
        Reviewed by Oliver Hunt.

        Made DOM handle ownership customizable, and customized it for Nodes and NamedAttrMaps
        https://bugs.webkit.org/show_bug.cgi?id=58828

        * WebCore.exp.in: Blah.

        * bindings/js/DOMWrapperWorld.cpp: Moved code related to JSNode ownership
        to JSNodeCustom, where other custom JSNode-related code goes.

        (WebCore::JSDOMWrapperOwner::finalize):
        (WebCore::DOMWrapperWorld::DOMWrapperWorld):
        * bindings/js/DOMWrapperWorld.h:
        (WebCore::JSDOMWrapperOwner::JSDOMWrapperOwner):
        (WebCore::DOMWrapperWorld::defaultWrapperOwner): Renamed DOMObjectHandleOwner
        to JSDOMWrapperOwner, to match the name of JSDOMWrapper.

        * bindings/js/JSArrayBufferViewHelper.h:
        (WebCore::toJSArrayBufferView):
        * bindings/js/JSCSSRuleCustom.cpp:
        (WebCore::toJS):
        * bindings/js/JSCSSValueCustom.cpp:
        (WebCore::toJS):
        * bindings/js/JSCanvasRenderingContextCustom.cpp:
        (WebCore::toJS): Removed "DOMObject" and "Node" from the names of wrapper-
        related functions, since there is no meaningful distinction between the
        two anymore -- they both use the same extensible interface.

        * bindings/js/JSDOMBinding.cpp: Removed some now-unused functions.

        * bindings/js/JSDOMBinding.h:
        (WebCore::getInlineCachedWrapper):
        (WebCore::setInlineCachedWrapper):
        (WebCore::clearInlineCachedWrapper):
        (WebCore::wrapperOwner):
        (WebCore::wrapperContext):
        (WebCore::getCachedWrapper):
        (WebCore::cacheWrapper):
        (WebCore::uncacheWrapper):
        (WebCore::createWrapper):
        (WebCore::wrap): Created a generic, extensible mechanism for creating,
        caching, retrieving, marking, and destroying DOM wrappers. This eliminates
        the difference between DOM object wrappers and DOM node wrappers, and
        lays the groundwork for getting rid of MarkStack::deprecatedAppend usage
        for marking the remainder of our DOM objects.

        * bindings/js/JSDOMWindowCustom.cpp:
        (WebCore::JSDOMWindow::history):
        (WebCore::JSDOMWindow::location):
        * bindings/js/JSDataViewCustom.cpp:
        (WebCore::toJS):
        * bindings/js/JSDocumentCustom.cpp:
        (WebCore::JSDocument::location):
        (WebCore::toJS):
        * bindings/js/JSElementCustom.cpp:
        (WebCore::toJSNewlyCreated):
        * bindings/js/JSEventCustom.cpp:
        (WebCore::toJS):
        * bindings/js/JSHTMLCollectionCustom.cpp:
        (WebCore::toJS):
        * bindings/js/JSImageDataCustom.cpp:
        (WebCore::toJS): Updated for renames mentioned above.

        * bindings/js/JSNamedNodeMapCustom.cpp:
        (WebCore::JSNamedNodeMapOwner::isReachableFromOpaqueRoots):
        (WebCore::JSNamedNodeMapOwner::finalize):
        (WebCore::wrapperOwner):
        (WebCore::wrapperContext):
        (WebCore::JSNamedNodeMap::markChildren):
        (WebCore::toJS): Updated to use our new interface for customizing wrapper
        lifetime management through function overloading without using
        MarkStack::deprecatedAppend.

        * bindings/js/JSNodeCustom.cpp:
        (WebCore::isObservable):
        (WebCore::isReachableFromDOM):
        (WebCore::JSNodeOwner::isReachableFromOpaqueRoots):
        (WebCore::JSNodeOwner::finalize):
        (WebCore::createWrapperInline): Moved node-related code from JSDOMBinding
        to here. Removed special case marking code for JSNamedNodeMap because
        JSNamedNodeMap now knows how to maintain its own lifetime invariants.

        * bindings/js/JSNodeCustom.h:
        (WebCore::wrapperOwner):
        (WebCore::wrapperContext):
        (WebCore::getInlineCachedWrapper):
        (WebCore::setInlineCachedWrapper):
        (WebCore::clearInlineCachedWrapper):
        (WebCore::toJS): Updated to use our new interface for customizing wrapper
        lifetime management through function overloading without using
        MarkStack::deprecatedAppend or special-case code for nodes.

        * bindings/js/JSSVGPathSegCustom.cpp:
        (WebCore::toJS):
        * bindings/js/JSStyleSheetCustom.cpp:
        (WebCore::toJS): Updated for renames mentioned above.

        * bindings/scripts/CodeGeneratorJS.pm: Fixed up newlines. Updated for
        renames mentioned above.

        * dom/NamedNodeMap.idl: NamedNodeMap needs a custom toJS function now
        because it needs to provide a custom WeakHandleOwner at wrapper creation time.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@84194 268f45cc-cd09-0410-ab3c-d52691b4dbfc

24 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebCore/bindings/js/DOMWrapperWorld.cpp
Source/WebCore/bindings/js/DOMWrapperWorld.h
Source/WebCore/bindings/js/JSArrayBufferViewHelper.h
Source/WebCore/bindings/js/JSCSSRuleCustom.cpp
Source/WebCore/bindings/js/JSCSSValueCustom.cpp
Source/WebCore/bindings/js/JSCanvasRenderingContextCustom.cpp
Source/WebCore/bindings/js/JSDOMBinding.cpp
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
Source/WebCore/bindings/js/JSDataViewCustom.cpp
Source/WebCore/bindings/js/JSDocumentCustom.cpp
Source/WebCore/bindings/js/JSElementCustom.cpp
Source/WebCore/bindings/js/JSEventCustom.cpp
Source/WebCore/bindings/js/JSHTMLCollectionCustom.cpp
Source/WebCore/bindings/js/JSImageDataCustom.cpp
Source/WebCore/bindings/js/JSNamedNodeMapCustom.cpp
Source/WebCore/bindings/js/JSNodeCustom.cpp
Source/WebCore/bindings/js/JSNodeCustom.h
Source/WebCore/bindings/js/JSSVGPathSegCustom.cpp
Source/WebCore/bindings/js/JSStyleSheetCustom.cpp
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/dom/NamedNodeMap.idl

index aae902b..4615b55 100644 (file)
@@ -1,3 +1,108 @@
+2011-04-18  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Oliver Hunt.
+
+        Made DOM handle ownership customizable, and customized it for Nodes and NamedAttrMaps
+        https://bugs.webkit.org/show_bug.cgi?id=58828
+
+        * WebCore.exp.in: Blah.
+
+        * bindings/js/DOMWrapperWorld.cpp: Moved code related to JSNode ownership
+        to JSNodeCustom, where other custom JSNode-related code goes.
+
+        (WebCore::JSDOMWrapperOwner::finalize):
+        (WebCore::DOMWrapperWorld::DOMWrapperWorld):
+        * bindings/js/DOMWrapperWorld.h:
+        (WebCore::JSDOMWrapperOwner::JSDOMWrapperOwner):
+        (WebCore::DOMWrapperWorld::defaultWrapperOwner): Renamed DOMObjectHandleOwner
+        to JSDOMWrapperOwner, to match the name of JSDOMWrapper.
+
+        * bindings/js/JSArrayBufferViewHelper.h:
+        (WebCore::toJSArrayBufferView):
+        * bindings/js/JSCSSRuleCustom.cpp:
+        (WebCore::toJS):
+        * bindings/js/JSCSSValueCustom.cpp:
+        (WebCore::toJS):
+        * bindings/js/JSCanvasRenderingContextCustom.cpp:
+        (WebCore::toJS): Removed "DOMObject" and "Node" from the names of wrapper-
+        related functions, since there is no meaningful distinction between the
+        two anymore -- they both use the same extensible interface.
+        
+        * bindings/js/JSDOMBinding.cpp: Removed some now-unused functions.
+
+        * bindings/js/JSDOMBinding.h:
+        (WebCore::getInlineCachedWrapper):
+        (WebCore::setInlineCachedWrapper):
+        (WebCore::clearInlineCachedWrapper):
+        (WebCore::wrapperOwner):
+        (WebCore::wrapperContext):
+        (WebCore::getCachedWrapper):
+        (WebCore::cacheWrapper):
+        (WebCore::uncacheWrapper):
+        (WebCore::createWrapper):
+        (WebCore::wrap): Created a generic, extensible mechanism for creating,
+        caching, retrieving, marking, and destroying DOM wrappers. This eliminates
+        the difference between DOM object wrappers and DOM node wrappers, and
+        lays the groundwork for getting rid of MarkStack::deprecatedAppend usage
+        for marking the remainder of our DOM objects.
+        
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::JSDOMWindow::history):
+        (WebCore::JSDOMWindow::location):
+        * bindings/js/JSDataViewCustom.cpp:
+        (WebCore::toJS):
+        * bindings/js/JSDocumentCustom.cpp:
+        (WebCore::JSDocument::location):
+        (WebCore::toJS):
+        * bindings/js/JSElementCustom.cpp:
+        (WebCore::toJSNewlyCreated):
+        * bindings/js/JSEventCustom.cpp:
+        (WebCore::toJS):
+        * bindings/js/JSHTMLCollectionCustom.cpp:
+        (WebCore::toJS):
+        * bindings/js/JSImageDataCustom.cpp:
+        (WebCore::toJS): Updated for renames mentioned above.
+
+        * bindings/js/JSNamedNodeMapCustom.cpp:
+        (WebCore::JSNamedNodeMapOwner::isReachableFromOpaqueRoots):
+        (WebCore::JSNamedNodeMapOwner::finalize):
+        (WebCore::wrapperOwner):
+        (WebCore::wrapperContext):
+        (WebCore::JSNamedNodeMap::markChildren):
+        (WebCore::toJS): Updated to use our new interface for customizing wrapper
+        lifetime management through function overloading without using
+        MarkStack::deprecatedAppend.
+
+        * bindings/js/JSNodeCustom.cpp:
+        (WebCore::isObservable):
+        (WebCore::isReachableFromDOM):
+        (WebCore::JSNodeOwner::isReachableFromOpaqueRoots):
+        (WebCore::JSNodeOwner::finalize):
+        (WebCore::createWrapperInline): Moved node-related code from JSDOMBinding
+        to here. Removed special case marking code for JSNamedNodeMap because
+        JSNamedNodeMap now knows how to maintain its own lifetime invariants.
+
+        * bindings/js/JSNodeCustom.h:
+        (WebCore::wrapperOwner):
+        (WebCore::wrapperContext):
+        (WebCore::getInlineCachedWrapper):
+        (WebCore::setInlineCachedWrapper):
+        (WebCore::clearInlineCachedWrapper):
+        (WebCore::toJS): Updated to use our new interface for customizing wrapper
+        lifetime management through function overloading without using
+        MarkStack::deprecatedAppend or special-case code for nodes.
+        
+        * bindings/js/JSSVGPathSegCustom.cpp:
+        (WebCore::toJS):
+        * bindings/js/JSStyleSheetCustom.cpp:
+        (WebCore::toJS): Updated for renames mentioned above.
+
+        * bindings/scripts/CodeGeneratorJS.pm: Fixed up newlines. Updated for
+        renames mentioned above.
+
+        * dom/NamedNodeMap.idl: NamedNodeMap needs a custom toJS function now
+        because it needs to provide a custom WeakHandleOwner at wrapper creation time.
+
 2011-04-18  Jessie Berlin  <jberlin@apple.com>
 
         Rubber-stamped by Sam Weinig.
index 99d2038..d8ee526 100644 (file)
@@ -597,7 +597,6 @@ __ZN7WebCore25PluginMainThreadScheduler16unregisterPluginEP4_NPP
 __ZN7WebCore25PluginMainThreadScheduler9schedulerEv
 __ZN7WebCore25addLanguageChangeObserverEPvPFvS0_E
 __ZN7WebCore25contextMenuItemTagOutlineEv
-__ZN7WebCore25getCachedDOMObjectWrapperEPNS_15DOMWrapperWorldEPv
 __ZN7WebCore26CSSMutableStyleDeclarationC1Ev
 __ZN7WebCore26UserTypingGestureIndicator27processingUserTypingGestureEv
 __ZN7WebCore26UserTypingGestureIndicator28focusedElementAtGestureStartEv
index 7f966e7..b52e2ff 100644 (file)
 #include "config.h"
 #include "DOMWrapperWorld.h"
 
-#include "HTMLAudioElement.h"
-#include "HTMLCanvasElement.h"
-#include "HTMLFrameElementBase.h"
-#include "HTMLImageElement.h"
-#include "HTMLLinkElement.h"
-#include "HTMLNames.h"
-#include "HTMLScriptElement.h"
-#include "HTMLStyleElement.h"
 #include "JSDOMWindow.h"
-#include "JSNode.h"
-#include "ProcessingInstruction.h"
-#include "ScriptController.h"
-#include "StyleSheet.h"
-#include "StyledElement.h"
 #include "WebCoreJSClientData.h"
-#include <heap/Weak.h>
 
 using namespace JSC;
 
 namespace WebCore {
 
-using namespace HTMLNames;
-
-static bool isObservable(JSNode* jsNode, Node* node, DOMWrapperWorld* world)
+void JSDOMWrapperOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
 {
-    // Certain conditions implicitly make existence of a JS DOM node wrapper observable
-    // through the DOM, even if no explicit reference to it remains.
-    
-    // The DOM doesn't know how to keep a tree of nodes alive without the root
-    // being explicitly referenced. So, we artificially treat the root of
-    // every tree as observable.
-    // FIXME: Resolve this lifetime issue in the DOM, and remove this inefficiency.
-    if (!node->parentNode())
-        return true;
-
-    // If a node is in the document, and its wrapper has custom properties,
-    // the wrapper is observable because future access to the node through the
-    // DOM must reflect those properties.
-    if (jsNode->hasCustomProperties())
-        return true;
-
-    // If a node is in the document, and has event listeners, its wrapper is
-    // observable because its wrapper is responsible for marking those event listeners.
-    if (node->hasEventListeners())
-        return true;
-
-    // If a node owns another object with a wrapper with custom properties,
-    // the wrapper must be treated as observable, because future access to
-    // those objects through the DOM must reflect those properties.
-    // FIXME: It would be better if this logic could be in the node next to
-    // the custom markChildren functions rather than here.
-    // Note that for some compound objects like stylesheets and CSSStyleDeclarations,
-    // we don't descend to check children for custom properties, and just conservatively
-    // keep the node wrappers protecting them alive.
-    if (node->isElementNode()) {
-        if (NamedNodeMap* attributes = static_cast<Element*>(node)->attributeMap()) {
-            if (JSDOMWrapper* wrapper = world->m_wrappers.get(attributes).get()) {
-                // FIXME: This check seems insufficient, because NamedNodeMap items can have custom properties themselves.
-                // Maybe it would be OK to just keep the wrapper alive, as it is done for CSSOM objects below.
-                if (wrapper->hasCustomProperties())
-                    return true;
-            }
-        }
-        if (node->isStyledElement()) {
-            if (CSSMutableStyleDeclaration* style = static_cast<StyledElement*>(node)->inlineStyleDecl()) {
-                if (world->m_wrappers.get(style))
-                    return true;
-            }
-        }
-        if (static_cast<Element*>(node)->hasTagName(canvasTag)) {
-            if (CanvasRenderingContext* context = static_cast<HTMLCanvasElement*>(node)->renderingContext()) {
-                if (JSDOMWrapper* wrapper = world->m_wrappers.get(context).get()) {
-                    if (wrapper->hasCustomProperties())
-                        return true;
-                }
-            }
-        } else if (static_cast<Element*>(node)->hasTagName(linkTag)) {
-            if (StyleSheet* sheet = static_cast<HTMLLinkElement*>(node)->sheet()) {
-                if (world->m_wrappers.get(sheet))
-                    return true;
-            }
-        } else if (static_cast<Element*>(node)->hasTagName(styleTag)) {
-            if (StyleSheet* sheet = static_cast<HTMLStyleElement*>(node)->sheet()) {
-                if (world->m_wrappers.get(sheet))
-                    return true;
-            }
-        }
-    } else if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
-        if (StyleSheet* sheet = static_cast<ProcessingInstruction*>(node)->sheet()) {
-            if (world->m_wrappers.get(sheet))
-                return true;
-        }
-    }
-
-    return false;
-}
-
-static inline bool isReachableFromDOM(JSNode* jsNode, Node* node, DOMWrapperWorld* world, MarkStack& markStack)
-{
-    if (!node->inDocument()) {
-        // If a wrapper is the last reference to an image or script element
-        // that is loading but not in the document, the wrapper is observable
-        // because it is the only thing keeping the image element alive, and if
-        // the image element is destroyed, its load event will not fire.
-        // FIXME: The DOM should manage this issue without the help of JavaScript wrappers.
-        if (node->hasTagName(imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())
-            return true;
-        if (node->hasTagName(scriptTag) && !static_cast<HTMLScriptElement*>(node)->haveFiredLoadEvent())
-            return true;
-    #if ENABLE(VIDEO)
-        if (node->hasTagName(audioTag) && !static_cast<HTMLAudioElement*>(node)->paused())
-            return true;
-    #endif
-
-        // If a node is firing event listeners, its wrapper is observable because
-        // its wrapper is responsible for marking those event listeners.
-        if (node->isFiringEventListeners())
-            return true;
-    }
-
-    return isObservable(jsNode, node, world) && markStack.containsOpaqueRoot(root(node));
+    JSDOMWrapper* wrapper = static_cast<JSDOMWrapper*>(handle.get().asCell());
+    void* domObject = context;
+    uncacheWrapper(m_world, domObject, wrapper);
 }
 
 DOMWrapperWorld::DOMWrapperWorld(JSC::JSGlobalData* globalData, bool isNormal)
     : m_globalData(globalData)
     , m_isNormal(isNormal)
-    , m_jsNodeHandleOwner(this)
-    , m_domObjectHandleOwner(this)
+    , m_defaultWrapperOwner(this)
 {
     JSGlobalData::ClientData* clientData = m_globalData->clientData;
     ASSERT(clientData);
@@ -182,27 +72,4 @@ DOMWrapperWorld* mainThreadNormalWorld()
     return cachedNormalWorld;
 }
 
-bool JSNodeHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::MarkStack& markStack)
-{
-    JSNode* jsNode = static_cast<JSNode*>(handle.get().asCell());
-    return isReachableFromDOM(jsNode, jsNode->impl(), m_world, markStack);
-}
-
-void JSNodeHandleOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
-{
-    JSNode* jsNode = static_cast<JSNode*>(handle.get().asCell());
-    uncacheDOMNodeWrapper(m_world, static_cast<Node*>(context), jsNode);
-}
-
-bool DOMObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void*, JSC::MarkStack&)
-{
-    return false;
-}
-
-void DOMObjectHandleOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
-{
-    JSDOMWrapper* domObject = static_cast<JSDOMWrapper*>(handle.get().asCell());
-    uncacheDOMObjectWrapper(m_world, context, domObject);
-}
-
 } // namespace WebCore
index 15a37de..cd7c59f 100644 (file)
@@ -23,6 +23,7 @@
 #define DOMWrapperWorld_h
 
 #include "JSDOMGlobalObject.h"
+#include <heap/Weak.h>
 #include <runtime/WeakGCMap.h>
 #include <wtf/Forward.h>
 
@@ -34,32 +35,16 @@ class ScriptController;
 typedef HashMap<void*, JSC::Weak<JSDOMWrapper> > DOMObjectWrapperMap;
 typedef JSC::WeakGCMap<StringImpl*, JSC::JSString> JSStringCache;
 
-class JSNodeHandleOwner : public JSC::WeakHandleOwner {
+class JSDOMWrapperOwner : public JSC::WeakHandleOwner {
 public:
-    JSNodeHandleOwner(DOMWrapperWorld*);
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void*, JSC::MarkStack&);
-    virtual void finalize(JSC::Handle<JSC::Unknown>, void*);
+    JSDOMWrapperOwner(DOMWrapperWorld*);
+    virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 
 private:
     DOMWrapperWorld* m_world;
 };
 
-inline JSNodeHandleOwner::JSNodeHandleOwner(DOMWrapperWorld* world)
-    : m_world(world)
-{
-}
-
-class DOMObjectHandleOwner : public JSC::WeakHandleOwner {
-public:
-    DOMObjectHandleOwner(DOMWrapperWorld*);
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void*, JSC::MarkStack&);
-    virtual void finalize(JSC::Handle<JSC::Unknown>, void*);
-
-private:
-    DOMWrapperWorld* m_world;
-};
-
-inline DOMObjectHandleOwner::DOMObjectHandleOwner(DOMWrapperWorld* world)
+inline JSDOMWrapperOwner::JSDOMWrapperOwner(DOMWrapperWorld* world)
     : m_world(world)
 {
 }
@@ -85,8 +70,7 @@ public:
     bool isNormal() const { return m_isNormal; }
 
     JSC::JSGlobalData* globalData() const { return m_globalData; }
-    JSNodeHandleOwner* jsNodeHandleOwner() { return &m_jsNodeHandleOwner; }
-    DOMObjectHandleOwner* domObjectHandleOwner() { return &m_domObjectHandleOwner; }
+    JSDOMWrapperOwner* defaultWrapperOwner() { return &m_defaultWrapperOwner; }
 
 protected:
     DOMWrapperWorld(JSC::JSGlobalData*, bool isNormal);
@@ -95,8 +79,7 @@ private:
     JSC::JSGlobalData* m_globalData;
     HashSet<ScriptController*> m_scriptControllersWithWindowShells;
     bool m_isNormal;
-    JSNodeHandleOwner m_jsNodeHandleOwner;
-    DOMObjectHandleOwner m_domObjectHandleOwner;
+    JSDOMWrapperOwner m_defaultWrapperOwner;
 };
 
 DOMWrapperWorld* normalWorld(JSC::JSGlobalData&);
index 3386a4d..58aaf19 100644 (file)
@@ -163,11 +163,11 @@ static JSC::JSValue toJSArrayBufferView(JSC::ExecState* exec, JSDOMGlobalObject*
     if (!object)
         return JSC::jsNull();
 
-    if (JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), object))
+    if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), object))
         return wrapper;
 
     exec->heap()->reportExtraMemoryCost(object->byteLength());
-    return createDOMObjectWrapper<JSType>(exec, globalObject, object);
+    return createWrapper<JSType>(exec, globalObject, object);
 }
 
 } // namespace WebCore
index 7e2700d..935ec1a 100644 (file)
@@ -63,7 +63,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, CSSRule* rule)
     if (!rule)
         return jsNull();
 
-    JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), rule);
+    JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), rule);
     if (wrapper)
         return wrapper;
 
index 58fb7d7..b1f8404 100644 (file)
@@ -49,7 +49,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, CSSValue* value)
     if (!value)
         return jsNull();
 
-    JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), value);
+    JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), value);
 
     if (wrapper)
         return wrapper;
index cab7ba3..cd20dc9 100644 (file)
@@ -44,10 +44,10 @@ JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, CanvasR
 
 #if ENABLE(WEBGL)
     if (object->is3d())
-        return getDOMObjectWrapper<JSWebGLRenderingContext>(exec, globalObject, static_cast<WebGLRenderingContext*>(object));
+        return wrap<JSWebGLRenderingContext>(exec, globalObject, static_cast<WebGLRenderingContext*>(object));
 #endif
     ASSERT(object->is2d());
-    return getDOMObjectWrapper<JSCanvasRenderingContext2D>(exec, globalObject, static_cast<CanvasRenderingContext2D*>(object));
+    return wrap<JSCanvasRenderingContext2D>(exec, globalObject, static_cast<CanvasRenderingContext2D*>(object));
 }
 
 } // namespace WebCore
index 302ff7f..5ac07a7 100644 (file)
@@ -44,7 +44,6 @@
 #include "JSEventException.h"
 #include "JSExceptionBase.h"
 #include "JSMainThreadExecState.h"
-#include "JSNode.h"
 #include "JSRangeException.h"
 #include "JSXMLHttpRequestException.h"
 #include "KURL.h"
@@ -135,22 +134,6 @@ const JSC::HashTable* getHashTableForGlobalData(JSGlobalData& globalData, const
     return DOMObjectHashTableMap::mapFor(globalData).get(staticTable);
 }
 
-JSDOMWrapper* getCachedDOMObjectWrapper(DOMWrapperWorld* world, void* objectHandle) 
-{
-    return world->m_wrappers.get(objectHandle).get();
-}
-
-void cacheDOMObjectWrapper(DOMWrapperWorld* world, void* objectHandle, JSDOMWrapper* wrapper) 
-{
-    world->m_wrappers.set(objectHandle, Weak<JSDOMWrapper>(*world->globalData(), wrapper, world->domObjectHandleOwner(), objectHandle));
-}
-
-void uncacheDOMObjectWrapper(DOMWrapperWorld* world, void* objectHandle, JSDOMWrapper* wrapper)
-{
-    ASSERT_UNUSED(wrapper, world->m_wrappers.find(objectHandle)->second.get() == wrapper);
-    world->m_wrappers.remove(objectHandle);
-}
-
 void markActiveObjectsForContext(MarkStack& markStack, JSGlobalData& globalData, ScriptExecutionContext* scriptExecutionContext)
 {
     // If an element has pending activity that may result in event listeners being called
index 9ca3ae4..803429f 100644 (file)
@@ -26,6 +26,7 @@
 #include "JSDOMWrapper.h"
 #include "DOMWrapperWorld.h"
 #include "Document.h"
+#include <heap/Weak.h>
 #include <runtime/Completion.h>
 #include <runtime/Lookup.h>
 #include <wtf/Forward.h>
@@ -111,14 +112,6 @@ namespace WebCore {
             ASSERT(globalObject->scriptExecutionContext()->isDocument());
         }
     };
-
-    JSDOMWrapper* getCachedDOMObjectWrapper(DOMWrapperWorld*, void* objectHandle);
-    void cacheDOMObjectWrapper(DOMWrapperWorld*, void* objectHandle, JSDOMWrapper* wrapper);
-    void uncacheDOMObjectWrapper(DOMWrapperWorld*, void* objectHandle, JSDOMWrapper* wrapper);
-
-    JSNode* getCachedDOMNodeWrapper(DOMWrapperWorld*, Node*);
-    void cacheDOMNodeWrapper(DOMWrapperWorld*, Node*, JSNode* wrapper);
-    void uncacheDOMNodeWrapper(DOMWrapperWorld*, Node*, JSNode* wrapper);
     
     void markActiveObjectsForContext(JSC::MarkStack&, JSC::JSGlobalData&, ScriptExecutionContext*);
     void markDOMObjectWrapper(JSC::MarkStack&, JSC::JSGlobalData& globalData, void* object);
@@ -140,52 +133,70 @@ namespace WebCore {
             return structure;
         return cacheDOMStructure(globalObject, WrapperClass::createStructure(exec->globalData(), WrapperClass::createPrototype(exec, globalObject)), &WrapperClass::s_info);
     }
+
     template<class WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec)
     {
         // FIXME: This function is wrong.  It uses the wrong global object for creating the prototype structure.
         return getDOMStructure<WrapperClass>(exec, deprecatedGlobalObjectForPrototype(exec));
     }
+
     template<class WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
     {
         return static_cast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(exec, static_cast<JSDOMGlobalObject*>(globalObject))->storedPrototype()));
     }
-    #define CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, className, object) createDOMObjectWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
-    template<class WrapperClass, class DOMClass> inline JSDOMWrapper* createDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object)
+
+    // Overload these functions to provide a fast path for wrapper access.
+    inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld*, void*) { return 0; }
+    inline bool setInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMWrapper*) { return false; }
+    inline bool clearInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMWrapper*) { return false; }
+
+    // Overload these functions to provide a custom WeakHandleOwner.
+    inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld* world, void*) { return world->defaultWrapperOwner(); }
+    inline void* wrapperContext(DOMWrapperWorld*, void* domObject) { return domObject; }
+
+    template <typename DOMClass> inline JSDOMWrapper* getCachedWrapper(DOMWrapperWorld* world, DOMClass* domObject)
     {
-        ASSERT(object);
-        ASSERT(!getCachedDOMObjectWrapper(currentWorld(exec), object));
-        // FIXME: new (exec) could use a different globalData than the globalData this wrapper is cached on.
-        WrapperClass* wrapper = new (exec) WrapperClass(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, object);
-        cacheDOMObjectWrapper(currentWorld(exec), object, wrapper);
-        return wrapper;
+        if (JSDOMWrapper* wrapper = getInlineCachedWrapper(world, domObject))
+            return wrapper;
+        return world->m_wrappers.get(domObject).get();
     }
-    template<class WrapperClass, class DOMClass> inline JSC::JSValue getDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object)
+
+    template <typename DOMClass> inline void cacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, JSDOMWrapper* wrapper)
     {
-        if (!object)
-            return JSC::jsNull();
-        if (JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), object))
-            return wrapper;
-        return createDOMObjectWrapper<WrapperClass>(exec, globalObject, object);
+        if (setInlineCachedWrapper(world, domObject, wrapper))
+            return;
+        ASSERT(!world->m_wrappers.contains(domObject));
+        world->m_wrappers.set(domObject, JSC::Weak<JSDOMWrapper>(*world->globalData(), wrapper, wrapperOwner(world, domObject), wrapperContext(world, domObject)));
     }
 
-    #define CREATE_DOM_NODE_WRAPPER(exec, globalObject, className, object) createDOMNodeWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
-    template<class WrapperClass, class DOMClass> inline JSNode* createDOMNodeWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node)
+    template <typename DOMClass> inline void uncacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, JSDOMWrapper* wrapper)
+    {
+        if (clearInlineCachedWrapper(world, domObject, wrapper))
+            return;
+        ASSERT(world->m_wrappers.find(domObject)->second.get() == wrapper);
+        world->m_wrappers.remove(domObject);
+    }
+    
+    #define CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, className, object) createWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
+    #define CREATE_DOM_NODE_WRAPPER(exec, globalObject, className, object) static_cast<JSNode*>(createWrapper<JS##className>(exec, globalObject, static_cast<className*>(object)))
+    template<class WrapperClass, class DOMClass> inline JSDOMWrapper* createWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node)
     {
         ASSERT(node);
-        ASSERT(!getCachedDOMNodeWrapper(currentWorld(exec), node));
+        ASSERT(!getCachedWrapper(currentWorld(exec), node));
         WrapperClass* wrapper = new (exec) WrapperClass(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, node);
         // FIXME: The entire function can be removed, once we fix caching.
         // This function is a one-off hack to make Nodes cache in the right global object.
-        cacheDOMNodeWrapper(currentWorld(exec), node, wrapper);
+        cacheWrapper(currentWorld(exec), node, wrapper);
         return wrapper;
     }
-    template<class WrapperClass, class DOMClass> inline JSC::JSValue getDOMNodeWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node)
+
+    template<class WrapperClass, class DOMClass> inline JSC::JSValue wrap(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* domObject)
     {
-        if (!node)
+        if (!domObject)
             return JSC::jsNull();
-        if (JSC::JSCell* wrapper = getCachedDOMNodeWrapper(currentWorld(exec), node))
+        if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), domObject))
             return wrapper;
-        return createDOMNodeWrapper<WrapperClass>(exec, globalObject, node);
+        return createWrapper<WrapperClass>(exec, globalObject, domObject);
     }
 
     const JSC::HashTable* getHashTableForGlobalData(JSC::JSGlobalData&, const JSC::HashTable* staticTable);
index 3102dcc..4bde9e5 100644 (file)
@@ -441,24 +441,24 @@ JSValue JSDOMWindow::lookupSetter(ExecState* exec, const Identifier& propertyNam
 JSValue JSDOMWindow::history(ExecState* exec) const
 {
     History* history = impl()->history();
-    if (JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), history))
+    if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), history))
         return wrapper;
 
     JSDOMWindow* window = const_cast<JSDOMWindow*>(this);
     JSHistory* jsHistory = new (exec) JSHistory(getDOMStructure<JSHistory>(exec, window), window, history);
-    cacheDOMObjectWrapper(currentWorld(exec), history, jsHistory);
+    cacheWrapper(currentWorld(exec), history, jsHistory);
     return jsHistory;
 }
 
 JSValue JSDOMWindow::location(ExecState* exec) const
 {
     Location* location = impl()->location();
-    if (JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), location))
+    if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), location))
         return wrapper;
 
     JSDOMWindow* window = const_cast<JSDOMWindow*>(this);
     JSLocation* jsLocation = new (exec) JSLocation(getDOMStructure<JSLocation>(exec, window), window, location);
-    cacheDOMObjectWrapper(currentWorld(exec), location, jsLocation);
+    cacheWrapper(currentWorld(exec), location, jsLocation);
     return jsLocation;
 }
 
index eaf57bd..48d56d8 100644 (file)
@@ -44,7 +44,7 @@ enum DataViewAccessType {
 
 JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, DataView* object)
 {
-    return getDOMObjectWrapper<JSDataView>(exec, globalObject, object);
+    return wrap<JSDataView>(exec, globalObject, object);
 }
 
 EncodedJSValue JSC_HOST_CALL JSDataViewConstructor::constructJSDataView(ExecState* exec)
index cf0adf1..df304f2 100644 (file)
@@ -68,11 +68,11 @@ JSValue JSDocument::location(ExecState* exec) const
         return jsNull();
 
     Location* location = frame->domWindow()->location();
-    if (JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), location))
+    if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), location))
         return wrapper;
 
     JSLocation* jsLocation = new (exec) JSLocation(getDOMStructure<JSLocation>(exec, globalObject()), globalObject(), location);
-    cacheDOMObjectWrapper(currentWorld(exec), location, jsLocation);
+    cacheWrapper(currentWorld(exec), location, jsLocation);
     return jsLocation;
 }
 
@@ -100,7 +100,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Document* documen
     if (!document)
         return jsNull();
 
-    JSDOMWrapper* wrapper = getCachedDOMNodeWrapper(currentWorld(exec), document);
+    JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), document);
     if (wrapper)
         return wrapper;
 
index 545fb19..4bedf3a 100644 (file)
@@ -71,7 +71,7 @@ JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, Eleme
     if (!element)
         return jsNull();
 
-    ASSERT(!getCachedDOMNodeWrapper(currentWorld(exec), element));
+    ASSERT(!getCachedWrapper(currentWorld(exec), element));
 
     JSNode* wrapper;        
     if (element->isHTMLElement())
index ace798b..9763b4b 100644 (file)
@@ -121,7 +121,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Event* event)
     if (!event)
         return jsNull();
 
-    JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), event);
+    JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), event);
     if (wrapper)
         return wrapper;
 
index a80586d..622a15a 100644 (file)
@@ -134,7 +134,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, HTMLCollection* c
     if (!collection)
         return jsNull();
 
-    JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), collection);
+    JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), collection);
 
     if (wrapper)
         return wrapper;
index 87df41d..fb955b1 100644 (file)
@@ -41,7 +41,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, ImageData* imageD
     if (!imageData)
         return jsNull();
     
-    JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), imageData);
+    JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), imageData);
     if (wrapper)
         return wrapper;
     
index b3a253a..89ca320 100644 (file)
@@ -35,6 +35,40 @@ using namespace JSC;
 
 namespace WebCore {
 
+class JSNamedNodeMapOwner : public JSC::WeakHandleOwner {
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::MarkStack&);
+    virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
+};
+
+bool JSNamedNodeMapOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, MarkStack& markStack)
+{
+    JSNamedNodeMap* jsNamedNodeMap = static_cast<JSNamedNodeMap*>(handle.get().asCell());
+    if (!jsNamedNodeMap->hasCustomProperties())
+        return false;
+    Element* element = jsNamedNodeMap->impl()->element();
+    if (!element)
+        return false;
+    return markStack.containsOpaqueRoot(root(element));
+}
+
+void JSNamedNodeMapOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
+{
+    JSNamedNodeMap* jsNamedNodeMap = static_cast<JSNamedNodeMap*>(handle.get().asCell());
+    DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context);
+    uncacheWrapper(world, jsNamedNodeMap->impl(), jsNamedNodeMap);
+}
+
+inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld*, NamedNodeMap*)
+{
+    DEFINE_STATIC_LOCAL(JSNamedNodeMapOwner, jsNamedNodeMapOwner, ());
+    return &jsNamedNodeMapOwner;
+}
+
+inline void* wrapperContext(DOMWrapperWorld* world, NamedNodeMap*)
+{
+    return world;
+}
+
 bool JSNamedNodeMap::canGetItemsForName(ExecState*, NamedNodeMap* impl, const Identifier& propertyName)
 {
     return impl->getNamedItem(identifierToString(propertyName));
@@ -50,10 +84,19 @@ void JSNamedNodeMap::markChildren(MarkStack& markStack)
 {
     Base::markChildren(markStack);
 
+    // We need to keep the wrapper for our underlying NamedNodeMap's element
+    // alive because NamedNodeMap and Attr rely on the element for data, and
+    // don't know how to keep it alive correctly.
+    // FIXME: Fix this lifetime issue in the DOM, and remove this.
     Element* element = impl()->element();
     if (!element)
         return;
     markStack.addOpaqueRoot(root(element));
 }
 
+JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, NamedNodeMap* impl)
+{
+    return wrap<JSNamedNodeMap>(exec, globalObject, impl);
+}
+
 } // namespace WebCore
index 268d5bf..d305be7 100644 (file)
 #include "Entity.h"
 #include "EntityReference.h"
 #include "ExceptionCode.h"
+#include "HTMLAudioElement.h"
+#include "HTMLCanvasElement.h"
 #include "HTMLElement.h"
+#include "HTMLFrameElementBase.h"
+#include "HTMLImageElement.h"
+#include "HTMLLinkElement.h"
+#include "HTMLNames.h"
+#include "HTMLScriptElement.h"
+#include "HTMLStyleElement.h"
 #include "JSAttr.h"
 #include "JSCDATASection.h"
 #include "JSComment.h"
@@ -55,6 +63,8 @@
 #include "Notation.h"
 #include "ProcessingInstruction.h"
 #include "RegisteredEventListener.h"
+#include "StyleSheet.h"
+#include "StyledElement.h"
 #include "Text.h"
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefPtr.h>
@@ -68,6 +78,114 @@ using namespace JSC;
 
 namespace WebCore {
 
+using namespace HTMLNames;
+
+static bool isObservable(JSNode* jsNode, Node* node, DOMWrapperWorld* world)
+{
+    // Certain conditions implicitly make existence of a JS DOM node wrapper observable
+    // through the DOM, even if no explicit reference to it remains.
+    
+    // The DOM doesn't know how to keep a tree of nodes alive without the root
+    // being explicitly referenced. So, we artificially treat the root of
+    // every tree as observable.
+    // FIXME: Resolve this lifetime issue in the DOM, and remove this inefficiency.
+    if (!node->parentNode())
+        return true;
+
+    // If a node is in the document, and its wrapper has custom properties,
+    // the wrapper is observable because future access to the node through the
+    // DOM must reflect those properties.
+    if (jsNode->hasCustomProperties())
+        return true;
+
+    // If a node is in the document, and has event listeners, its wrapper is
+    // observable because its wrapper is responsible for marking those event listeners.
+    if (node->hasEventListeners())
+        return true;
+
+    // If a node owns another object with a wrapper with custom properties,
+    // the wrapper must be treated as observable, because future access to
+    // those objects through the DOM must reflect those properties.
+    // FIXME: It would be better if this logic could be in the node next to
+    // the custom markChildren functions rather than here.
+    // Note that for some compound objects like stylesheets and CSSStyleDeclarations,
+    // we don't descend to check children for custom properties, and just conservatively
+    // keep the node wrappers protecting them alive.
+    if (node->isElementNode()) {
+        if (node->isStyledElement()) {
+            if (CSSMutableStyleDeclaration* style = static_cast<StyledElement*>(node)->inlineStyleDecl()) {
+                if (world->m_wrappers.get(style))
+                    return true;
+            }
+        }
+        if (static_cast<Element*>(node)->hasTagName(canvasTag)) {
+            if (CanvasRenderingContext* context = static_cast<HTMLCanvasElement*>(node)->renderingContext()) {
+                if (JSDOMWrapper* wrapper = world->m_wrappers.get(context).get()) {
+                    if (wrapper->hasCustomProperties())
+                        return true;
+                }
+            }
+        } else if (static_cast<Element*>(node)->hasTagName(linkTag)) {
+            if (StyleSheet* sheet = static_cast<HTMLLinkElement*>(node)->sheet()) {
+                if (world->m_wrappers.get(sheet))
+                    return true;
+            }
+        } else if (static_cast<Element*>(node)->hasTagName(styleTag)) {
+            if (StyleSheet* sheet = static_cast<HTMLStyleElement*>(node)->sheet()) {
+                if (world->m_wrappers.get(sheet))
+                    return true;
+            }
+        }
+    } else if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
+        if (StyleSheet* sheet = static_cast<ProcessingInstruction*>(node)->sheet()) {
+            if (world->m_wrappers.get(sheet))
+                return true;
+        }
+    }
+
+    return false;
+}
+
+static inline bool isReachableFromDOM(JSNode* jsNode, Node* node, DOMWrapperWorld* world, MarkStack& markStack)
+{
+    if (!node->inDocument()) {
+        // If a wrapper is the last reference to an image or script element
+        // that is loading but not in the document, the wrapper is observable
+        // because it is the only thing keeping the image element alive, and if
+        // the image element is destroyed, its load event will not fire.
+        // FIXME: The DOM should manage this issue without the help of JavaScript wrappers.
+        if (node->hasTagName(imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())
+            return true;
+        if (node->hasTagName(scriptTag) && !static_cast<HTMLScriptElement*>(node)->haveFiredLoadEvent())
+            return true;
+    #if ENABLE(VIDEO)
+        if (node->hasTagName(audioTag) && !static_cast<HTMLAudioElement*>(node)->paused())
+            return true;
+    #endif
+
+        // If a node is firing event listeners, its wrapper is observable because
+        // its wrapper is responsible for marking those event listeners.
+        if (node->isFiringEventListeners())
+            return true;
+    }
+
+    return isObservable(jsNode, node, world) && markStack.containsOpaqueRoot(root(node));
+}
+
+bool JSNodeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void* context, MarkStack& markStack)
+{
+    JSNode* jsNode = static_cast<JSNode*>(handle.get().asCell());
+    DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context);
+    return isReachableFromDOM(jsNode, jsNode->impl(), world, markStack);
+}
+
+void JSNodeOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
+{
+    JSNode* jsNode = static_cast<JSNode*>(handle.get().asCell());
+    DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context);
+    uncacheWrapper(world, jsNode->impl(), jsNode);
+}
+
 JSValue JSNode::insertBefore(ExecState* exec)
 {
     Node* imp = static_cast<Node*>(impl());
@@ -130,7 +248,7 @@ void JSNode::markChildren(MarkStack& markStack)
 static ALWAYS_INLINE JSValue createWrapperInline(ExecState* exec, JSDOMGlobalObject* globalObject, Node* node)
 {
     ASSERT(node);
-    ASSERT(!getCachedDOMNodeWrapper(currentWorld(exec), node));
+    ASSERT(!getCachedWrapper(currentWorld(exec), node));
     
     JSNode* wrapper;    
     switch (node->nodeType()) {
index dbbb009..cefa3e3 100644 (file)
 
 namespace WebCore {
 
-inline JSNode* getCachedDOMNodeWrapper(DOMWrapperWorld* world, Node* node)
+class JSNodeOwner : public JSC::WeakHandleOwner {
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::MarkStack&);
+    virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
+};
+
+inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld*, Node*)
+{
+    DEFINE_STATIC_LOCAL(JSNodeOwner, jsNodeOwner, ());
+    return &jsNodeOwner;
+}
+
+inline void* wrapperContext(DOMWrapperWorld* world, Node*)
+{
+    return world;
+}
+
+inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld* world, Node* node)
 {
-    if (world->isNormal())
-        return static_cast<JSNode*>(node->wrapper());
-    return static_cast<JSNode*>(getCachedDOMObjectWrapper(world, node));
+    if (!world->isNormal())
+        return 0;
+    return node->wrapper();
 }
 
-inline void cacheDOMNodeWrapper(DOMWrapperWorld* world, Node* node, JSNode* wrapper)
+inline bool setInlineCachedWrapper(DOMWrapperWorld* world, Node* node, JSDOMWrapper* wrapper)
 {
-    ASSERT(wrapper);
-    if (world->isNormal()) {
-        node->setWrapper(*world->globalData(), wrapper, world->jsNodeHandleOwner(), node);
-        return;
-    }
-    cacheDOMObjectWrapper(world, node, wrapper);
+    if (!world->isNormal())
+        return false;
+    ASSERT(!node->wrapper());
+    node->setWrapper(*world->globalData(), wrapper, wrapperOwner(world, node), wrapperContext(world, node));
+    return true;
 }
 
-inline void uncacheDOMNodeWrapper(DOMWrapperWorld* world, Node* node, JSNode* jsNode)
+inline bool clearInlineCachedWrapper(DOMWrapperWorld* world, Node* node, JSDOMWrapper* wrapper)
 {
-    if (world->isNormal()) {
-        node->clearWrapper();
-        return;
-    }
-    uncacheDOMObjectWrapper(world, node, jsNode);
+    if (!world->isNormal())
+        return false;
+    ASSERT_UNUSED(wrapper, node->wrapper() == wrapper);
+    node->clearWrapper();
+    return true;
 }
 
 JSC::JSValue createWrapper(JSC::ExecState*, JSDOMGlobalObject*, Node*);
@@ -64,7 +79,7 @@ inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject,
     if (!node)
         return JSC::jsNull();
 
-    JSNode* wrapper = getCachedDOMNodeWrapper(currentWorld(exec), node);
+    JSNode* wrapper = static_cast<JSNode*>(getCachedWrapper(currentWorld(exec), node));
     if (wrapper)
         return wrapper;
 
index 97d301b..dc5eadd 100644 (file)
@@ -63,7 +63,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, SVGPathSeg* objec
     if (!object)
         return jsNull();
 
-    if (JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), object))
+    if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), object))
         return wrapper;
 
     switch (object->pathSegType()) {
index 39a9fe4..66e5244 100644 (file)
@@ -40,7 +40,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, StyleSheet* style
     if (!styleSheet)
         return jsNull();
 
-    JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), styleSheet);
+    JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), styleSheet);
     if (wrapper)
         return wrapper;
 
index 5a5ddcd..181fd24 100644 (file)
@@ -1304,7 +1304,7 @@ sub GenerateImplementation
         push(@implContent, "static const HashTable* get${className}PrototypeTable(ExecState* exec)\n");
         push(@implContent, "{\n");
         push(@implContent, "    return getHashTableForGlobalData(exec->globalData(), &${className}PrototypeTable);\n");
-        push(@implContent, "}\n");
+        push(@implContent, "}\n\n");
         push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleClassName}Prototype\", &JSC::JSObjectWithGlobalObject::s_info, 0, get${className}PrototypeTable };\n\n");
     } else {
         push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleClassName}Prototype\", &JSC::JSObjectWithGlobalObject::s_info, &${className}PrototypeTable, 0 };\n\n");
@@ -1379,7 +1379,7 @@ sub GenerateImplementation
         push(@implContent, "static const HashTable* get${className}Table(ExecState* exec)\n");
         push(@implContent, "{\n");
         push(@implContent, "    return getHashTableForGlobalData(exec->globalData(), &${className}Table);\n");
-        push(@implContent, "}\n");
+        push(@implContent, "}\n\n");
     }
 
     push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleClassName}\", &" . $parentClassName . "::s_info, ");
@@ -1590,7 +1590,7 @@ sub GenerateImplementation
                     push(@implContent, "    return result;\n");
                 }
 
-                push(@implContent, "}\n");
+                push(@implContent, "}\n\n");
 
                 push(@implContent, "#endif\n") if $attributeConditionalString;
 
@@ -1610,8 +1610,7 @@ sub GenerateImplementation
                 }
 
                 push(@implContent, "    return ${className}::getConstructor(exec, domObject->globalObject());\n");
-                push(@implContent, "}\n");
-                push(@implContent, "\n");
+                push(@implContent, "}\n\n");
             }
         }
 
@@ -1769,7 +1768,7 @@ sub GenerateImplementation
                             }
                         }
                         
-                        push(@implContent, "}\n");
+                        push(@implContent, "}\n\n");
 
                         push(@implContent, "#endif\n") if $attributeConditionalString;
 
@@ -1799,8 +1798,7 @@ sub GenerateImplementation
                 } else {
                     push(@implContent, "    static_cast<$className*>(thisObject)->putDirect(exec->globalData(), Identifier(exec, \"$name\"), value);\n");
                 }
-                push(@implContent, "}\n");
-                push(@implContent, "\n");
+                push(@implContent, "}\n\n");
             }        
         }
     }
@@ -2095,7 +2093,7 @@ sub GenerateImplementation
         } else {
             push(@implContent, "    return toJS(exec, thisObj->globalObject(), static_cast<$implClassName*>(thisObj->impl())->item(index));\n");
         }
-        push(@implContent, "}\n");
+        push(@implContent, "}\n\n");
         if ($interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") {
             $implIncludes{"JSNode.h"} = 1;
             $implIncludes{"Node.h"} = 1;
@@ -2106,7 +2104,7 @@ sub GenerateImplementation
         push(@implContent, "\nJSValue ${className}::getByIndex(ExecState*, unsigned index)\n");
         push(@implContent, "{\n");
         push(@implContent, "    return jsNumber(static_cast<$implClassName*>(impl())->item(index));\n");
-        push(@implContent, "}\n");
+        push(@implContent, "}\n\n");
         if ($interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") {
             $implIncludes{"JSNode.h"} = 1;
             $implIncludes{"Node.h"} = 1;
@@ -2115,17 +2113,17 @@ sub GenerateImplementation
 
     if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateToJS"}) and !$dataNode->extendedAttributes->{"CustomToJS"}) {
         if ($svgPropertyType) {
-            push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* object)\n");
+            push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n");
         } else {
-            push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* object)\n");
+            push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n");
         }
         push(@implContent, "{\n");
         if ($svgPropertyType) {
-            push(@implContent, "    return getDOMObjectWrapper<$className, $implType>(exec, globalObject, object);\n");
+            push(@implContent, "    return wrap<$className, $implType>(exec, globalObject, impl);\n");
         } else {
-            push(@implContent, "    return getDOMObjectWrapper<$className>(exec, globalObject, object);\n");
+            push(@implContent, "    return wrap<$className>(exec, globalObject, impl);\n");
         }
-        push(@implContent, "}\n");
+        push(@implContent, "}\n\n");
     }
 
     if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateNativeConverter"}) and !$dataNode->extendedAttributes->{"CustomNativeConverter"}) {
index 4d36577..3350d2f 100644 (file)
@@ -21,6 +21,7 @@
 module core {
 
     interface [
+        CustomToJS,
         CustomMarkFunction,
         HasIndexGetter,
         HasNameGetter