diff options
author | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-25 22:39:12 +0000 |
---|---|---|
committer | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-25 22:39:12 +0000 |
commit | 20ecf967af4883293aca18d69889d1f85d279446 (patch) | |
tree | 33ef10436c6a81e62d58e5e051dadfc1ea0604d7 | |
parent | 6e1f48fb52edc5583db8c6deea2f00600bdddb8b (diff) | |
download | chromium_src-20ecf967af4883293aca18d69889d1f85d279446.zip chromium_src-20ecf967af4883293aca18d69889d1f85d279446.tar.gz chromium_src-20ecf967af4883293aca18d69889d1f85d279446.tar.bz2 |
Fix the problem that DOM object is deleted in the GC thread, not owning thread.
Review URL: http://codereview.chromium.org/40088
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12507 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | webkit/build/V8Bindings/SConscript | 1 | ||||
-rw-r--r-- | webkit/build/V8Bindings/V8Bindings.vcproj | 12 | ||||
-rw-r--r-- | webkit/port/bindings/v8/DOMObjectsInclude.h | 181 | ||||
-rw-r--r-- | webkit/port/bindings/v8/V8DOMMap.cpp | 510 | ||||
-rw-r--r-- | webkit/port/bindings/v8/V8DOMMap.h | 58 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.cpp | 419 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.h | 7 | ||||
-rw-r--r-- | webkit/webkit.gyp | 3 |
8 files changed, 803 insertions, 388 deletions
diff --git a/webkit/build/V8Bindings/SConscript b/webkit/build/V8Bindings/SConscript index dd6a25a..7835adc 100644 --- a/webkit/build/V8Bindings/SConscript +++ b/webkit/build/V8Bindings/SConscript @@ -353,6 +353,7 @@ inputs = [ '$PORT_DIR/bindings/v8/V8NPObject.cpp', '$PORT_DIR/bindings/v8/v8_proxy.cpp', '$PORT_DIR/bindings/v8/V8CanvasPixelArrayCustom.cpp', + '$PORT_DIR/bindings/v8/V8DOMMap.cpp', '$PORT_DIR/bindings/v8/V8MessagePortCustom.cpp', '$PORT_DIR/bindings/v8/V8WorkerContextCustom.cpp', '$PORT_DIR/bindings/v8/V8WorkerCustom.cpp', diff --git a/webkit/build/V8Bindings/V8Bindings.vcproj b/webkit/build/V8Bindings/V8Bindings.vcproj index c5d1326..61f25a1 100644 --- a/webkit/build/V8Bindings/V8Bindings.vcproj +++ b/webkit/build/V8Bindings/V8Bindings.vcproj @@ -2813,6 +2813,10 @@ > </File> <File + RelativePath="..\..\port\bindings\v8\DOMObjectsInclude.h" + > + </File> + <File RelativePath="..\..\port\bindings\v8\JSDOMBinding.cpp" > </File> @@ -2985,6 +2989,14 @@ > </File> <File + RelativePath="..\..\port\bindings\v8\V8DOMMap.cpp" + > + </File> + <File + RelativePath="..\..\port\bindings\v8\V8DOMMap.h" + > + </File> + <File RelativePath="..\..\..\third_party\WebKit\WebCore\bindings\v8\V8Collection.h" > </File> diff --git a/webkit/port/bindings/v8/DOMObjectsInclude.h b/webkit/port/bindings/v8/DOMObjectsInclude.h new file mode 100644 index 0000000..7759065 --- /dev/null +++ b/webkit/port/bindings/v8/DOMObjectsInclude.h @@ -0,0 +1,181 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DOMObjectsInclude_h +#define DOMObjectsInclude_h + +#include "BarInfo.h" +#include "CanvasGradient.h" +#include "CanvasPattern.h" +#include "CanvasPixelArray.h" +#include "CanvasRenderingContext2D.h" +#include "CanvasStyle.h" +#include "CharacterData.h" +#include "ClientRect.h" +#include "ClientRectList.h" +#include "Clipboard.h" +#include "Console.h" +#include "Counter.h" +#include "CSSCharsetRule.h" +#include "CSSFontFaceRule.h" +#include "CSSImportRule.h" +#include "CSSMediaRule.h" +#include "CSSPageRule.h" +#include "CSSRule.h" +#include "CSSRuleList.h" +#include "CSSValueList.h" +#include "CSSStyleRule.h" +#include "CSSStyleSheet.h" +#include "CSSVariablesDeclaration.h" +#include "CSSVariablesRule.h" +#include "Database.h" +#include "DocumentType.h" +#include "DocumentFragment.h" +#include "DOMCoreException.h" +#include "DOMImplementation.h" +#include "DOMParser.h" +#include "DOMSelection.h" +#include "DOMStringList.h" +#include "DOMWindow.h" +#include "Entity.h" +#include "EventListener.h" +#include "EventTarget.h" +#include "Event.h" +#include "EventException.h" +#include "ExceptionCode.h" +#include "File.h" +#include "FileList.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "History.h" +#include "HTMLNames.h" +#include "HTMLDocument.h" +#include "HTMLElement.h" +#include "HTMLImageElement.h" +#include "HTMLInputElement.h" +#include "HTMLSelectElement.h" +#include "HTMLOptionsCollection.h" +#include "ImageData.h" +#include "InspectorController.h" +#include "KeyboardEvent.h" +#include "Location.h" +#include "MediaError.h" +#include "MediaList.h" +#include "MediaPlayer.h" +#include "MessageChannel.h" +#include "MessageEvent.h" +#include "MessagePort.h" +#include "MimeTypeArray.h" +#include "MouseEvent.h" +#include "MutationEvent.h" +#include "Navigator.h" // for MimeTypeArray +#include "NodeFilter.h" +#include "Notation.h" +#include "NodeList.h" +#include "NodeIterator.h" +#include "OverflowEvent.h" +#include "Page.h" +#include "Plugin.h" +#include "PluginArray.h" +#include "ProcessingInstruction.h" +#include "ProgressEvent.h" +#include "Range.h" +#include "RangeException.h" +#include "Rect.h" +#include "RGBColor.h" +#include "Screen.h" +#include "ScriptExecutionContext.h" +#include "SecurityOrigin.h" +#include "Settings.h" +#include "SQLTransaction.h" +#include "SQLResultSet.h" +#include "SQLResultSetRowList.h" +#include "StyleSheet.h" +#include "StyleSheetList.h" +#include "SVGColor.h" +#include "SVGPaint.h" +#include "TextEvent.h" +#include "TextMetrics.h" +#include "TimeRanges.h" +#include "TreeWalker.h" +#include "XSLTProcessor.h" +#include "V8AbstractEventListener.h" +#include "V8CustomEventListener.h" +#include "V8DOMWindow.h" +#include "V8HTMLElement.h" +#include "V8LazyEventListener.h" +#include "V8ObjectEventListener.h" +#include "WebKitAnimationEvent.h" +#include "WebKitCSSKeyframeRule.h" +#include "WebKitCSSKeyframesRule.h" +#include "WebKitCSSMatrix.h" +#include "WebKitCSSTransformValue.h" +#include "WebKitPoint.h" +#include "WebKitTransitionEvent.h" +#include "WheelEvent.h" +#include "XMLHttpRequest.h" +#include "XMLHttpRequestException.h" +#include "XMLHttpRequestProgressEvent.h" +#include "XMLHttpRequestUpload.h" +#include "XMLSerializer.h" +#include "XPathException.h" +#include "XPathExpression.h" +#include "XPathNSResolver.h" +#include "XPathResult.h" + +#if ENABLE(SVG) +#include "SVGAngle.h" +#include "SVGAnimatedPoints.h" +#include "SVGElement.h" +#include "SVGElementInstance.h" +#include "SVGElementInstanceList.h" +#include "SVGException.h" +#include "SVGLength.h" +#include "SVGLengthList.h" +#include "SVGNumberList.h" +#include "SVGPathSeg.h" +#include "SVGPathSegArc.h" +#include "SVGPathSegClosePath.h" +#include "SVGPathSegCurvetoCubic.h" +#include "SVGPathSegCurvetoCubicSmooth.h" +#include "SVGPathSegCurvetoQuadratic.h" +#include "SVGPathSegCurvetoQuadraticSmooth.h" +#include "SVGPathSegLineto.h" +#include "SVGPathSegLinetoHorizontal.h" +#include "SVGPathSegLinetoVertical.h" +#include "SVGPathSegList.h" +#include "SVGPathSegMoveto.h" +#include "SVGPointList.h" +#include "SVGPreserveAspectRatio.h" +#include "SVGRenderingIntent.h" +#include "SVGStringList.h" +#include "SVGTransform.h" +#include "SVGTransformList.h" +#include "SVGUnitTypes.h" +#include "SVGURIReference.h" +#include "SVGZoomEvent.h" +#include "V8SVGPODTypeWrapper.h" +#endif + +#if ENABLE(WORKERS) +#include "Worker.h" +#include "WorkerContext.h" +#include "WorkerLocation.h" +#include "WorkerNavigator.h" +#endif + +#if ENABLE(XPATH) +#include "XPathEvaluator.h" +#endif + +namespace WebCore { + +// A helper class for undetectable document.all +class UndetectableHTMLCollection : public HTMLCollection { +}; + +} // namespace WebCore + +#endif // DOMObjectsInclude_h diff --git a/webkit/port/bindings/v8/V8DOMMap.cpp b/webkit/port/bindings/v8/V8DOMMap.cpp new file mode 100644 index 0000000..912dad7 --- /dev/null +++ b/webkit/port/bindings/v8/V8DOMMap.cpp @@ -0,0 +1,510 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include <v8.h> + +#include "DOMObjectsInclude.h" +#include "V8DOMMap.h" + +#include <wtf/HashMap.h> +#include <wtf/MainThread.h> +#include <wtf/Threading.h> +#include <wtf/ThreadSpecific.h> + +namespace WebCore { + +// DOM binding algorithm: +// +// There are two kinds of DOM objects: +// 1. DOM tree nodes, such as Document, HTMLElement, ... +// there classes implements TreeShared<T> interface; +// 2. Non-node DOM objects, such as CSSRule, Location, etc. +// these classes implement a ref-counted scheme. +// +// A DOM object may have a JS wrapper object. If a tree node +// is alive, its JS wrapper must be kept alive even it is not +// reachable from JS roots. +// However, JS wrappers of non-node objects can go away if +// not reachable from other JS objects. It works like a cache. +// +// DOM objects are ref-counted, and JS objects are traced from +// a set of root objects. They can create a cycle. To break +// cycles, we do following: +// Handles from DOM objects to JS wrappers are always weak, +// so JS wrappers of non-node object cannot create a cycle. +// Before starting a global GC, we create a virtual connection +// between nodes in the same tree in the JS heap. If the wrapper +// of one node in a tree is alive, wrappers of all nodes in +// the same tree are considered alive. This is done by creating +// object groups in GC prologue callbacks. The mark-compact +// collector will remove these groups after each GC. +// +// DOM objects should be deref-ed from the owning thread, not the GC thread +// that does not own them. In V8, GC can kick in from any thread. To ensure +// that DOM objects are always deref-ed from the owning thread when running +// V8 in multi-threading environment, we do following: +// 1. Maintain a thread specific DOM wrapper map for each object map. +// (We're using TLS support from WTF instead of base since V8Bindings +// does not depend on base. We further assume that all child threads +// running V8 instances are created by WTF and thus a destructor will +// be called to clean up all thread specific data.) +// 2. When GC happens: +// 2.1. If the dead object is in GC thread's map, remove the JS reference +// and deref the DOM object. +// 2.2. Otherwise, go through all thread maps to find the owning thread. +// Remove the JS reference from the owning thread's map and move the +// DOM object to a delayed queue. Post a task to the owning thread +// to have it deref-ed from the owning thread at later time. +// 3. When a thread is tearing down, invoke a cleanup routine to go through +// all objects in the delayed queue and the thread map and deref all of +// them. + +static void weakDOMObjectCallback(v8::Persistent<v8::Value> obj, void* param); +static void weakNodeCallback(v8::Persistent<v8::Value> obj, void* param); + +#if ENABLE(SVG) +static void weakSVGElementInstanceCallback(v8::Persistent<v8::Value> obj, void* param); + +// SVG non-node elements may have a reference to a context node which should be notified when the element is change +static void weakSVGObjectWithContextCallback(v8::Persistent<v8::Value> obj, void* domObj); +#endif + +// This is to ensure that we will deref DOM objects from the owning thread, not the GC thread. +// The helper function will be scheduled by the GC thread to get called from the owning thread. +static void derefDelayedObjectsInCurrentThread(void*); + +// This should be called to remove all DOM objects associated with the current thread when it is tearing down. +static void removeAllDOMObjectsInCurrentThread(); + +// A map from a thread ID to thread's specific data. +class ThreadSpecificDOMData; +typedef WTF::HashMap<WTF::ThreadIdentifier, ThreadSpecificDOMData*> DOMThreadMap; +static DOMThreadMap domThreadMap; + +// Mutex to protect against concurrent access of domThreadMap. +static WTF::Mutex domThreadMapMutex; + +class ThreadSpecificDOMData { +public: + enum DOMWrapperMapType + { + DOMNodeMap, + DOMObjectMap, + ActiveDOMObjectMap, +#if ENABLE(SVG) + DOMSVGElementInstanceMap, + DOMSVGObjectWithContextMap +#endif + }; + + typedef WTF::HashMap<void*, V8ClassIndex::V8WrapperType> DelayedObjectMap; + + template <class KeyType> + class InternalDOMWrapperMap : public DOMWrapperMap<KeyType> { + public: + InternalDOMWrapperMap(v8::WeakReferenceCallback callback) + : DOMWrapperMap<KeyType>(callback) { } + + virtual void forget(KeyType* obj); + + void forgetOnly(KeyType* obj) + { + DOMWrapperMap<KeyType>::forget(obj); + } + }; + + ThreadSpecificDOMData() + : m_domNodeMap(new InternalDOMWrapperMap<Node>(&weakNodeCallback)) + , m_domObjectMap(new InternalDOMWrapperMap<void>(weakDOMObjectCallback)) + , m_activeDomObjectMap(new InternalDOMWrapperMap<void>(weakActiveDOMObjectCallback)) +#if ENABLE(SVG) + , m_domSvgElementInstanceMap(new InternalDOMWrapperMap<SVGElementInstance>(weakSVGElementInstanceCallback)) + , m_domSvgObjectWithContextMap(new InternalDOMWrapperMap<void>(weakSVGObjectWithContextCallback)) +#endif + , m_delayedProcessingScheduled(false) + , m_isMainThread(WTF::isMainThread()) + { + WTF::MutexLocker locker(domThreadMapMutex); + domThreadMap.set(WTF::currentThread(), this); + } + + // This is called when WTF thread is tearing down. + // We assume that all child threads running V8 instances are created by WTF. + ~ThreadSpecificDOMData() + { + removeAllDOMObjectsInCurrentThread(); + + delete m_domNodeMap; + delete m_domObjectMap; + delete m_activeDomObjectMap; +#if ENABLE(SVG) + delete m_domSvgElementInstanceMap; + delete m_domSvgObjectWithContextMap; +#endif + + WTF::MutexLocker locker(domThreadMapMutex); + domThreadMap.remove(WTF::currentThread()); + } + + void* getDOMWrapperMap(DOMWrapperMapType type) + { + switch (type) { + case DOMNodeMap: + return m_domNodeMap; + case DOMObjectMap: + return m_domObjectMap; + case ActiveDOMObjectMap: + return m_activeDomObjectMap; +#if ENABLE(SVG) + case DOMSVGElementInstanceMap: + return m_domSvgElementInstanceMap; + case DOMSVGObjectWithContextMap: + return m_domSvgObjectWithContextMap; +#endif + default: + ASSERT(false); + return NULL; + } + } + + InternalDOMWrapperMap<Node>& domNodeMap() { return *m_domNodeMap; } + InternalDOMWrapperMap<void>& domObjectMap() { return *m_domObjectMap; } + InternalDOMWrapperMap<void>& activeDomObjectMap() { return *m_activeDomObjectMap; } +#if ENABLE(SVG) + InternalDOMWrapperMap<SVGElementInstance>& domSvgElementInstanceMap() { return *m_domSvgElementInstanceMap; } + InternalDOMWrapperMap<void>& domSvgObjectWithContextMap() { return *m_domSvgObjectWithContextMap; } +#endif + + DelayedObjectMap& delayedObjectMap() { return m_delayedObjectMap; } + bool delayedProcessingScheduled() const { return m_delayedProcessingScheduled; } + void setDelayedProcessingScheduled(bool value) { m_delayedProcessingScheduled = value; } + bool isMainThread() const { return m_isMainThread; } + +private: + InternalDOMWrapperMap<Node>* m_domNodeMap; + InternalDOMWrapperMap<void>* m_domObjectMap; + InternalDOMWrapperMap<void>* m_activeDomObjectMap; +#if ENABLE(SVG) + InternalDOMWrapperMap<SVGElementInstance>* m_domSvgElementInstanceMap; + InternalDOMWrapperMap<void>* m_domSvgObjectWithContextMap; +#endif + + // Stores all the DOM objects that are delayed to be processed when the owning thread gains control. + DelayedObjectMap m_delayedObjectMap; + + // The flag to indicate if the task to do the delayed process has already been posted. + bool m_delayedProcessingScheduled; + + bool m_isMainThread; +}; + +static WTF::ThreadSpecific<ThreadSpecificDOMData> threadSpecificDOMData; + +template<typename T> +static void handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMWrapperMapType mapType, V8ClassIndex::V8WrapperType objType, T* obj); + +template <class KeyType> +void ThreadSpecificDOMData::InternalDOMWrapperMap<KeyType>::forget(KeyType* obj) +{ + DOMWrapperMap<KeyType>::forget(obj); + + ThreadSpecificDOMData::DelayedObjectMap& delayedObjectMap = (*threadSpecificDOMData).delayedObjectMap(); + delayedObjectMap.take(obj); +} + +DOMWrapperMap<Node>& getDOMNodeMap() +{ + return (*threadSpecificDOMData).domNodeMap(); +} + +DOMWrapperMap<void>& getDOMObjectMap() +{ + return (*threadSpecificDOMData).domObjectMap(); +} + +DOMWrapperMap<void>& getActiveDOMObjectMap() +{ + return (*threadSpecificDOMData).activeDomObjectMap(); +} + +#if ENABLE(SVG) +DOMWrapperMap<SVGElementInstance>& getDOMSVGElementInstanceMap() +{ + return (*threadSpecificDOMData).domSvgElementInstanceMap(); +} + +static void weakSVGElementInstanceCallback(v8::Persistent<v8::Value> obj, void* param) +{ + SVGElementInstance* instance = static_cast<SVGElementInstance*>(param); + + ThreadSpecificDOMData::InternalDOMWrapperMap<SVGElementInstance>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<SVGElementInstance>&>(getDOMSVGElementInstanceMap()); + if (map.contains(instance)) { + instance->deref(); + map.forgetOnly(instance); + } else { + handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMSVGElementInstanceMap, V8ClassIndex::SVGELEMENTINSTANCE, instance); + } +} + +// Map of SVG objects with contexts to V8 objects +DOMWrapperMap<void>& getDOMSVGObjectWithContextMap() +{ + return (*threadSpecificDOMData).domSvgObjectWithContextMap(); +} + +static void weakSVGObjectWithContextCallback(v8::Persistent<v8::Value> obj, void* domObj) +{ + v8::HandleScope scope; + ASSERT(obj->IsObject()); + + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj)); + + ThreadSpecificDOMData::InternalDOMWrapperMap<void>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<void>&>(getDOMSVGObjectWithContextMap()); + if (map.contains(domObj)) { + // Forget function removes object from the map and dispose the wrapper. + map.forgetOnly(domObj); + + switch (type) { +#define MakeCase(TYPE, NAME) \ + case V8ClassIndex::TYPE: static_cast<NAME*>(domObj)->deref(); break; + SVG_OBJECT_TYPES(MakeCase) +#undef MakeCase +#define MakeCase(TYPE, NAME) \ + case V8ClassIndex::TYPE: \ + static_cast<V8SVGPODTypeWrapper<NAME>*>(domObj)->deref(); break; + SVG_POD_NATIVE_TYPES(MakeCase) +#undef MakeCase + default: + ASSERT(false); + } + } else { + handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMSVGObjectWithContextMap, type, domObj); + } +} +#endif + +// Called when the dead object is not in GC thread's map. Go through all thread maps to find the one containing it. +// Then clear the JS reference and push the DOM object into the delayed queue for it to be deref-ed at later time from the owning thread. +// * This is called when the GC thread is not the owning thread. +// * This can be called on any thread that has GC running. +// * Only one V8 instance is running at a time due to V8::Locker. So we don't need to worry about concurrency. +template<typename T> +static void handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMWrapperMapType mapType, V8ClassIndex::V8WrapperType objType, T* obj) +{ + WTF::MutexLocker locker(domThreadMapMutex); + for (typename DOMThreadMap::iterator iter(domThreadMap.begin()); iter != domThreadMap.end(); ++iter) { + WTF::ThreadIdentifier threadID = iter->first; + ThreadSpecificDOMData* threadData = iter->second; + + // Skip the current thread that is GC thread. + if (threadID == WTF::currentThread()) { + ASSERT(!static_cast<DOMWrapperMap<T>*>(threadData->getDOMWrapperMap(mapType))->contains(obj)); + continue; + } + + ThreadSpecificDOMData::InternalDOMWrapperMap<T>* domMap = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<T>*>(threadData->getDOMWrapperMap(mapType)); + if (domMap->contains(obj)) { + // Clear the JS reference. + domMap->forgetOnly(obj); + + // Push into the delayed queue. + threadData->delayedObjectMap().set(obj, objType); + + // Post a task to the owning thread in order to process the delayed queue. + // FIXME(jianli): For now, we can only post to main thread due to WTF task posting limitation. We will fix this when we work on nested worker. + if (!threadData->delayedProcessingScheduled()) { + threadData->setDelayedProcessingScheduled(true); + if (threadData->isMainThread()) + WTF::callOnMainThread(&derefDelayedObjectsInCurrentThread, NULL); + } + + break; + } + } +} + +// Called when obj is near death (not reachable from JS roots). +// It is time to remove the entry from the table and dispose the handle. +static void weakDOMObjectCallback(v8::Persistent<v8::Value> obj, void* domObj) +{ + v8::HandleScope scope; + ASSERT(obj->IsObject()); + + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj)); + + ThreadSpecificDOMData::InternalDOMWrapperMap<void>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<void>&>(getDOMObjectMap()); + if (map.contains(domObj)) { + // Forget function removes object from the map and dispose the wrapper. + map.forgetOnly(domObj); + + switch (type) { +#define MakeCase(TYPE, NAME) \ + case V8ClassIndex::TYPE: static_cast<NAME*>(domObj)->deref(); break; + DOM_OBJECT_TYPES(MakeCase) +#undef MakeCase + default: + ASSERT(false); + } + } else { + handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMObjectMap, type, domObj); + } +} + +void weakActiveDOMObjectCallback(v8::Persistent<v8::Value> obj, void* domObj) +{ + v8::HandleScope scope; + ASSERT(obj->IsObject()); + + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj)); + + ThreadSpecificDOMData::InternalDOMWrapperMap<void>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<void>&>(getActiveDOMObjectMap()); + if (map.contains(domObj)) { + // Forget function removes object from the map and dispose the wrapper. + map.forgetOnly(domObj); + + switch (type) { +#define MakeCase(TYPE, NAME) \ + case V8ClassIndex::TYPE: static_cast<NAME*>(domObj)->deref(); break; + ACTIVE_DOM_OBJECT_TYPES(MakeCase) +#undef MakeCase + default: + ASSERT(false); + } + } else { + handleWeakObjectInOwningThread(ThreadSpecificDOMData::ActiveDOMObjectMap, type, domObj); + } +} + +static void weakNodeCallback(v8::Persistent<v8::Value> obj, void* param) +{ + Node* node = static_cast<Node*>(param); + + ThreadSpecificDOMData::InternalDOMWrapperMap<Node>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<Node>&>(getDOMNodeMap()); + if (map.contains(node)) { + map.forgetOnly(node); + node->deref(); + } else { + handleWeakObjectInOwningThread<Node>(ThreadSpecificDOMData::DOMNodeMap, V8ClassIndex::NODE, node); + } +} + +static void derefObject(V8ClassIndex::V8WrapperType type, void* domObj) +{ + switch (type) { + case V8ClassIndex::NODE: + static_cast<Node*>(domObj)->deref(); + break; + +#define MakeCase(TYPE, NAME) \ + case V8ClassIndex::TYPE: static_cast<NAME*>(domObj)->deref(); break; + DOM_OBJECT_TYPES(MakeCase) // This includes both active and non-active. +#undef MakeCase + +#if ENABLE(SVG) +#define MakeCase(TYPE, NAME) \ + case V8ClassIndex::TYPE: static_cast<NAME*>(domObj)->deref(); break; + SVG_OBJECT_TYPES(MakeCase) // This also includes SVGElementInstance. +#undef MakeCase + +#define MakeCase(TYPE, NAME) \ + case V8ClassIndex::TYPE: \ + static_cast<V8SVGPODTypeWrapper<NAME>*>(domObj)->deref(); break; + SVG_POD_NATIVE_TYPES(MakeCase) +#undef MakeCase +#endif + + default: + ASSERT(false); + } +} + +static void derefDelayedObjects() +{ + WTF::MutexLocker locker(domThreadMapMutex); + ThreadSpecificDOMData::DelayedObjectMap& delayedObjectMap = (*threadSpecificDOMData).delayedObjectMap(); + for (ThreadSpecificDOMData::DelayedObjectMap::iterator iter(delayedObjectMap.begin()); iter != delayedObjectMap.end(); ++iter) { + derefObject(iter->second, iter->first); + } + delayedObjectMap.clear(); +} + +static void derefDelayedObjectsInCurrentThread(void*) +{ + (*threadSpecificDOMData).setDelayedProcessingScheduled(false); + derefDelayedObjects(); +} + +template<typename T> +static void removeObjectsFromWrapperMap(DOMWrapperMap<T>& domMap) +{ + for (typename WTF::HashMap<T*, v8::Object*>::iterator iter(domMap.impl().begin()); iter != domMap.impl().end(); ++iter) { + T* domObj = static_cast<T*>(iter->first); + v8::Persistent<v8::Object> obj(iter->second); + + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj)); + + // Deref the DOM object. + derefObject(type, domObj); + + // Clear the JS wrapper. + obj.Dispose(); + } + domMap.impl().clear(); +} + +static void removeAllDOMObjectsInCurrentThread() +{ + v8::Locker locker; + v8::HandleScope scope; + + // Deref all objects in the delayed queue. + derefDelayedObjects(); + + // Remove all DOM nodes. + removeObjectsFromWrapperMap<Node>(getDOMNodeMap()); + + // Remove all DOM objects in the wrapper map. + removeObjectsFromWrapperMap<void>(getDOMObjectMap()); + + // Remove all active DOM objects in the wrapper map. + removeObjectsFromWrapperMap<void>(getActiveDOMObjectMap()); + +#if ENABLE(SVG) + // Remove all SVG element instances in the wrapper map. + removeObjectsFromWrapperMap<SVGElementInstance>(getDOMSVGElementInstanceMap()); + + // Remove all SVG objects with context in the wrapper map. + removeObjectsFromWrapperMap<void>(getDOMSVGObjectWithContextMap()); +#endif +} + +} // namespace WebCore diff --git a/webkit/port/bindings/v8/V8DOMMap.h b/webkit/port/bindings/v8/V8DOMMap.h new file mode 100644 index 0000000..835f064 --- /dev/null +++ b/webkit/port/bindings/v8/V8DOMMap.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef V8DOMMap_h +#define V8DOMMap_h + +#include "dom_wrapper_map.h" + +namespace WebCore { + // Callback when JS wrapper of active DOM object is dead. + void weakActiveDOMObjectCallback(v8::Persistent<v8::Value> obj, void* domObj); + + // A map from DOM node to its JS wrapper. + DOMWrapperMap<Node>& getDOMNodeMap(); + + // A map from a DOM object (non-node) to its JS wrapper. This map does not contain the DOM objects which can have pending activity (active dom objects). + DOMWrapperMap<void>& getDOMObjectMap(); + + // A map from a DOM object to its JS wrapper for DOM objects which can have pending activity. + DOMWrapperMap<void>& getActiveDOMObjectMap(); + +#if ENABLE(SVG) + // A map for SVGElementInstances to its JS wrapper. + DOMWrapperMap<SVGElementInstance>& getDOMSVGElementInstanceMap(); + + // Map of SVG objects with contexts to V8 objects + DOMWrapperMap<void>& getDOMSVGObjectWithContextMap(); +#endif +} // namespace WebCore + +#endif // V8DOMMap_h diff --git a/webkit/port/bindings/v8/v8_proxy.cpp b/webkit/port/bindings/v8/v8_proxy.cpp index ca00058..3f9e4da 100644 --- a/webkit/port/bindings/v8/v8_proxy.cpp +++ b/webkit/port/bindings/v8/v8_proxy.cpp @@ -36,7 +36,6 @@ #include <v8-debug.h> #include "v8_proxy.h" -#include "dom_wrapper_map.h" #include "v8_index.h" #include "v8_binding.h" #include "v8_custom.h" @@ -45,206 +44,12 @@ #include "V8DOMWindow.h" #include "ChromiumBridge.h" - -#include "BarInfo.h" -#include "CanvasGradient.h" -#include "CanvasPattern.h" -#include "CanvasPixelArray.h" -#include "CanvasRenderingContext2D.h" -#include "CanvasStyle.h" -#include "CharacterData.h" -#include "ClientRect.h" -#include "ClientRectList.h" -#include "Clipboard.h" -#include "Console.h" -#include "Counter.h" -#include "CSSCharsetRule.h" -#include "CSSFontFaceRule.h" -#include "CSSImportRule.h" -#include "CSSMediaRule.h" -#include "CSSPageRule.h" -#include "CSSRule.h" -#include "CSSRuleList.h" -#include "CSSValueList.h" -#include "CSSStyleRule.h" -#include "CSSStyleSheet.h" -#include "CSSVariablesDeclaration.h" -#include "CSSVariablesRule.h" -#include "Database.h" -#include "DocumentType.h" -#include "DocumentFragment.h" -#include "DOMCoreException.h" -#include "DOMImplementation.h" -#include "DOMParser.h" -#include "DOMSelection.h" -#include "DOMStringList.h" -#include "DOMWindow.h" -#include "Entity.h" -#include "EventListener.h" -#include "EventTarget.h" -#include "Event.h" -#include "EventException.h" -#include "ExceptionCode.h" -#include "File.h" -#include "FileList.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameTree.h" -#include "History.h" -#include "HTMLNames.h" -#include "HTMLDocument.h" -#include "HTMLElement.h" -#include "HTMLImageElement.h" -#include "HTMLInputElement.h" -#include "HTMLSelectElement.h" -#include "HTMLOptionsCollection.h" -#include "ImageData.h" -#include "InspectorController.h" -#include "KeyboardEvent.h" -#include "Location.h" -#include "MediaError.h" -#include "MediaList.h" -#include "MediaPlayer.h" -#include "MessageChannel.h" -#include "MessageEvent.h" -#include "MessagePort.h" -#include "MimeTypeArray.h" -#include "MouseEvent.h" -#include "MutationEvent.h" -#include "Navigator.h" // for MimeTypeArray -#include "NodeFilter.h" -#include "Notation.h" -#include "NodeList.h" -#include "NodeIterator.h" -#include "OverflowEvent.h" -#include "Page.h" -#include "Plugin.h" -#include "PluginArray.h" -#include "ProcessingInstruction.h" -#include "ProgressEvent.h" -#include "Range.h" -#include "RangeException.h" -#include "Rect.h" -#include "RGBColor.h" -#include "Screen.h" -#include "ScriptExecutionContext.h" -#include "SecurityOrigin.h" -#include "Settings.h" -#include "SQLTransaction.h" -#include "SQLResultSet.h" -#include "SQLResultSetRowList.h" -#include "StyleSheet.h" -#include "StyleSheetList.h" -#include "SVGColor.h" -#include "SVGPaint.h" -#include "TextEvent.h" -#include "TextMetrics.h" -#include "TimeRanges.h" -#include "TreeWalker.h" -#include "XSLTProcessor.h" -#include "V8AbstractEventListener.h" -#include "V8CustomEventListener.h" -#include "V8DOMWindow.h" -#include "V8HTMLElement.h" -#include "V8LazyEventListener.h" -#include "V8ObjectEventListener.h" -#include "WebKitAnimationEvent.h" -#include "WebKitCSSKeyframeRule.h" -#include "WebKitCSSKeyframesRule.h" -#include "WebKitCSSMatrix.h" -#include "WebKitCSSTransformValue.h" -#include "WebKitPoint.h" -#include "WebKitTransitionEvent.h" -#include "WheelEvent.h" -#include "XMLHttpRequest.h" -#include "XMLHttpRequestException.h" -#include "XMLHttpRequestProgressEvent.h" -#include "XMLHttpRequestUpload.h" -#include "XMLSerializer.h" -#include "XPathException.h" -#include "XPathExpression.h" -#include "XPathNSResolver.h" -#include "XPathResult.h" - +#include "DOMObjectsInclude.h" #include "ScriptController.h" -#if ENABLE(SVG) -#include "SVGAngle.h" -#include "SVGAnimatedPoints.h" -#include "SVGElement.h" -#include "SVGElementInstance.h" -#include "SVGElementInstanceList.h" -#include "SVGException.h" -#include "SVGLength.h" -#include "SVGLengthList.h" -#include "SVGNumberList.h" -#include "SVGPathSeg.h" -#include "SVGPathSegArc.h" -#include "SVGPathSegClosePath.h" -#include "SVGPathSegCurvetoCubic.h" -#include "SVGPathSegCurvetoCubicSmooth.h" -#include "SVGPathSegCurvetoQuadratic.h" -#include "SVGPathSegCurvetoQuadraticSmooth.h" -#include "SVGPathSegLineto.h" -#include "SVGPathSegLinetoHorizontal.h" -#include "SVGPathSegLinetoVertical.h" -#include "SVGPathSegList.h" -#include "SVGPathSegMoveto.h" -#include "SVGPointList.h" -#include "SVGPreserveAspectRatio.h" -#include "SVGRenderingIntent.h" -#include "SVGStringList.h" -#include "SVGTransform.h" -#include "SVGTransformList.h" -#include "SVGUnitTypes.h" -#include "SVGURIReference.h" -#include "SVGZoomEvent.h" -#include "V8SVGPODTypeWrapper.h" -#endif // SVG - -#if ENABLE(WORKERS) -#include "Worker.h" -#include "WorkerContext.h" -#include "WorkerLocation.h" -#include "WorkerNavigator.h" -#endif // WORKERS - -#if ENABLE(XPATH) -#include "XPathEvaluator.h" -#endif - - namespace WebCore { - -// DOM binding algorithm: -// -// There are two kinds of DOM objects: -// 1. DOM tree nodes, such as Document, HTMLElement, ... -// there classes implements TreeShared<T> interface; -// 2. Non-node DOM objects, such as CSSRule, Location, etc. -// these classes implement a ref-counted scheme. -// -// A DOM object may have a JS wrapper object. If a tree node -// is alive, its JS wrapper must be kept alive even it is not -// reachable from JS roots. -// However, JS wrappers of non-node objects can go away if -// not reachable from other JS objects. It works like a cache. -// -// DOM objects are ref-counted, and JS objects are traced from -// a set of root objects. They can create a cycle. To break -// cycles, we do following: -// Handles from DOM objects to JS wrappers are always weak, -// so JS wrappers of non-node object cannot create a cycle. -// Before starting a global GC, we create a virtual connection -// between nodes in the same tree in the JS heap. If the wrapper -// of one node in a tree is alive, wrappers of all nodes in -// the same tree are considered alive. This is done by creating -// object groups in GC prologue callbacks. The mark-compact -// collector will remove these groups after each GC. - - // Static utility context. v8::Persistent<v8::Context> V8Proxy::m_utilityContext; @@ -252,10 +57,6 @@ v8::Persistent<v8::Context> V8Proxy::m_utilityContext; V8ExtensionList V8Proxy::m_extensions; -// A helper class for undetectable document.all -class UndetectableHTMLCollection : public HTMLCollection { -}; - #ifndef NDEBUG // Keeps track of global handles created (not JS wrappers // of DOM objects). Often these global handles are source @@ -385,66 +186,14 @@ static void EnumerateDOMNodeMap(DOMNodeMap& node_map) } #endif // NDEBUG -static void WeakDOMObjectCallback(v8::Persistent<v8::Value> obj, void* para); -static void WeakActiveDOMObjectCallback(v8::Persistent<v8::Value> obj, - void* para); -static void WeakNodeCallback(v8::Persistent<v8::Value> obj, void* para); -// A map from DOM node to its JS wrapper. -static DOMWrapperMap<Node>& GetDOMNodeMap() -{ - static DOMWrapperMap<Node> static_dom_node_map(&WeakNodeCallback); - return static_dom_node_map; -} - - -// A map from a DOM object (non-node) to its JS wrapper. This map does not -// contain the DOM objects which can have pending activity (active dom objects). -DOMWrapperMap<void>& GetDOMObjectMap() -{ - static DOMWrapperMap<void> - static_dom_object_map(&WeakDOMObjectCallback); - return static_dom_object_map; -} - - -// A map from a DOM object to its JS wrapper for DOM objects which -// can have pending activity. -static DOMWrapperMap<void>& GetActiveDOMObjectMap() -{ - static DOMWrapperMap<void> - static_active_dom_object_map(&WeakActiveDOMObjectCallback); - return static_active_dom_object_map; -} - #if ENABLE(SVG) -static void WeakSVGElementInstanceCallback(v8::Persistent<v8::Value> obj, - void* param); - -// A map for SVGElementInstances. -static DOMWrapperMap<SVGElementInstance>& dom_svg_element_instance_map() -{ - static DOMWrapperMap<SVGElementInstance> - static_dom_svg_element_instance_map(&WeakSVGElementInstanceCallback); - return static_dom_svg_element_instance_map; -} - -static void WeakSVGElementInstanceCallback(v8::Persistent<v8::Value> obj, - void* param) -{ - SVGElementInstance* instance = static_cast<SVGElementInstance*>(param); - ASSERT(dom_svg_element_instance_map().contains(instance)); - - instance->deref(); - dom_svg_element_instance_map().forget(instance); -} - v8::Handle<v8::Value> V8Proxy::SVGElementInstanceToV8Object( SVGElementInstance* instance) { if (!instance) return v8::Null(); - v8::Handle<v8::Object> existing_instance = dom_svg_element_instance_map().get(instance); + v8::Handle<v8::Object> existing_instance = getDOMSVGElementInstanceMap().get(instance); if (!existing_instance.IsEmpty()) return existing_instance; @@ -457,32 +206,12 @@ v8::Handle<v8::Value> V8Proxy::SVGElementInstanceToV8Object( instance); if (!result.IsEmpty()) { // Only update the DOM SVG element map if the result is non-empty. - dom_svg_element_instance_map().set(instance, + getDOMSVGElementInstanceMap().set(instance, v8::Persistent<v8::Object>::New(result)); } return result; } - -// SVG non-node elements may have a reference to a context node which -// should be notified when the element is change -static void WeakSVGObjectWithContext(v8::Persistent<v8::Value> obj, - void* dom_obj); - -// Map of SVG objects with contexts to V8 objects -static DOMWrapperMap<void>& dom_svg_object_with_context_map() { - static DOMWrapperMap<void> - static_dom_svg_object_with_context_map(&WeakSVGObjectWithContext); - return static_dom_svg_object_with_context_map; -} - -// Map of SVG objects with contexts to their contexts -static HashMap<void*, SVGElement*>& svg_object_to_context_map() -{ - static HashMap<void*, SVGElement*> static_svg_object_to_context_map; - return static_svg_object_to_context_map; -} - v8::Handle<v8::Value> V8Proxy::SVGObjectWithContextToV8Object( V8ClassIndex::V8WrapperType type, void* object) { @@ -490,7 +219,7 @@ v8::Handle<v8::Value> V8Proxy::SVGObjectWithContextToV8Object( return v8::Null(); v8::Persistent<v8::Object> result = - dom_svg_object_with_context_map().get(object); + getDOMSVGObjectWithContextMap().get(object); if (!result.IsEmpty()) return result; // Special case: SVGPathSegs need to be downcast to their real type @@ -513,38 +242,16 @@ SVG_POD_NATIVE_TYPES(MAKE_CASE) default: ASSERT(false); } - dom_svg_object_with_context_map().set(object, result); + getDOMSVGObjectWithContextMap().set(object, result); } return result; } -static void WeakSVGObjectWithContext(v8::Persistent<v8::Value> obj, - void* dom_obj) -{ - v8::HandleScope handle_scope; - ASSERT(dom_svg_object_with_context_map().contains(dom_obj)); - ASSERT(obj->IsObject()); - - // Forget function removes object from the map and dispose the wrapper. - dom_svg_object_with_context_map().forget(dom_obj); - - V8ClassIndex::V8WrapperType type = - V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj)); - - switch (type) { -#define MAKE_CASE(TYPE, NAME) \ - case V8ClassIndex::TYPE: static_cast<NAME*>(dom_obj)->deref(); break; -SVG_OBJECT_TYPES(MAKE_CASE) -#undef MAKE_CASE -#define MAKE_CASE(TYPE, NAME) \ - case V8ClassIndex::TYPE: \ - static_cast<V8SVGPODTypeWrapper<NAME>*>(dom_obj)->deref(); break; -SVG_POD_NATIVE_TYPES(MAKE_CASE) -#undef MAKE_CASE - default: - ASSERT(false); - } +// Map of SVG objects with contexts to their contexts +static HashMap<void*, SVGElement*>& svg_object_to_context_map() { + static HashMap<void*, SVGElement*> static_svg_object_to_context_map; + return static_svg_object_to_context_map; } void V8Proxy::SetSVGContext(void* obj, SVGElement* context) @@ -567,66 +274,8 @@ SVGElement* V8Proxy::GetSVGContext(void* obj) { return svg_object_to_context_map().get(obj); } - #endif -// Called when obj is near death (not reachable from JS roots) -// It is time to remove the entry from the table and dispose -// the handle. -static void WeakDOMObjectCallback(v8::Persistent<v8::Value> obj, - void* dom_obj) { - v8::HandleScope scope; - ASSERT(GetDOMObjectMap().contains(dom_obj)); - ASSERT(obj->IsObject()); - - // Forget function removes object from the map and dispose the wrapper. - GetDOMObjectMap().forget(dom_obj); - - V8ClassIndex::V8WrapperType type = - V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj)); - switch (type) { -#define MAKE_CASE(TYPE, NAME) \ - case V8ClassIndex::TYPE: static_cast<NAME*>(dom_obj)->deref(); break; - DOM_OBJECT_TYPES(MAKE_CASE) -#undef MAKE_CASE - default: - ASSERT(false); - } -} - - -static void WeakActiveDOMObjectCallback(v8::Persistent<v8::Value> obj, - void* dom_obj) -{ - v8::HandleScope scope; - ASSERT(GetActiveDOMObjectMap().contains(dom_obj)); - ASSERT(obj->IsObject()); - - // Forget function removes object from the map and dispose the wrapper. - GetActiveDOMObjectMap().forget(dom_obj); - - V8ClassIndex::V8WrapperType type = - V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj)); - switch (type) { -#define MAKE_CASE(TYPE, NAME) \ - case V8ClassIndex::TYPE: static_cast<NAME*>(dom_obj)->deref(); break; - ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) -#undef MAKE_CASE - default: - ASSERT(false); - } -} - -static void WeakNodeCallback(v8::Persistent<v8::Value> obj, void* param) -{ - Node* node = static_cast<Node*>(param); - ASSERT(GetDOMNodeMap().contains(node)); - - GetDOMNodeMap().forget(node); - node->deref(); -} - - // A map from a DOM node to its JS wrapper, the wrapper // is kept as a strong reference to survive GCs. static DOMObjectMap& gc_protected_map() { @@ -641,11 +290,11 @@ void V8Proxy::GCProtect(void* dom_object) return; if (gc_protected_map().contains(dom_object)) return; - if (!GetDOMObjectMap().contains(dom_object)) + if (!getDOMObjectMap().contains(dom_object)) return; // Create a new (strong) persistent handle for the object. - v8::Persistent<v8::Object> wrapper = GetDOMObjectMap().get(dom_object); + v8::Persistent<v8::Object> wrapper = getDOMObjectMap().get(dom_object); if (wrapper.IsEmpty()) return; gc_protected_map().set(dom_object, *v8::Persistent<v8::Object>::New(wrapper)); @@ -672,12 +321,12 @@ static void GCPrologue() v8::HandleScope scope; #ifndef NDEBUG - EnumerateDOMObjectMap(GetDOMObjectMap().impl()); + EnumerateDOMObjectMap(getDOMObjectMap().impl()); #endif // Run through all objects with possible pending activity making their // wrappers non weak if there is pending activity. - DOMObjectMap active_map = GetActiveDOMObjectMap().impl(); + DOMObjectMap active_map = getActiveDOMObjectMap().impl(); for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end(); it != end; ++it) { void* obj = it->first; @@ -740,7 +389,7 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) typedef std::pair<uintptr_t, Node*> GrouperPair; typedef Vector<GrouperPair> GrouperList; - DOMNodeMap node_map = GetDOMNodeMap().impl(); + DOMNodeMap node_map = getDOMNodeMap().impl(); GrouperList grouper; grouper.reserveCapacity(node_map.size()); @@ -806,7 +455,7 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) group.reserveCapacity(next_key_index - i); for (; i < next_key_index; ++i) { v8::Persistent<v8::Value> wrapper = - GetDOMNodeMap().get(grouper[i].second); + getDOMNodeMap().get(grouper[i].second); if (!wrapper.IsEmpty()) group.append(wrapper); } @@ -825,7 +474,7 @@ static void GCEpilogue() // Run through all objects with pending activity making their wrappers weak // again. - DOMObjectMap active_map = GetActiveDOMObjectMap().impl(); + DOMObjectMap active_map = getActiveDOMObjectMap().impl(); for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end(); it != end; ++it) { void* obj = it->first; @@ -837,7 +486,7 @@ static void GCEpilogue() NAME* impl = static_cast<NAME*>(obj); \ if (impl->hasPendingActivity()) { \ ASSERT(!wrapper.IsWeak()); \ - wrapper.MakeWeak(impl, &WeakActiveDOMObjectCallback); \ + wrapper.MakeWeak(impl, &weakActiveDOMObjectCallback); \ } \ break; \ } @@ -850,8 +499,8 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) #ifndef NDEBUG // Check all survivals are weak. - EnumerateDOMObjectMap(GetDOMObjectMap().impl()); - EnumerateDOMNodeMap(GetDOMNodeMap().impl()); + EnumerateDOMObjectMap(getDOMObjectMap().impl()); + EnumerateDOMNodeMap(getDOMNodeMap().impl()); EnumerateDOMObjectMap(gc_protected_map()); EnumerateGlobalHandles(); #undef USE_VAR @@ -1113,8 +762,8 @@ void V8Proxy::DestroyGlobal() bool V8Proxy::DOMObjectHasJSWrapper(void* obj) { - return GetDOMObjectMap().contains(obj) || - GetActiveDOMObjectMap().contains(obj); + return getDOMObjectMap().contains(obj) || + getActiveDOMObjectMap().contains(obj); } @@ -1132,7 +781,7 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) default: break; } #endif - GetDOMObjectMap().set(obj, wrapper); + getDOMObjectMap().set(obj, wrapper); } // The caller must have increased obj's ref count. @@ -1148,14 +797,14 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) #undef MAKE_CASE } #endif - GetActiveDOMObjectMap().set(obj, wrapper); + getActiveDOMObjectMap().set(obj, wrapper); } // The caller must have increased node's ref count. void V8Proxy::SetJSWrapperForDOMNode(Node* node, v8::Persistent<v8::Object> wrapper) { ASSERT(MaybeDOMWrapper(wrapper)); - GetDOMNodeMap().set(node, wrapper); + getDOMNodeMap().set(node, wrapper); } PassRefPtr<EventListener> V8Proxy::createInlineEventListener( @@ -2632,8 +2281,8 @@ v8::Handle<v8::Value> V8Proxy::ToV8Object(V8ClassIndex::V8WrapperType type, void // Non DOM node v8::Persistent<v8::Object> result = is_active_dom_object ? - GetActiveDOMObjectMap().get(imp) : - GetDOMObjectMap().get(imp); + getActiveDOMObjectMap().get(imp) : + getDOMObjectMap().get(imp); if (result.IsEmpty()) { v8::Local<v8::Object> v8obj = InstantiateV8Object(type, type, imp); if (!v8obj.IsEmpty()) { @@ -3103,7 +2752,7 @@ v8::Handle<v8::Value> V8Proxy::EventToV8Object(Event* event) if (!event) return v8::Null(); - v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(event); + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(event); if (!wrapper.IsEmpty()) return wrapper; @@ -3162,7 +2811,7 @@ v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node) { if (!node) return v8::Null(); - v8::Handle<v8::Object> wrapper = GetDOMNodeMap().get(node); + v8::Handle<v8::Object> wrapper = getDOMNodeMap().get(node); if (!wrapper.IsEmpty()) return wrapper; @@ -3308,7 +2957,7 @@ v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target) // XMLHttpRequest is created within its JS counterpart. XMLHttpRequest* xhr = target->toXMLHttpRequest(); if (xhr) { - v8::Handle<v8::Object> wrapper = GetActiveDOMObjectMap().get(xhr); + v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(xhr); ASSERT(!wrapper.IsEmpty()); return wrapper; } @@ -3316,14 +2965,14 @@ v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target) // MessagePort is created within its JS counterpart MessagePort* port = target->toMessagePort(); if (port) { - v8::Handle<v8::Object> wrapper = GetActiveDOMObjectMap().get(port); + v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(port); ASSERT(!wrapper.IsEmpty()); return wrapper; } XMLHttpRequestUpload* upload = target->toXMLHttpRequestUpload(); if (upload) { - v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(upload); + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(upload); ASSERT(!wrapper.IsEmpty()); return wrapper; } @@ -3365,7 +3014,7 @@ v8::Handle<v8::Value> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet) { if (!sheet) return v8::Null(); - v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(sheet); + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(sheet); if (!wrapper.IsEmpty()) return wrapper; @@ -3397,7 +3046,7 @@ v8::Handle<v8::Value> V8Proxy::CSSValueToV8Object(CSSValue* value) { if (!value) return v8::Null(); - v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(value); + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(value); if (!wrapper.IsEmpty()) return wrapper; @@ -3434,7 +3083,7 @@ v8::Handle<v8::Value> V8Proxy::CSSRuleToV8Object(CSSRule* rule) { if (!rule) return v8::Null(); - v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(rule); + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(rule); if (!wrapper.IsEmpty()) return wrapper; diff --git a/webkit/port/bindings/v8/v8_proxy.h b/webkit/port/bindings/v8/v8_proxy.h index e403751..017293e 100644 --- a/webkit/port/bindings/v8/v8_proxy.h +++ b/webkit/port/bindings/v8/v8_proxy.h @@ -6,7 +6,6 @@ #define V8_PROXY_H__ #include <v8.h> -#include "dom_wrapper_map.h" #include "v8_index.h" #include "v8_custom.h" #include "v8_utility.h" @@ -16,6 +15,7 @@ #include "PlatformString.h" // for WebCore::String #include "ScriptSourceCode.h" // for WebCore::ScriptSourceCode #include "SecurityOrigin.h" // for WebCore::SecurityOrigin +#include "V8DOMMap.h" #include <wtf/Assertions.h> #include <wtf/PassRefPtr.h> // so generated bindings don't have to #include <wtf/Vector.h> @@ -29,6 +29,9 @@ #define INC_STATS(name) #endif +// FIXME: Remove the following hack when we replace all references to GetDOMObjectMap. +#define GetDOMObjectMap getDOMObjectMap + namespace WebCore { class CSSStyleDeclaration; @@ -144,8 +147,6 @@ void BatchConfigureConstants(v8::Handle<v8::FunctionTemplate> desc, const BatchedConstant* consts, size_t num_consts); -DOMWrapperMap<void>& GetDOMObjectMap(); - const int kMaxRecursionDepth = 20; // Information about an extension that is registered for use with V8. If scheme diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index 76c84b5..77a431a 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -1056,6 +1056,7 @@ 'extensions/v8/playback_extension.h', 'extensions/v8/profiler_extension.cc', 'extensions/v8/profiler_extension.h', + 'port/bindings/v8/DOMObjectsInclude.h', 'port/bindings/v8/JSDOMBinding.cpp', 'port/bindings/v8/JSDOMBinding.h', 'port/bindings/v8/JSXPathNSResolver.cpp', @@ -1065,6 +1066,8 @@ 'port/bindings/v8/ScriptController.cpp', 'port/bindings/v8/ScriptController.h', 'port/bindings/v8/V8CanvasPixelArrayCustom.cpp', + 'port/bindings/v8/V8DOMMap.cpp', + 'port/bindings/v8/V8DOMMap.h', 'port/bindings/v8/V8MessagePortCustom.cpp', 'port/bindings/v8/V8SVGPODTypeWrapper.h', 'port/bindings/v8/V8WorkerContextCustom.cpp', |