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 #ifndef DOMDataStore_h
32 #define DOMDataStore_h
33
34 #include "bindings/core/v8/DOMWrapperMap.h"
35 #include "bindings/core/v8/DOMWrapperWorld.h"
36 #include "bindings/core/v8/ScriptWrappable.h"
37 #include "bindings/core/v8/WrapperTypeInfo.h"
38 #include "wtf/Noncopyable.h"
39 #include "wtf/StdLibExtras.h"
40 #include <v8.h>
41
42 namespace blink {
43
44 class Node;
45
46 class DOMDataStore {
47 WTF_MAKE_NONCOPYABLE(DOMDataStore);
48 public:
49 explicit DOMDataStore(bool isMainWorld);
50 ~DOMDataStore();
51
52 static DOMDataStore& current(v8::Isolate*);
53
54 // We can use a wrapper stored in a ScriptWrappable when we're in the main world.
55 // This method does the fast check if we're in the main world. If this method returns true,
56 // it is guaranteed that we're in the main world. On the other hand, if this method returns
57 // false, nothing is guaranteed (we might be in the main world).
58 template<typename T>
canUseScriptWrappable(T * object)59 static bool canUseScriptWrappable(T* object)
60 {
61 return !DOMWrapperWorld::isolatedWorldsExist()
62 && !canExistInWorker(object)
63 && ScriptWrappable::wrapperCanBeStoredInObject(object);
64 }
65
canUseScriptWrappableNonTemplate(Node * object)66 static bool canUseScriptWrappableNonTemplate(Node* object)
67 {
68 // Node cannot exist in workers and a wrapper can be stored in Node
69 // which (indirectly) derives ScriptWrappable.
70 return !DOMWrapperWorld::isolatedWorldsExist();
71 }
72
73 template<typename V8T, typename T, typename Wrappable>
setReturnValueFromWrapperFast(v8::ReturnValue<v8::Value> returnValue,T * object,v8::Local<v8::Object> holder,Wrappable * wrappable)74 static bool setReturnValueFromWrapperFast(v8::ReturnValue<v8::Value> returnValue, T* object, v8::Local<v8::Object> holder, Wrappable* wrappable)
75 {
76 if (canUseScriptWrappable(object)) {
77 ScriptWrappable::assertWrapperSanity<V8T, T>(object, object);
78 return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
79 }
80 // The second fastest way to check if we're in the main world is to check if
81 // the wrappable's wrapper is the same as the holder.
82 // FIXME: Investigate if it's worth having this check for performance.
83 if (holderContainsWrapper(holder, wrappable)) {
84 if (ScriptWrappable::wrapperCanBeStoredInObject(object)) {
85 ScriptWrappable::assertWrapperSanity<V8T, T>(object, object);
86 return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
87 }
88 return DOMWrapperWorld::mainWorld().domDataStore().m_wrapperMap.setReturnValueFrom(returnValue, V8T::toScriptWrappableBase(object));
89 }
90 return current(returnValue.GetIsolate()).template setReturnValueFrom<V8T>(returnValue, object);
91 }
92
93 template<typename V8T, typename T>
setReturnValueFromWrapper(v8::ReturnValue<v8::Value> returnValue,T * object)94 static bool setReturnValueFromWrapper(v8::ReturnValue<v8::Value> returnValue, T* object)
95 {
96 if (canUseScriptWrappable(object)) {
97 ScriptWrappable::assertWrapperSanity<V8T, T>(object, object);
98 return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
99 }
100 return current(returnValue.GetIsolate()).template setReturnValueFrom<V8T>(returnValue, object);
101 }
102
103 template<typename V8T, typename T>
setReturnValueFromWrapperForMainWorld(v8::ReturnValue<v8::Value> returnValue,T * object)104 static bool setReturnValueFromWrapperForMainWorld(v8::ReturnValue<v8::Value> returnValue, T* object)
105 {
106 if (ScriptWrappable::wrapperCanBeStoredInObject(object))
107 return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
108 return DOMWrapperWorld::mainWorld().domDataStore().m_wrapperMap.setReturnValueFrom(returnValue, V8T::toScriptWrappableBase(object));
109 }
110
111 template<typename V8T, typename T>
getWrapper(T * object,v8::Isolate * isolate)112 static v8::Handle<v8::Object> getWrapper(T* object, v8::Isolate* isolate)
113 {
114 if (canUseScriptWrappable(object)) {
115 v8::Handle<v8::Object> result = ScriptWrappable::fromObject(object)->newLocalWrapper(isolate);
116 // Security: always guard against malicious tampering.
117 ScriptWrappable::assertWrapperSanity<V8T, T>(result, object);
118 return result;
119 }
120 return current(isolate).template get<V8T>(object, isolate);
121 }
122
getWrapperNonTemplate(ScriptWrappableBase * object,v8::Isolate * isolate)123 static v8::Handle<v8::Object> getWrapperNonTemplate(ScriptWrappableBase* object, v8::Isolate* isolate)
124 {
125 return current(isolate).getNonTemplate(object, isolate);
126 }
127
getWrapperNonTemplate(ScriptWrappable * object,v8::Isolate * isolate)128 static v8::Handle<v8::Object> getWrapperNonTemplate(ScriptWrappable* object, v8::Isolate* isolate)
129 {
130 return current(isolate).getNonTemplate(object, isolate);
131 }
132
getWrapperNonTemplate(Node * node,v8::Isolate * isolate)133 static v8::Handle<v8::Object> getWrapperNonTemplate(Node* node, v8::Isolate* isolate)
134 {
135 if (canUseScriptWrappableNonTemplate(node)) {
136 v8::Handle<v8::Object> result = ScriptWrappable::fromObject(node)->newLocalWrapper(isolate);
137 // Security: always guard against malicious tampering.
138 ScriptWrappable::fromObject(node)->assertWrapperSanity(result);
139 return result;
140 }
141 return current(isolate).getNonTemplate(ScriptWrappable::fromObject(node), isolate);
142 }
143
144 template<typename V8T, typename T>
setWrapperReference(const v8::Persistent<v8::Object> & parent,T * child,v8::Isolate * isolate)145 static void setWrapperReference(const v8::Persistent<v8::Object>& parent, T* child, v8::Isolate* isolate)
146 {
147 if (canUseScriptWrappable(child)) {
148 ScriptWrappable::assertWrapperSanity<V8T, T>(child, child);
149 ScriptWrappable::fromObject(child)->setReference(parent, isolate);
150 return;
151 }
152 current(isolate).template setReference<V8T>(parent, child, isolate);
153 }
154
155 template<typename V8T, typename T>
setWrapper(T * object,v8::Handle<v8::Object> wrapper,v8::Isolate * isolate,const WrapperTypeInfo * wrapperTypeInfo)156 static void setWrapper(T* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
157 {
158 if (canUseScriptWrappable(object)) {
159 ScriptWrappable::fromObject(object)->setWrapper(wrapper, isolate, wrapperTypeInfo);
160 return;
161 }
162 return current(isolate).template set<V8T>(object, wrapper, isolate, wrapperTypeInfo);
163 }
164
setWrapperNonTemplate(ScriptWrappableBase * object,v8::Handle<v8::Object> wrapper,v8::Isolate * isolate,const WrapperTypeInfo * wrapperTypeInfo)165 static void setWrapperNonTemplate(ScriptWrappableBase* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
166 {
167 return current(isolate).setNonTemplate(object, wrapper, isolate, wrapperTypeInfo);
168 }
169
setWrapperNonTemplate(ScriptWrappable * object,v8::Handle<v8::Object> wrapper,v8::Isolate * isolate,const WrapperTypeInfo * wrapperTypeInfo)170 static void setWrapperNonTemplate(ScriptWrappable* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
171 {
172 return current(isolate).setNonTemplate(object, wrapper, isolate, wrapperTypeInfo);
173 }
174
setWrapperNonTemplate(Node * node,v8::Handle<v8::Object> wrapper,v8::Isolate * isolate,const WrapperTypeInfo * wrapperTypeInfo)175 static void setWrapperNonTemplate(Node* node, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
176 {
177 if (canUseScriptWrappableNonTemplate(node)) {
178 ScriptWrappable::fromObject(node)->setWrapper(wrapper, isolate, wrapperTypeInfo);
179 return;
180 }
181 return current(isolate).setNonTemplate(ScriptWrappable::fromObject(node), wrapper, isolate, wrapperTypeInfo);
182 }
183
184 template<typename V8T, typename T>
containsWrapper(T * object,v8::Isolate * isolate)185 static bool containsWrapper(T* object, v8::Isolate* isolate)
186 {
187 return current(isolate).template containsWrapper<V8T>(object);
188 }
189
containsWrapperNonTemplate(ScriptWrappableBase * object,v8::Isolate * isolate)190 static bool containsWrapperNonTemplate(ScriptWrappableBase* object, v8::Isolate* isolate)
191 {
192 return current(isolate).containsWrapperNonTemplate(object);
193 }
194
containsWrapperNonTemplate(ScriptWrappable * object,v8::Isolate * isolate)195 static bool containsWrapperNonTemplate(ScriptWrappable* object, v8::Isolate* isolate)
196 {
197 return current(isolate).containsWrapperNonTemplate(object);
198 }
199
200 template<typename V8T, typename T>
get(T * object,v8::Isolate * isolate)201 v8::Handle<v8::Object> get(T* object, v8::Isolate* isolate)
202 {
203 if (ScriptWrappable::wrapperCanBeStoredInObject(object) && m_isMainWorld)
204 return ScriptWrappable::fromObject(object)->newLocalWrapper(isolate);
205 return m_wrapperMap.newLocal(V8T::toScriptWrappableBase(object), isolate);
206 }
207
getNonTemplate(ScriptWrappableBase * object,v8::Isolate * isolate)208 v8::Handle<v8::Object> getNonTemplate(ScriptWrappableBase* object, v8::Isolate* isolate)
209 {
210 return m_wrapperMap.newLocal(object->toScriptWrappableBase(), isolate);
211 }
212
getNonTemplate(ScriptWrappable * object,v8::Isolate * isolate)213 v8::Handle<v8::Object> getNonTemplate(ScriptWrappable* object, v8::Isolate* isolate)
214 {
215 if (m_isMainWorld)
216 return object->newLocalWrapper(isolate);
217 return m_wrapperMap.newLocal(object->toScriptWrappableBase(), isolate);
218 }
219
220 template<typename V8T, typename T>
setReference(const v8::Persistent<v8::Object> & parent,T * child,v8::Isolate * isolate)221 void setReference(const v8::Persistent<v8::Object>& parent, T* child, v8::Isolate* isolate)
222 {
223 if (ScriptWrappable::wrapperCanBeStoredInObject(child) && m_isMainWorld) {
224 ScriptWrappable::fromObject(child)->setReference(parent, isolate);
225 return;
226 }
227 m_wrapperMap.setReference(parent, V8T::toScriptWrappableBase(child), isolate);
228 }
229
230 template<typename V8T, typename T>
setReturnValueFrom(v8::ReturnValue<v8::Value> returnValue,T * object)231 bool setReturnValueFrom(v8::ReturnValue<v8::Value> returnValue, T* object)
232 {
233 if (ScriptWrappable::wrapperCanBeStoredInObject(object) && m_isMainWorld)
234 return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
235 return m_wrapperMap.setReturnValueFrom(returnValue, V8T::toScriptWrappableBase(object));
236 }
237
238 template<typename V8T, typename T>
containsWrapper(T * object)239 bool containsWrapper(T* object)
240 {
241 if (ScriptWrappable::wrapperCanBeStoredInObject(object) && m_isMainWorld)
242 return ScriptWrappable::fromObject(object)->containsWrapper();
243 return m_wrapperMap.containsKey(V8T::toScriptWrappableBase(object));
244 }
245
containsWrapperNonTemplate(ScriptWrappableBase * object)246 bool containsWrapperNonTemplate(ScriptWrappableBase* object)
247 {
248 return m_wrapperMap.containsKey(object->toScriptWrappableBase());
249 }
250
containsWrapperNonTemplate(ScriptWrappable * object)251 bool containsWrapperNonTemplate(ScriptWrappable* object)
252 {
253 if (m_isMainWorld)
254 return object->containsWrapper();
255 return m_wrapperMap.containsKey(object->toScriptWrappableBase());
256 }
257
258 private:
259 template<typename V8T, typename T>
set(T * object,v8::Handle<v8::Object> wrapper,v8::Isolate * isolate,const WrapperTypeInfo * wrapperTypeInfo)260 void set(T* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
261 {
262 ASSERT(object);
263 ASSERT(!wrapper.IsEmpty());
264 if (ScriptWrappable::wrapperCanBeStoredInObject(object) && m_isMainWorld) {
265 ScriptWrappable::fromObject(object)->setWrapper(wrapper, isolate, wrapperTypeInfo);
266 return;
267 }
268 m_wrapperMap.set(V8T::toScriptWrappableBase(object), wrapper, wrapperTypeInfo);
269 }
270
setNonTemplate(ScriptWrappableBase * object,v8::Handle<v8::Object> wrapper,v8::Isolate * isolate,const WrapperTypeInfo * wrapperTypeInfo)271 void setNonTemplate(ScriptWrappableBase* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
272 {
273 ASSERT(object);
274 ASSERT(!wrapper.IsEmpty());
275 m_wrapperMap.set(object->toScriptWrappableBase(), wrapper, wrapperTypeInfo);
276 }
277
setNonTemplate(ScriptWrappable * object,v8::Handle<v8::Object> wrapper,v8::Isolate * isolate,const WrapperTypeInfo * wrapperTypeInfo)278 void setNonTemplate(ScriptWrappable* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
279 {
280 ASSERT(object);
281 ASSERT(!wrapper.IsEmpty());
282 if (m_isMainWorld) {
283 ScriptWrappable::fromObject(object)->setWrapper(wrapper, isolate, wrapperTypeInfo);
284 return;
285 }
286 m_wrapperMap.set(object->toScriptWrappableBase(), wrapper, wrapperTypeInfo);
287 }
288
canExistInWorker(void *)289 static bool canExistInWorker(void*) { return true; }
canExistInWorker(Node *)290 static bool canExistInWorker(Node*) { return false; }
291
holderContainsWrapper(v8::Local<v8::Object>,void *)292 static bool holderContainsWrapper(v8::Local<v8::Object>, void*)
293 {
294 return false;
295 }
296
holderContainsWrapper(v8::Local<v8::Object> holder,ScriptWrappable * wrappable)297 static bool holderContainsWrapper(v8::Local<v8::Object> holder, ScriptWrappable* wrappable)
298 {
299 // Verify our assumptions about the main world.
300 ASSERT(wrappable);
301 ASSERT(!wrappable->containsWrapper() || !wrappable->isEqualTo(holder) || current(v8::Isolate::GetCurrent()).m_isMainWorld);
302 return wrappable->isEqualTo(holder);
303 }
304
305 bool m_isMainWorld;
306 DOMWrapperMap<ScriptWrappableBase> m_wrapperMap;
307 };
308
309 template <>
Dispose(v8::Isolate * isolate,v8::UniquePersistent<v8::Object> value,ScriptWrappableBase * key)310 inline void DOMWrapperMap<ScriptWrappableBase>::PersistentValueMapTraits::Dispose(
311 v8::Isolate* isolate,
312 v8::UniquePersistent<v8::Object> value,
313 ScriptWrappableBase* key)
314 {
315 RELEASE_ASSERT(!value.IsEmpty()); // See crbug.com/368095.
316 releaseObject(v8::Local<v8::Object>::New(isolate, value));
317 }
318
319 } // namespace blink
320
321 #endif // DOMDataStore_h
322