tizen beta release
[profile/ivi/webkit-efl.git] / Source / WebCore / bindings / v8 / DOMDataStore.cpp
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "DOMDataStore.h"
33
34 #include "DOMData.h"
35 #include "V8Binding.h"
36 #include <wtf/MainThread.h>
37
38 namespace WebCore {
39
40 // DOM binding algorithm:
41 //
42 // There are two kinds of DOM objects:
43 // 1. DOM tree nodes, such as Document, HTMLElement, ...
44 //    there classes implement TreeShared<T> interface;
45 // 2. Non-node DOM objects, such as CSSRule, Location, etc.
46 //    these classes implement a ref-counted scheme.
47 //
48 // A DOM object may have a JS wrapper object. If a tree node
49 // is alive, its JS wrapper must be kept alive even it is not
50 // reachable from JS roots.
51 // However, JS wrappers of non-node objects can go away if
52 // not reachable from other JS objects. It works like a cache.
53 //
54 // DOM objects are ref-counted, and JS objects are traced from
55 // a set of root objects. They can create a cycle. To break
56 // cycles, we do following:
57 //   Handles from DOM objects to JS wrappers are always weak,
58 // so JS wrappers of non-node object cannot create a cycle.
59 //   Before starting a global GC, we create a virtual connection
60 // between nodes in the same tree in the JS heap. If the wrapper
61 // of one node in a tree is alive, wrappers of all nodes in
62 // the same tree are considered alive. This is done by creating
63 // object groups in GC prologue callbacks. The mark-compact
64 // collector will remove these groups after each GC.
65 //
66 // DOM objects should be deref-ed from the owning thread, not the GC thread
67 // that does not own them. In V8, GC can kick in from any thread. To ensure
68 // that DOM objects are always deref-ed from the owning thread when running
69 // V8 in multi-threading environment, we do following:
70 // 1. Maintain a thread specific DOM wrapper map for each object map.
71 //    (We're using TLS support from WTF instead of base since V8Bindings
72 //     does not depend on base. We further assume that all child threads
73 //     running V8 instances are created by WTF and thus a destructor will
74 //     be called to clean up all thread specific data.)
75 // 2. When GC happens:
76 //    2.1. If the dead object is in GC thread's map, remove the JS reference
77 //         and deref the DOM object.
78 //    2.2. Otherwise, go through all thread maps to find the owning thread.
79 //         Remove the JS reference from the owning thread's map and move the
80 //         DOM object to a delayed queue. Post a task to the owning thread
81 //         to have it deref-ed from the owning thread at later time.
82 // 3. When a thread is tearing down, invoke a cleanup routine to go through
83 //    all objects in the delayed queue and the thread map and deref all of
84 //    them.
85
86
87 DOMDataStore::DOMDataStore()
88     : m_domNodeMap(0)
89     , m_activeDomNodeMap(0)
90     , m_domObjectMap(0)
91     , m_activeDomObjectMap(0)
92 #if ENABLE(SVG)
93     , m_domSvgElementInstanceMap(0)
94 #endif
95 {
96 }
97
98 DOMDataStore::~DOMDataStore()
99 {
100 }
101
102 DOMDataList& DOMDataStore::allStores()
103 {
104     return V8BindingPerIsolateData::current()->allStores();
105 }
106
107 void* DOMDataStore::getDOMWrapperMap(DOMWrapperMapType type)
108 {
109     switch (type) {
110     case DOMNodeMap:
111         return m_domNodeMap;
112     case ActiveDOMNodeMap:
113         return m_activeDomNodeMap;
114     case DOMObjectMap:
115         return m_domObjectMap;
116     case ActiveDOMObjectMap:
117         return m_activeDomObjectMap;
118 #if ENABLE(SVG)
119     case DOMSVGElementInstanceMap:
120         return m_domSvgElementInstanceMap;
121 #endif
122     }
123
124     ASSERT_NOT_REACHED();
125     return 0;
126 }
127
128 // Called when the object is near death (not reachable from JS roots).
129 // It is time to remove the entry from the table and dispose the handle.
130 void DOMDataStore::weakDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
131 {
132     v8::HandleScope scope;
133     ASSERT(v8Object->IsObject());
134     DOMData::handleWeakObject(DOMDataStore::DOMObjectMap, v8::Persistent<v8::Object>::Cast(v8Object), domObject);
135 }
136
137 void DOMDataStore::weakActiveDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
138 {
139     v8::HandleScope scope;
140     ASSERT(v8Object->IsObject());
141     DOMData::handleWeakObject(DOMDataStore::ActiveDOMObjectMap, v8::Persistent<v8::Object>::Cast(v8Object), domObject);
142 }
143
144 void DOMDataStore::weakNodeCallback(v8::Persistent<v8::Value> value, void* domObject)
145 {
146     ASSERT(isMainThread());
147
148     Node* node = static_cast<Node*>(domObject);
149     // Node wrappers must be JS objects.
150     v8::Persistent<v8::Object> v8Object = v8::Persistent<v8::Object>::Cast(value);
151
152     DOMDataList& list = DOMDataStore::allStores();
153     for (size_t i = 0; i < list.size(); ++i) {
154         DOMDataStore* store = list[i];
155         DOMNodeMapping& nodeMap = node->isActiveNode() ? store->activeDomNodeMap() : store->domNodeMap();
156         if (nodeMap.removeIfPresent(node, v8Object)) {
157             node->deref(); // Nobody overrides Node::deref so it's safe
158             return; // There might be at most one wrapper for the node in world's maps
159         }
160     }
161
162     // If not found, it means map for the wrapper has been already destroyed, just dispose the
163     // handle and deref the object to fight memory leak.
164     v8Object.Dispose();
165     node->deref(); // Nobody overrides Node::deref so it's safe
166 }
167
168 #if ENABLE(SVG)
169
170 void DOMDataStore::weakSVGElementInstanceCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
171 {
172     v8::HandleScope scope;
173     ASSERT(v8Object->IsObject());
174     DOMData::handleWeakObject(DOMDataStore::DOMSVGElementInstanceMap, v8::Persistent<v8::Object>::Cast(v8Object), static_cast<SVGElementInstance*>(domObject));
175 }
176
177 #endif  // ENABLE(SVG)
178
179 } // namespace WebCore