• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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