Changeset 84194 in webkit
- Timestamp:
- Apr 18, 2011 3:41:06 PM (13 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 24 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r84192 r84194 1 2011-04-18 Geoffrey Garen <ggaren@apple.com> 2 3 Reviewed by Oliver Hunt. 4 5 Made DOM handle ownership customizable, and customized it for Nodes and NamedAttrMaps 6 https://bugs.webkit.org/show_bug.cgi?id=58828 7 8 * WebCore.exp.in: Blah. 9 10 * bindings/js/DOMWrapperWorld.cpp: Moved code related to JSNode ownership 11 to JSNodeCustom, where other custom JSNode-related code goes. 12 13 (WebCore::JSDOMWrapperOwner::finalize): 14 (WebCore::DOMWrapperWorld::DOMWrapperWorld): 15 * bindings/js/DOMWrapperWorld.h: 16 (WebCore::JSDOMWrapperOwner::JSDOMWrapperOwner): 17 (WebCore::DOMWrapperWorld::defaultWrapperOwner): Renamed DOMObjectHandleOwner 18 to JSDOMWrapperOwner, to match the name of JSDOMWrapper. 19 20 * bindings/js/JSArrayBufferViewHelper.h: 21 (WebCore::toJSArrayBufferView): 22 * bindings/js/JSCSSRuleCustom.cpp: 23 (WebCore::toJS): 24 * bindings/js/JSCSSValueCustom.cpp: 25 (WebCore::toJS): 26 * bindings/js/JSCanvasRenderingContextCustom.cpp: 27 (WebCore::toJS): Removed "DOMObject" and "Node" from the names of wrapper- 28 related functions, since there is no meaningful distinction between the 29 two anymore -- they both use the same extensible interface. 30 31 * bindings/js/JSDOMBinding.cpp: Removed some now-unused functions. 32 33 * bindings/js/JSDOMBinding.h: 34 (WebCore::getInlineCachedWrapper): 35 (WebCore::setInlineCachedWrapper): 36 (WebCore::clearInlineCachedWrapper): 37 (WebCore::wrapperOwner): 38 (WebCore::wrapperContext): 39 (WebCore::getCachedWrapper): 40 (WebCore::cacheWrapper): 41 (WebCore::uncacheWrapper): 42 (WebCore::createWrapper): 43 (WebCore::wrap): Created a generic, extensible mechanism for creating, 44 caching, retrieving, marking, and destroying DOM wrappers. This eliminates 45 the difference between DOM object wrappers and DOM node wrappers, and 46 lays the groundwork for getting rid of MarkStack::deprecatedAppend usage 47 for marking the remainder of our DOM objects. 48 49 * bindings/js/JSDOMWindowCustom.cpp: 50 (WebCore::JSDOMWindow::history): 51 (WebCore::JSDOMWindow::location): 52 * bindings/js/JSDataViewCustom.cpp: 53 (WebCore::toJS): 54 * bindings/js/JSDocumentCustom.cpp: 55 (WebCore::JSDocument::location): 56 (WebCore::toJS): 57 * bindings/js/JSElementCustom.cpp: 58 (WebCore::toJSNewlyCreated): 59 * bindings/js/JSEventCustom.cpp: 60 (WebCore::toJS): 61 * bindings/js/JSHTMLCollectionCustom.cpp: 62 (WebCore::toJS): 63 * bindings/js/JSImageDataCustom.cpp: 64 (WebCore::toJS): Updated for renames mentioned above. 65 66 * bindings/js/JSNamedNodeMapCustom.cpp: 67 (WebCore::JSNamedNodeMapOwner::isReachableFromOpaqueRoots): 68 (WebCore::JSNamedNodeMapOwner::finalize): 69 (WebCore::wrapperOwner): 70 (WebCore::wrapperContext): 71 (WebCore::JSNamedNodeMap::markChildren): 72 (WebCore::toJS): Updated to use our new interface for customizing wrapper 73 lifetime management through function overloading without using 74 MarkStack::deprecatedAppend. 75 76 * bindings/js/JSNodeCustom.cpp: 77 (WebCore::isObservable): 78 (WebCore::isReachableFromDOM): 79 (WebCore::JSNodeOwner::isReachableFromOpaqueRoots): 80 (WebCore::JSNodeOwner::finalize): 81 (WebCore::createWrapperInline): Moved node-related code from JSDOMBinding 82 to here. Removed special case marking code for JSNamedNodeMap because 83 JSNamedNodeMap now knows how to maintain its own lifetime invariants. 84 85 * bindings/js/JSNodeCustom.h: 86 (WebCore::wrapperOwner): 87 (WebCore::wrapperContext): 88 (WebCore::getInlineCachedWrapper): 89 (WebCore::setInlineCachedWrapper): 90 (WebCore::clearInlineCachedWrapper): 91 (WebCore::toJS): Updated to use our new interface for customizing wrapper 92 lifetime management through function overloading without using 93 MarkStack::deprecatedAppend or special-case code for nodes. 94 95 * bindings/js/JSSVGPathSegCustom.cpp: 96 (WebCore::toJS): 97 * bindings/js/JSStyleSheetCustom.cpp: 98 (WebCore::toJS): Updated for renames mentioned above. 99 100 * bindings/scripts/CodeGeneratorJS.pm: Fixed up newlines. Updated for 101 renames mentioned above. 102 103 * dom/NamedNodeMap.idl: NamedNodeMap needs a custom toJS function now 104 because it needs to provide a custom WeakHandleOwner at wrapper creation time. 105 1 106 2011-04-18 Jessie Berlin <jberlin@apple.com> 2 107 -
trunk/Source/WebCore/WebCore.exp.in
r84120 r84194 598 598 __ZN7WebCore25addLanguageChangeObserverEPvPFvS0_E 599 599 __ZN7WebCore25contextMenuItemTagOutlineEv 600 __ZN7WebCore25getCachedDOMObjectWrapperEPNS_15DOMWrapperWorldEPv601 600 __ZN7WebCore26CSSMutableStyleDeclarationC1Ev 602 601 __ZN7WebCore26UserTypingGestureIndicator27processingUserTypingGestureEv -
trunk/Source/WebCore/bindings/js/DOMWrapperWorld.cpp
r84105 r84194 22 22 #include "DOMWrapperWorld.h" 23 23 24 #include "HTMLAudioElement.h"25 #include "HTMLCanvasElement.h"26 #include "HTMLFrameElementBase.h"27 #include "HTMLImageElement.h"28 #include "HTMLLinkElement.h"29 #include "HTMLNames.h"30 #include "HTMLScriptElement.h"31 #include "HTMLStyleElement.h"32 24 #include "JSDOMWindow.h" 33 #include "JSNode.h"34 #include "ProcessingInstruction.h"35 #include "ScriptController.h"36 #include "StyleSheet.h"37 #include "StyledElement.h"38 25 #include "WebCoreJSClientData.h" 39 #include <heap/Weak.h>40 26 41 27 using namespace JSC; … … 43 29 namespace WebCore { 44 30 45 using namespace HTMLNames; 46 47 static bool isObservable(JSNode* jsNode, Node* node, DOMWrapperWorld* world) 31 void JSDOMWrapperOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context) 48 32 { 49 // Certain conditions implicitly make existence of a JS DOM node wrapper observable 50 // through the DOM, even if no explicit reference to it remains. 51 52 // The DOM doesn't know how to keep a tree of nodes alive without the root 53 // being explicitly referenced. So, we artificially treat the root of 54 // every tree as observable. 55 // FIXME: Resolve this lifetime issue in the DOM, and remove this inefficiency. 56 if (!node->parentNode()) 57 return true; 58 59 // If a node is in the document, and its wrapper has custom properties, 60 // the wrapper is observable because future access to the node through the 61 // DOM must reflect those properties. 62 if (jsNode->hasCustomProperties()) 63 return true; 64 65 // If a node is in the document, and has event listeners, its wrapper is 66 // observable because its wrapper is responsible for marking those event listeners. 67 if (node->hasEventListeners()) 68 return true; 69 70 // If a node owns another object with a wrapper with custom properties, 71 // the wrapper must be treated as observable, because future access to 72 // those objects through the DOM must reflect those properties. 73 // FIXME: It would be better if this logic could be in the node next to 74 // the custom markChildren functions rather than here. 75 // Note that for some compound objects like stylesheets and CSSStyleDeclarations, 76 // we don't descend to check children for custom properties, and just conservatively 77 // keep the node wrappers protecting them alive. 78 if (node->isElementNode()) { 79 if (NamedNodeMap* attributes = static_cast<Element*>(node)->attributeMap()) { 80 if (JSDOMWrapper* wrapper = world->m_wrappers.get(attributes).get()) { 81 // FIXME: This check seems insufficient, because NamedNodeMap items can have custom properties themselves. 82 // Maybe it would be OK to just keep the wrapper alive, as it is done for CSSOM objects below. 83 if (wrapper->hasCustomProperties()) 84 return true; 85 } 86 } 87 if (node->isStyledElement()) { 88 if (CSSMutableStyleDeclaration* style = static_cast<StyledElement*>(node)->inlineStyleDecl()) { 89 if (world->m_wrappers.get(style)) 90 return true; 91 } 92 } 93 if (static_cast<Element*>(node)->hasTagName(canvasTag)) { 94 if (CanvasRenderingContext* context = static_cast<HTMLCanvasElement*>(node)->renderingContext()) { 95 if (JSDOMWrapper* wrapper = world->m_wrappers.get(context).get()) { 96 if (wrapper->hasCustomProperties()) 97 return true; 98 } 99 } 100 } else if (static_cast<Element*>(node)->hasTagName(linkTag)) { 101 if (StyleSheet* sheet = static_cast<HTMLLinkElement*>(node)->sheet()) { 102 if (world->m_wrappers.get(sheet)) 103 return true; 104 } 105 } else if (static_cast<Element*>(node)->hasTagName(styleTag)) { 106 if (StyleSheet* sheet = static_cast<HTMLStyleElement*>(node)->sheet()) { 107 if (world->m_wrappers.get(sheet)) 108 return true; 109 } 110 } 111 } else if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) { 112 if (StyleSheet* sheet = static_cast<ProcessingInstruction*>(node)->sheet()) { 113 if (world->m_wrappers.get(sheet)) 114 return true; 115 } 116 } 117 118 return false; 119 } 120 121 static inline bool isReachableFromDOM(JSNode* jsNode, Node* node, DOMWrapperWorld* world, MarkStack& markStack) 122 { 123 if (!node->inDocument()) { 124 // If a wrapper is the last reference to an image or script element 125 // that is loading but not in the document, the wrapper is observable 126 // because it is the only thing keeping the image element alive, and if 127 // the image element is destroyed, its load event will not fire. 128 // FIXME: The DOM should manage this issue without the help of JavaScript wrappers. 129 if (node->hasTagName(imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent()) 130 return true; 131 if (node->hasTagName(scriptTag) && !static_cast<HTMLScriptElement*>(node)->haveFiredLoadEvent()) 132 return true; 133 #if ENABLE(VIDEO) 134 if (node->hasTagName(audioTag) && !static_cast<HTMLAudioElement*>(node)->paused()) 135 return true; 136 #endif 137 138 // If a node is firing event listeners, its wrapper is observable because 139 // its wrapper is responsible for marking those event listeners. 140 if (node->isFiringEventListeners()) 141 return true; 142 } 143 144 return isObservable(jsNode, node, world) && markStack.containsOpaqueRoot(root(node)); 33 JSDOMWrapper* wrapper = static_cast<JSDOMWrapper*>(handle.get().asCell()); 34 void* domObject = context; 35 uncacheWrapper(m_world, domObject, wrapper); 145 36 } 146 37 … … 148 39 : m_globalData(globalData) 149 40 , m_isNormal(isNormal) 150 , m_jsNodeHandleOwner(this) 151 , m_domObjectHandleOwner(this) 41 , m_defaultWrapperOwner(this) 152 42 { 153 43 JSGlobalData::ClientData* clientData = m_globalData->clientData; … … 183 73 } 184 74 185 bool JSNodeHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::MarkStack& markStack)186 {187 JSNode* jsNode = static_cast<JSNode*>(handle.get().asCell());188 return isReachableFromDOM(jsNode, jsNode->impl(), m_world, markStack);189 }190 191 void JSNodeHandleOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)192 {193 JSNode* jsNode = static_cast<JSNode*>(handle.get().asCell());194 uncacheDOMNodeWrapper(m_world, static_cast<Node*>(context), jsNode);195 }196 197 bool DOMObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void*, JSC::MarkStack&)198 {199 return false;200 }201 202 void DOMObjectHandleOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)203 {204 JSDOMWrapper* domObject = static_cast<JSDOMWrapper*>(handle.get().asCell());205 uncacheDOMObjectWrapper(m_world, context, domObject);206 }207 208 75 } // namespace WebCore -
trunk/Source/WebCore/bindings/js/DOMWrapperWorld.h
r84105 r84194 24 24 25 25 #include "JSDOMGlobalObject.h" 26 #include <heap/Weak.h> 26 27 #include <runtime/WeakGCMap.h> 27 28 #include <wtf/Forward.h> … … 35 36 typedef JSC::WeakGCMap<StringImpl*, JSC::JSString> JSStringCache; 36 37 37 class JS NodeHandleOwner : public JSC::WeakHandleOwner {38 class JSDOMWrapperOwner : public JSC::WeakHandleOwner { 38 39 public: 39 JSNodeHandleOwner(DOMWrapperWorld*); 40 virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void*, JSC::MarkStack&); 41 virtual void finalize(JSC::Handle<JSC::Unknown>, void*); 40 JSDOMWrapperOwner(DOMWrapperWorld*); 41 virtual void finalize(JSC::Handle<JSC::Unknown>, void* context); 42 42 43 43 private: … … 45 45 }; 46 46 47 inline JSNodeHandleOwner::JSNodeHandleOwner(DOMWrapperWorld* world) 48 : m_world(world) 49 { 50 } 51 52 class DOMObjectHandleOwner : public JSC::WeakHandleOwner { 53 public: 54 DOMObjectHandleOwner(DOMWrapperWorld*); 55 virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void*, JSC::MarkStack&); 56 virtual void finalize(JSC::Handle<JSC::Unknown>, void*); 57 58 private: 59 DOMWrapperWorld* m_world; 60 }; 61 62 inline DOMObjectHandleOwner::DOMObjectHandleOwner(DOMWrapperWorld* world) 47 inline JSDOMWrapperOwner::JSDOMWrapperOwner(DOMWrapperWorld* world) 63 48 : m_world(world) 64 49 { … … 86 71 87 72 JSC::JSGlobalData* globalData() const { return m_globalData; } 88 JSNodeHandleOwner* jsNodeHandleOwner() { return &m_jsNodeHandleOwner; } 89 DOMObjectHandleOwner* domObjectHandleOwner() { return &m_domObjectHandleOwner; } 73 JSDOMWrapperOwner* defaultWrapperOwner() { return &m_defaultWrapperOwner; } 90 74 91 75 protected: … … 96 80 HashSet<ScriptController*> m_scriptControllersWithWindowShells; 97 81 bool m_isNormal; 98 JSNodeHandleOwner m_jsNodeHandleOwner; 99 DOMObjectHandleOwner m_domObjectHandleOwner; 82 JSDOMWrapperOwner m_defaultWrapperOwner; 100 83 }; 101 84 -
trunk/Source/WebCore/bindings/js/JSArrayBufferViewHelper.h
r84105 r84194 164 164 return JSC::jsNull(); 165 165 166 if (JSDOMWrapper* wrapper = getCached DOMObjectWrapper(currentWorld(exec), object))166 if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), object)) 167 167 return wrapper; 168 168 169 169 exec->heap()->reportExtraMemoryCost(object->byteLength()); 170 return create DOMObjectWrapper<JSType>(exec, globalObject, object);170 return createWrapper<JSType>(exec, globalObject, object); 171 171 } 172 172 -
trunk/Source/WebCore/bindings/js/JSCSSRuleCustom.cpp
r84105 r84194 64 64 return jsNull(); 65 65 66 JSDOMWrapper* wrapper = getCached DOMObjectWrapper(currentWorld(exec), rule);66 JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), rule); 67 67 if (wrapper) 68 68 return wrapper; -
trunk/Source/WebCore/bindings/js/JSCSSValueCustom.cpp
r84105 r84194 50 50 return jsNull(); 51 51 52 JSDOMWrapper* wrapper = getCached DOMObjectWrapper(currentWorld(exec), value);52 JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), value); 53 53 54 54 if (wrapper) -
trunk/Source/WebCore/bindings/js/JSCanvasRenderingContextCustom.cpp
r76600 r84194 45 45 #if ENABLE(WEBGL) 46 46 if (object->is3d()) 47 return getDOMObjectWrapper<JSWebGLRenderingContext>(exec, globalObject, static_cast<WebGLRenderingContext*>(object));47 return wrap<JSWebGLRenderingContext>(exec, globalObject, static_cast<WebGLRenderingContext*>(object)); 48 48 #endif 49 49 ASSERT(object->is2d()); 50 return getDOMObjectWrapper<JSCanvasRenderingContext2D>(exec, globalObject, static_cast<CanvasRenderingContext2D*>(object));50 return wrap<JSCanvasRenderingContext2D>(exec, globalObject, static_cast<CanvasRenderingContext2D*>(object)); 51 51 } 52 52 -
trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp
r84105 r84194 45 45 #include "JSExceptionBase.h" 46 46 #include "JSMainThreadExecState.h" 47 #include "JSNode.h"48 47 #include "JSRangeException.h" 49 48 #include "JSXMLHttpRequestException.h" … … 136 135 } 137 136 138 JSDOMWrapper* getCachedDOMObjectWrapper(DOMWrapperWorld* world, void* objectHandle)139 {140 return world->m_wrappers.get(objectHandle).get();141 }142 143 void cacheDOMObjectWrapper(DOMWrapperWorld* world, void* objectHandle, JSDOMWrapper* wrapper)144 {145 world->m_wrappers.set(objectHandle, Weak<JSDOMWrapper>(*world->globalData(), wrapper, world->domObjectHandleOwner(), objectHandle));146 }147 148 void uncacheDOMObjectWrapper(DOMWrapperWorld* world, void* objectHandle, JSDOMWrapper* wrapper)149 {150 ASSERT_UNUSED(wrapper, world->m_wrappers.find(objectHandle)->second.get() == wrapper);151 world->m_wrappers.remove(objectHandle);152 }153 154 137 void markActiveObjectsForContext(MarkStack& markStack, JSGlobalData& globalData, ScriptExecutionContext* scriptExecutionContext) 155 138 { -
trunk/Source/WebCore/bindings/js/JSDOMBinding.h
r84105 r84194 27 27 #include "DOMWrapperWorld.h" 28 28 #include "Document.h" 29 #include <heap/Weak.h> 29 30 #include <runtime/Completion.h> 30 31 #include <runtime/Lookup.h> … … 112 113 } 113 114 }; 114 115 JSDOMWrapper* getCachedDOMObjectWrapper(DOMWrapperWorld*, void* objectHandle);116 void cacheDOMObjectWrapper(DOMWrapperWorld*, void* objectHandle, JSDOMWrapper* wrapper);117 void uncacheDOMObjectWrapper(DOMWrapperWorld*, void* objectHandle, JSDOMWrapper* wrapper);118 119 JSNode* getCachedDOMNodeWrapper(DOMWrapperWorld*, Node*);120 void cacheDOMNodeWrapper(DOMWrapperWorld*, Node*, JSNode* wrapper);121 void uncacheDOMNodeWrapper(DOMWrapperWorld*, Node*, JSNode* wrapper);122 115 123 116 void markActiveObjectsForContext(JSC::MarkStack&, JSC::JSGlobalData&, ScriptExecutionContext*); … … 141 134 return cacheDOMStructure(globalObject, WrapperClass::createStructure(exec->globalData(), WrapperClass::createPrototype(exec, globalObject)), &WrapperClass::s_info); 142 135 } 136 143 137 template<class WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec) 144 138 { … … 146 140 return getDOMStructure<WrapperClass>(exec, deprecatedGlobalObjectForPrototype(exec)); 147 141 } 142 148 143 template<class WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject) 149 144 { 150 145 return static_cast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(exec, static_cast<JSDOMGlobalObject*>(globalObject))->storedPrototype())); 151 146 } 152 #define CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, className, object) createDOMObjectWrapper<JS##className>(exec, globalObject, static_cast<className*>(object)) 153 template<class WrapperClass, class DOMClass> inline JSDOMWrapper* createDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object) 154 { 155 ASSERT(object); 156 ASSERT(!getCachedDOMObjectWrapper(currentWorld(exec), object)); 157 // FIXME: new (exec) could use a different globalData than the globalData this wrapper is cached on. 158 WrapperClass* wrapper = new (exec) WrapperClass(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, object); 159 cacheDOMObjectWrapper(currentWorld(exec), object, wrapper); 160 return wrapper; 161 } 162 template<class WrapperClass, class DOMClass> inline JSC::JSValue getDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object) 163 { 164 if (!object) 165 return JSC::jsNull(); 166 if (JSDOMWrapper* wrapper = getCachedDOMObjectWrapper(currentWorld(exec), object)) 147 148 // Overload these functions to provide a fast path for wrapper access. 149 inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld*, void*) { return 0; } 150 inline bool setInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMWrapper*) { return false; } 151 inline bool clearInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMWrapper*) { return false; } 152 153 // Overload these functions to provide a custom WeakHandleOwner. 154 inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld* world, void*) { return world->defaultWrapperOwner(); } 155 inline void* wrapperContext(DOMWrapperWorld*, void* domObject) { return domObject; } 156 157 template <typename DOMClass> inline JSDOMWrapper* getCachedWrapper(DOMWrapperWorld* world, DOMClass* domObject) 158 { 159 if (JSDOMWrapper* wrapper = getInlineCachedWrapper(world, domObject)) 167 160 return wrapper; 168 return createDOMObjectWrapper<WrapperClass>(exec, globalObject, object); 169 } 170 171 #define CREATE_DOM_NODE_WRAPPER(exec, globalObject, className, object) createDOMNodeWrapper<JS##className>(exec, globalObject, static_cast<className*>(object)) 172 template<class WrapperClass, class DOMClass> inline JSNode* createDOMNodeWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node) 161 return world->m_wrappers.get(domObject).get(); 162 } 163 164 template <typename DOMClass> inline void cacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, JSDOMWrapper* wrapper) 165 { 166 if (setInlineCachedWrapper(world, domObject, wrapper)) 167 return; 168 ASSERT(!world->m_wrappers.contains(domObject)); 169 world->m_wrappers.set(domObject, JSC::Weak<JSDOMWrapper>(*world->globalData(), wrapper, wrapperOwner(world, domObject), wrapperContext(world, domObject))); 170 } 171 172 template <typename DOMClass> inline void uncacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, JSDOMWrapper* wrapper) 173 { 174 if (clearInlineCachedWrapper(world, domObject, wrapper)) 175 return; 176 ASSERT(world->m_wrappers.find(domObject)->second.get() == wrapper); 177 world->m_wrappers.remove(domObject); 178 } 179 180 #define CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, className, object) createWrapper<JS##className>(exec, globalObject, static_cast<className*>(object)) 181 #define CREATE_DOM_NODE_WRAPPER(exec, globalObject, className, object) static_cast<JSNode*>(createWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))) 182 template<class WrapperClass, class DOMClass> inline JSDOMWrapper* createWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node) 173 183 { 174 184 ASSERT(node); 175 ASSERT(!getCached DOMNodeWrapper(currentWorld(exec), node));185 ASSERT(!getCachedWrapper(currentWorld(exec), node)); 176 186 WrapperClass* wrapper = new (exec) WrapperClass(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, node); 177 187 // FIXME: The entire function can be removed, once we fix caching. 178 188 // This function is a one-off hack to make Nodes cache in the right global object. 179 cache DOMNodeWrapper(currentWorld(exec), node, wrapper);189 cacheWrapper(currentWorld(exec), node, wrapper); 180 190 return wrapper; 181 191 } 182 template<class WrapperClass, class DOMClass> inline JSC::JSValue getDOMNodeWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node) 183 { 184 if (!node) 192 193 template<class WrapperClass, class DOMClass> inline JSC::JSValue wrap(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* domObject) 194 { 195 if (!domObject) 185 196 return JSC::jsNull(); 186 if (JS C::JSCell* wrapper = getCachedDOMNodeWrapper(currentWorld(exec), node))197 if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), domObject)) 187 198 return wrapper; 188 return create DOMNodeWrapper<WrapperClass>(exec, globalObject, node);199 return createWrapper<WrapperClass>(exec, globalObject, domObject); 189 200 } 190 201 -
trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
r84105 r84194 442 442 { 443 443 History* history = impl()->history(); 444 if (JSDOMWrapper* wrapper = getCached DOMObjectWrapper(currentWorld(exec), history))444 if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), history)) 445 445 return wrapper; 446 446 447 447 JSDOMWindow* window = const_cast<JSDOMWindow*>(this); 448 448 JSHistory* jsHistory = new (exec) JSHistory(getDOMStructure<JSHistory>(exec, window), window, history); 449 cache DOMObjectWrapper(currentWorld(exec), history, jsHistory);449 cacheWrapper(currentWorld(exec), history, jsHistory); 450 450 return jsHistory; 451 451 } … … 454 454 { 455 455 Location* location = impl()->location(); 456 if (JSDOMWrapper* wrapper = getCached DOMObjectWrapper(currentWorld(exec), location))456 if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), location)) 457 457 return wrapper; 458 458 459 459 JSDOMWindow* window = const_cast<JSDOMWindow*>(this); 460 460 JSLocation* jsLocation = new (exec) JSLocation(getDOMStructure<JSLocation>(exec, window), window, location); 461 cache DOMObjectWrapper(currentWorld(exec), location, jsLocation);461 cacheWrapper(currentWorld(exec), location, jsLocation); 462 462 return jsLocation; 463 463 } -
trunk/Source/WebCore/bindings/js/JSDataViewCustom.cpp
r78407 r84194 45 45 JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, DataView* object) 46 46 { 47 return getDOMObjectWrapper<JSDataView>(exec, globalObject, object);47 return wrap<JSDataView>(exec, globalObject, object); 48 48 } 49 49 -
trunk/Source/WebCore/bindings/js/JSDocumentCustom.cpp
r84105 r84194 69 69 70 70 Location* location = frame->domWindow()->location(); 71 if (JSDOMWrapper* wrapper = getCached DOMObjectWrapper(currentWorld(exec), location))71 if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), location)) 72 72 return wrapper; 73 73 74 74 JSLocation* jsLocation = new (exec) JSLocation(getDOMStructure<JSLocation>(exec, globalObject()), globalObject(), location); 75 cache DOMObjectWrapper(currentWorld(exec), location, jsLocation);75 cacheWrapper(currentWorld(exec), location, jsLocation); 76 76 return jsLocation; 77 77 } … … 101 101 return jsNull(); 102 102 103 JSDOMWrapper* wrapper = getCached DOMNodeWrapper(currentWorld(exec), document);103 JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), document); 104 104 if (wrapper) 105 105 return wrapper; -
trunk/Source/WebCore/bindings/js/JSElementCustom.cpp
r84029 r84194 72 72 return jsNull(); 73 73 74 ASSERT(!getCached DOMNodeWrapper(currentWorld(exec), element));74 ASSERT(!getCachedWrapper(currentWorld(exec), element)); 75 75 76 76 JSNode* wrapper; -
trunk/Source/WebCore/bindings/js/JSEventCustom.cpp
r84105 r84194 122 122 return jsNull(); 123 123 124 JSDOMWrapper* wrapper = getCached DOMObjectWrapper(currentWorld(exec), event);124 JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), event); 125 125 if (wrapper) 126 126 return wrapper; -
trunk/Source/WebCore/bindings/js/JSHTMLCollectionCustom.cpp
r84105 r84194 135 135 return jsNull(); 136 136 137 JSDOMWrapper* wrapper = getCached DOMObjectWrapper(currentWorld(exec), collection);137 JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), collection); 138 138 139 139 if (wrapper) -
trunk/Source/WebCore/bindings/js/JSImageDataCustom.cpp
r84105 r84194 42 42 return jsNull(); 43 43 44 JSDOMWrapper* wrapper = getCached DOMObjectWrapper(currentWorld(exec), imageData);44 JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), imageData); 45 45 if (wrapper) 46 46 return wrapper; -
trunk/Source/WebCore/bindings/js/JSNamedNodeMapCustom.cpp
r83938 r84194 36 36 namespace WebCore { 37 37 38 class JSNamedNodeMapOwner : public JSC::WeakHandleOwner { 39 virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::MarkStack&); 40 virtual void finalize(JSC::Handle<JSC::Unknown>, void* context); 41 }; 42 43 bool JSNamedNodeMapOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, MarkStack& markStack) 44 { 45 JSNamedNodeMap* jsNamedNodeMap = static_cast<JSNamedNodeMap*>(handle.get().asCell()); 46 if (!jsNamedNodeMap->hasCustomProperties()) 47 return false; 48 Element* element = jsNamedNodeMap->impl()->element(); 49 if (!element) 50 return false; 51 return markStack.containsOpaqueRoot(root(element)); 52 } 53 54 void JSNamedNodeMapOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context) 55 { 56 JSNamedNodeMap* jsNamedNodeMap = static_cast<JSNamedNodeMap*>(handle.get().asCell()); 57 DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context); 58 uncacheWrapper(world, jsNamedNodeMap->impl(), jsNamedNodeMap); 59 } 60 61 inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld*, NamedNodeMap*) 62 { 63 DEFINE_STATIC_LOCAL(JSNamedNodeMapOwner, jsNamedNodeMapOwner, ()); 64 return &jsNamedNodeMapOwner; 65 } 66 67 inline void* wrapperContext(DOMWrapperWorld* world, NamedNodeMap*) 68 { 69 return world; 70 } 71 38 72 bool JSNamedNodeMap::canGetItemsForName(ExecState*, NamedNodeMap* impl, const Identifier& propertyName) 39 73 { … … 51 85 Base::markChildren(markStack); 52 86 87 // We need to keep the wrapper for our underlying NamedNodeMap's element 88 // alive because NamedNodeMap and Attr rely on the element for data, and 89 // don't know how to keep it alive correctly. 90 // FIXME: Fix this lifetime issue in the DOM, and remove this. 53 91 Element* element = impl()->element(); 54 92 if (!element) … … 57 95 } 58 96 97 JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, NamedNodeMap* impl) 98 { 99 return wrap<JSNamedNodeMap>(exec, globalObject, impl); 100 } 101 59 102 } // namespace WebCore -
trunk/Source/WebCore/bindings/js/JSNodeCustom.cpp
r84029 r84194 36 36 #include "EntityReference.h" 37 37 #include "ExceptionCode.h" 38 #include "HTMLAudioElement.h" 39 #include "HTMLCanvasElement.h" 38 40 #include "HTMLElement.h" 41 #include "HTMLFrameElementBase.h" 42 #include "HTMLImageElement.h" 43 #include "HTMLLinkElement.h" 44 #include "HTMLNames.h" 45 #include "HTMLScriptElement.h" 46 #include "HTMLStyleElement.h" 39 47 #include "JSAttr.h" 40 48 #include "JSCDATASection.h" … … 56 64 #include "ProcessingInstruction.h" 57 65 #include "RegisteredEventListener.h" 66 #include "StyleSheet.h" 67 #include "StyledElement.h" 58 68 #include "Text.h" 59 69 #include <wtf/PassRefPtr.h> … … 68 78 69 79 namespace WebCore { 80 81 using namespace HTMLNames; 82 83 static bool isObservable(JSNode* jsNode, Node* node, DOMWrapperWorld* world) 84 { 85 // Certain conditions implicitly make existence of a JS DOM node wrapper observable 86 // through the DOM, even if no explicit reference to it remains. 87 88 // The DOM doesn't know how to keep a tree of nodes alive without the root 89 // being explicitly referenced. So, we artificially treat the root of 90 // every tree as observable. 91 // FIXME: Resolve this lifetime issue in the DOM, and remove this inefficiency. 92 if (!node->parentNode()) 93 return true; 94 95 // If a node is in the document, and its wrapper has custom properties, 96 // the wrapper is observable because future access to the node through the 97 // DOM must reflect those properties. 98 if (jsNode->hasCustomProperties()) 99 return true; 100 101 // If a node is in the document, and has event listeners, its wrapper is 102 // observable because its wrapper is responsible for marking those event listeners. 103 if (node->hasEventListeners()) 104 return true; 105 106 // If a node owns another object with a wrapper with custom properties, 107 // the wrapper must be treated as observable, because future access to 108 // those objects through the DOM must reflect those properties. 109 // FIXME: It would be better if this logic could be in the node next to 110 // the custom markChildren functions rather than here. 111 // Note that for some compound objects like stylesheets and CSSStyleDeclarations, 112 // we don't descend to check children for custom properties, and just conservatively 113 // keep the node wrappers protecting them alive. 114 if (node->isElementNode()) { 115 if (node->isStyledElement()) { 116 if (CSSMutableStyleDeclaration* style = static_cast<StyledElement*>(node)->inlineStyleDecl()) { 117 if (world->m_wrappers.get(style)) 118 return true; 119 } 120 } 121 if (static_cast<Element*>(node)->hasTagName(canvasTag)) { 122 if (CanvasRenderingContext* context = static_cast<HTMLCanvasElement*>(node)->renderingContext()) { 123 if (JSDOMWrapper* wrapper = world->m_wrappers.get(context).get()) { 124 if (wrapper->hasCustomProperties()) 125 return true; 126 } 127 } 128 } else if (static_cast<Element*>(node)->hasTagName(linkTag)) { 129 if (StyleSheet* sheet = static_cast<HTMLLinkElement*>(node)->sheet()) { 130 if (world->m_wrappers.get(sheet)) 131 return true; 132 } 133 } else if (static_cast<Element*>(node)->hasTagName(styleTag)) { 134 if (StyleSheet* sheet = static_cast<HTMLStyleElement*>(node)->sheet()) { 135 if (world->m_wrappers.get(sheet)) 136 return true; 137 } 138 } 139 } else if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) { 140 if (StyleSheet* sheet = static_cast<ProcessingInstruction*>(node)->sheet()) { 141 if (world->m_wrappers.get(sheet)) 142 return true; 143 } 144 } 145 146 return false; 147 } 148 149 static inline bool isReachableFromDOM(JSNode* jsNode, Node* node, DOMWrapperWorld* world, MarkStack& markStack) 150 { 151 if (!node->inDocument()) { 152 // If a wrapper is the last reference to an image or script element 153 // that is loading but not in the document, the wrapper is observable 154 // because it is the only thing keeping the image element alive, and if 155 // the image element is destroyed, its load event will not fire. 156 // FIXME: The DOM should manage this issue without the help of JavaScript wrappers. 157 if (node->hasTagName(imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent()) 158 return true; 159 if (node->hasTagName(scriptTag) && !static_cast<HTMLScriptElement*>(node)->haveFiredLoadEvent()) 160 return true; 161 #if ENABLE(VIDEO) 162 if (node->hasTagName(audioTag) && !static_cast<HTMLAudioElement*>(node)->paused()) 163 return true; 164 #endif 165 166 // If a node is firing event listeners, its wrapper is observable because 167 // its wrapper is responsible for marking those event listeners. 168 if (node->isFiringEventListeners()) 169 return true; 170 } 171 172 return isObservable(jsNode, node, world) && markStack.containsOpaqueRoot(root(node)); 173 } 174 175 bool JSNodeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void* context, MarkStack& markStack) 176 { 177 JSNode* jsNode = static_cast<JSNode*>(handle.get().asCell()); 178 DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context); 179 return isReachableFromDOM(jsNode, jsNode->impl(), world, markStack); 180 } 181 182 void JSNodeOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context) 183 { 184 JSNode* jsNode = static_cast<JSNode*>(handle.get().asCell()); 185 DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context); 186 uncacheWrapper(world, jsNode->impl(), jsNode); 187 } 70 188 71 189 JSValue JSNode::insertBefore(ExecState* exec) … … 131 249 { 132 250 ASSERT(node); 133 ASSERT(!getCached DOMNodeWrapper(currentWorld(exec), node));251 ASSERT(!getCachedWrapper(currentWorld(exec), node)); 134 252 135 253 JSNode* wrapper; -
trunk/Source/WebCore/bindings/js/JSNodeCustom.h
r84049 r84194 32 32 namespace WebCore { 33 33 34 inline JSNode* getCachedDOMNodeWrapper(DOMWrapperWorld* world, Node* node) 34 class JSNodeOwner : public JSC::WeakHandleOwner { 35 virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::MarkStack&); 36 virtual void finalize(JSC::Handle<JSC::Unknown>, void* context); 37 }; 38 39 inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld*, Node*) 35 40 { 36 if (world->isNormal()) 37 return static_cast<JSNode*>(node->wrapper()); 38 return static_cast<JSNode*>(getCachedDOMObjectWrapper(world, node)); 41 DEFINE_STATIC_LOCAL(JSNodeOwner, jsNodeOwner, ()); 42 return &jsNodeOwner; 39 43 } 40 44 41 inline void cacheDOMNodeWrapper(DOMWrapperWorld* world, Node* node, JSNode* wrapper)45 inline void* wrapperContext(DOMWrapperWorld* world, Node*) 42 46 { 43 ASSERT(wrapper); 44 if (world->isNormal()) { 45 node->setWrapper(*world->globalData(), wrapper, world->jsNodeHandleOwner(), node); 46 return; 47 } 48 cacheDOMObjectWrapper(world, node, wrapper); 47 return world; 49 48 } 50 49 51 inline void uncacheDOMNodeWrapper(DOMWrapperWorld* world, Node* node, JSNode* jsNode)50 inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld* world, Node* node) 52 51 { 53 if (world->isNormal()) { 54 node->clearWrapper(); 55 return; 56 } 57 uncacheDOMObjectWrapper(world, node, jsNode); 52 if (!world->isNormal()) 53 return 0; 54 return node->wrapper(); 55 } 56 57 inline bool setInlineCachedWrapper(DOMWrapperWorld* world, Node* node, JSDOMWrapper* wrapper) 58 { 59 if (!world->isNormal()) 60 return false; 61 ASSERT(!node->wrapper()); 62 node->setWrapper(*world->globalData(), wrapper, wrapperOwner(world, node), wrapperContext(world, node)); 63 return true; 64 } 65 66 inline bool clearInlineCachedWrapper(DOMWrapperWorld* world, Node* node, JSDOMWrapper* wrapper) 67 { 68 if (!world->isNormal()) 69 return false; 70 ASSERT_UNUSED(wrapper, node->wrapper() == wrapper); 71 node->clearWrapper(); 72 return true; 58 73 } 59 74 … … 65 80 return JSC::jsNull(); 66 81 67 JSNode* wrapper = getCachedDOMNodeWrapper(currentWorld(exec), node);82 JSNode* wrapper = static_cast<JSNode*>(getCachedWrapper(currentWorld(exec), node)); 68 83 if (wrapper) 69 84 return wrapper; -
trunk/Source/WebCore/bindings/js/JSSVGPathSegCustom.cpp
r84105 r84194 64 64 return jsNull(); 65 65 66 if (JSDOMWrapper* wrapper = getCached DOMObjectWrapper(currentWorld(exec), object))66 if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), object)) 67 67 return wrapper; 68 68 -
trunk/Source/WebCore/bindings/js/JSStyleSheetCustom.cpp
r84105 r84194 41 41 return jsNull(); 42 42 43 JSDOMWrapper* wrapper = getCached DOMObjectWrapper(currentWorld(exec), styleSheet);43 JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), styleSheet); 44 44 if (wrapper) 45 45 return wrapper; -
trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
r84105 r84194 1305 1305 push(@implContent, "{\n"); 1306 1306 push(@implContent, " return getHashTableForGlobalData(exec->globalData(), &${className}PrototypeTable);\n"); 1307 push(@implContent, "}\n ");1307 push(@implContent, "}\n\n"); 1308 1308 push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleClassName}Prototype\", &JSC::JSObjectWithGlobalObject::s_info, 0, get${className}PrototypeTable };\n\n"); 1309 1309 } else { … … 1380 1380 push(@implContent, "{\n"); 1381 1381 push(@implContent, " return getHashTableForGlobalData(exec->globalData(), &${className}Table);\n"); 1382 push(@implContent, "}\n ");1382 push(@implContent, "}\n\n"); 1383 1383 } 1384 1384 … … 1591 1591 } 1592 1592 1593 push(@implContent, "}\n ");1593 push(@implContent, "}\n\n"); 1594 1594 1595 1595 push(@implContent, "#endif\n") if $attributeConditionalString; … … 1611 1611 1612 1612 push(@implContent, " return ${className}::getConstructor(exec, domObject->globalObject());\n"); 1613 push(@implContent, "}\n"); 1614 push(@implContent, "\n"); 1613 push(@implContent, "}\n\n"); 1615 1614 } 1616 1615 } … … 1770 1769 } 1771 1770 1772 push(@implContent, "}\n ");1771 push(@implContent, "}\n\n"); 1773 1772 1774 1773 push(@implContent, "#endif\n") if $attributeConditionalString; … … 1800 1799 push(@implContent, " static_cast<$className*>(thisObject)->putDirect(exec->globalData(), Identifier(exec, \"$name\"), value);\n"); 1801 1800 } 1802 push(@implContent, "}\n"); 1803 push(@implContent, "\n"); 1801 push(@implContent, "}\n\n"); 1804 1802 } 1805 1803 } … … 2096 2094 push(@implContent, " return toJS(exec, thisObj->globalObject(), static_cast<$implClassName*>(thisObj->impl())->item(index));\n"); 2097 2095 } 2098 push(@implContent, "}\n ");2096 push(@implContent, "}\n\n"); 2099 2097 if ($interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") { 2100 2098 $implIncludes{"JSNode.h"} = 1; … … 2107 2105 push(@implContent, "{\n"); 2108 2106 push(@implContent, " return jsNumber(static_cast<$implClassName*>(impl())->item(index));\n"); 2109 push(@implContent, "}\n ");2107 push(@implContent, "}\n\n"); 2110 2108 if ($interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") { 2111 2109 $implIncludes{"JSNode.h"} = 1; … … 2116 2114 if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateToJS"}) and !$dataNode->extendedAttributes->{"CustomToJS"}) { 2117 2115 if ($svgPropertyType) { 2118 push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* object)\n");2116 push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n"); 2119 2117 } else { 2120 push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* object)\n");2118 push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n"); 2121 2119 } 2122 2120 push(@implContent, "{\n"); 2123 2121 if ($svgPropertyType) { 2124 push(@implContent, " return getDOMObjectWrapper<$className, $implType>(exec, globalObject, object);\n");2122 push(@implContent, " return wrap<$className, $implType>(exec, globalObject, impl);\n"); 2125 2123 } else { 2126 push(@implContent, " return getDOMObjectWrapper<$className>(exec, globalObject, object);\n");2127 } 2128 push(@implContent, "}\n ");2124 push(@implContent, " return wrap<$className>(exec, globalObject, impl);\n"); 2125 } 2126 push(@implContent, "}\n\n"); 2129 2127 } 2130 2128 -
trunk/Source/WebCore/dom/NamedNodeMap.idl
r60022 r84194 22 22 23 23 interface [ 24 CustomToJS, 24 25 CustomMarkFunction, 25 26 HasIndexGetter,
Note: See TracChangeset
for help on using the changeset viewer.