OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2010 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 18 matching lines...) Expand all Loading... | |
29 */ | 29 */ |
30 | 30 |
31 #ifndef ScriptWrappable_h | 31 #ifndef ScriptWrappable_h |
32 #define ScriptWrappable_h | 32 #define ScriptWrappable_h |
33 | 33 |
34 #include "bindings/core/v8/WrapperTypeInfo.h" | 34 #include "bindings/core/v8/WrapperTypeInfo.h" |
35 #include "platform/ScriptForbiddenScope.h" | 35 #include "platform/ScriptForbiddenScope.h" |
36 #include "platform/heap/Handle.h" | 36 #include "platform/heap/Handle.h" |
37 #include <v8.h> | 37 #include <v8.h> |
38 | 38 |
39 // Helper to call webCoreInitializeScriptWrappableForInterface in the global nam espace. | |
40 template <class C> inline void initializeScriptWrappableHelper(C* object) | |
41 { | |
42 void webCoreInitializeScriptWrappableForInterface(C*); | |
43 webCoreInitializeScriptWrappableForInterface(object); | |
44 } | |
45 | |
46 namespace blink { | 39 namespace blink { |
47 | 40 |
48 /** | 41 /** |
49 * The base class of all wrappable objects. | 42 * The base class of all wrappable objects. |
50 * | 43 * |
51 * This class provides the internal pointer to be stored in the wrapper objects, | 44 * This class provides the internal pointer to be stored in the wrapper objects, |
52 * and its conversions from / to the DOM instances. | 45 * and its conversions from / to the DOM instances. |
53 * | 46 * |
54 * Note that this class must not have vtbl (any virtual function) or any member | 47 * Note that this class must not have vtbl (any virtual function) or any member |
55 * variable which increase the size of instances. Some of the classes sensitive | 48 * variable which increase the size of instances. Some of the classes sensitive |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
100 { | 93 { |
101 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(object.IsEmpty() | 94 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(object.IsEmpty() |
102 || object->GetAlignedPointerFromInternalField(v8DOMWrapperObjectInde x) == toScriptWrappableBase()); | 95 || object->GetAlignedPointerFromInternalField(v8DOMWrapperObjectInde x) == toScriptWrappableBase()); |
103 } | 96 } |
104 }; | 97 }; |
105 | 98 |
106 /** | 99 /** |
107 * ScriptWrappable wraps a V8 object and its WrapperTypeInfo. | 100 * ScriptWrappable wraps a V8 object and its WrapperTypeInfo. |
108 * | 101 * |
109 * ScriptWrappable acts much like a v8::Persistent<> in that it keeps a | 102 * ScriptWrappable acts much like a v8::Persistent<> in that it keeps a |
110 * V8 object alive. Under the hood, however, it keeps either a TypeInfo | 103 * V8 object alive. |
111 * object or an actual v8 persistent (or is empty). | |
112 * | |
113 * The physical state space of ScriptWrappable is: | |
114 * - uintptr_t m_wrapperOrTypeInfo; | |
115 * - if 0: the ScriptWrappable is uninitialized/empty. | |
116 * - if even: a pointer to blink::TypeInfo | |
117 * - if odd: a pointer to v8::Persistent<v8::Object> + 1. | |
118 * | |
119 * In other words, one integer represents one of two object pointers, | |
120 * depending on its least signficiant bit, plus an uninitialized state. | |
121 * This class is meant to mask the logistics behind this. | |
122 * | |
123 * typeInfo() and newLocalWrapper will return appropriate values (possibly | |
124 * 0/empty) in all physical states. | |
125 * | 104 * |
126 * The state transitions are: | 105 * The state transitions are: |
127 * - new: an empty and invalid ScriptWrappable. | 106 * - new: an empty ScriptWrappable. |
128 * - init (to be called by all subclasses in their constructor): | |
129 * needs to call setTypeInfo | |
130 * - setTypeInfo: install a WrapperTypeInfo | |
131 * - setWrapper: install a v8::Persistent (or empty) | 107 * - setWrapper: install a v8::Persistent (or empty) |
132 * - disposeWrapper (via setWeakCallback, triggered by V8 garbage collecter): | 108 * - disposeWrapper (via setWeakCallback, triggered by V8 garbage collecter): |
133 * remove v8::Persistent and install a TypeInfo of the previous value. | 109 * remove v8::Persistent and become empty. |
134 */ | 110 */ |
135 class ScriptWrappable : public ScriptWrappableBase { | 111 class ScriptWrappable : public ScriptWrappableBase { |
136 public: | 112 public: |
137 ScriptWrappable() : m_wrapperOrTypeInfo(0) { } | 113 ScriptWrappable() : m_wrapper(0) { } |
138 | |
139 // Wrappables need to be initialized with their most derrived type for which | |
140 // bindings exist, in much the same way that certain other types need to be | |
141 // adopted and so forth. The overloaded initializeScriptWrappableForInterfac e() | |
142 // functions are implemented by the generated V8 bindings code. Declaring th e | |
143 // extern function in the template avoids making a centralized header of all | |
144 // the bindings in the universe. C++11's extern template feature may provide | |
145 // a cleaner solution someday. | |
146 template <class C> static void init(C* object) | |
147 { | |
148 initializeScriptWrappableHelper(object); | |
149 } | |
150 | 114 |
151 // Returns the WrapperTypeInfo of the instance. | 115 // Returns the WrapperTypeInfo of the instance. |
152 // | 116 // |
153 // This method must be overridden by DEFINE_WRAPPERTYPEINFO macro. | 117 // This method must be overridden by DEFINE_WRAPPERTYPEINFO macro. |
154 virtual const WrapperTypeInfo* wrapperTypeInfo() const = 0; | 118 virtual const WrapperTypeInfo* wrapperTypeInfo() const = 0; |
155 | 119 |
156 // Creates and returns a new wrapper object. | 120 // Creates and returns a new wrapper object. |
157 virtual v8::Handle<v8::Object> wrap(v8::Handle<v8::Object> creationContext, v8::Isolate*); | 121 virtual v8::Handle<v8::Object> wrap(v8::Handle<v8::Object> creationContext, v8::Isolate*); |
158 | 122 |
159 void setWrapper(v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo) | 123 void setWrapper(v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo) |
160 { | 124 { |
161 ASSERT(!containsWrapper()); | 125 ASSERT(!containsWrapper()); |
162 if (!*wrapper) { | 126 if (!*wrapper) { |
163 m_wrapperOrTypeInfo = 0; | 127 m_wrapper = 0; |
164 return; | 128 return; |
165 } | 129 } |
166 v8::Persistent<v8::Object> persistent(isolate, wrapper); | 130 v8::Persistent<v8::Object> persistent(isolate, wrapper); |
167 wrapperTypeInfo->configureWrapper(&persistent); | 131 wrapperTypeInfo->configureWrapper(&persistent); |
168 persistent.SetWeak(this, &setWeakCallback); | 132 persistent.SetWeak(this, &setWeakCallback); |
169 m_wrapperOrTypeInfo = reinterpret_cast<uintptr_t>(persistent.ClearAndLea k()) | 1; | 133 m_wrapper = persistent.ClearAndLeak(); |
170 ASSERT(containsWrapper()); | 134 ASSERT(containsWrapper()); |
171 } | 135 } |
172 | 136 |
173 v8::Local<v8::Object> newLocalWrapper(v8::Isolate* isolate) const | 137 v8::Local<v8::Object> newLocalWrapper(v8::Isolate* isolate) const |
174 { | 138 { |
175 v8::Persistent<v8::Object> persistent; | 139 v8::Persistent<v8::Object> persistent; |
176 getPersistent(&persistent); | 140 getPersistent(&persistent); |
177 return v8::Local<v8::Object>::New(isolate, persistent); | 141 return v8::Local<v8::Object>::New(isolate, persistent); |
178 } | 142 } |
179 | 143 |
180 const WrapperTypeInfo* typeInfo() | |
181 { | |
182 if (containsTypeInfo()) | |
183 return reinterpret_cast<const WrapperTypeInfo*>(m_wrapperOrTypeInfo) ; | |
184 | |
185 if (containsWrapper()) { | |
186 v8::Persistent<v8::Object> persistent; | |
187 getPersistent(&persistent); | |
188 return toWrapperTypeInfo(persistent); | |
189 } | |
190 | |
191 return 0; | |
192 } | |
193 | |
194 void setTypeInfo(const WrapperTypeInfo* typeInfo) | |
195 { | |
196 m_wrapperOrTypeInfo = reinterpret_cast<uintptr_t>(typeInfo); | |
197 ASSERT(containsTypeInfo()); | |
198 } | |
199 | |
200 bool isEqualTo(const v8::Local<v8::Object>& other) const | 144 bool isEqualTo(const v8::Local<v8::Object>& other) const |
201 { | 145 { |
202 v8::Persistent<v8::Object> persistent; | 146 v8::Persistent<v8::Object> persistent; |
203 getPersistent(&persistent); | 147 getPersistent(&persistent); |
204 return persistent == other; | 148 return persistent == other; |
205 } | 149 } |
206 | 150 |
207 static bool wrapperCanBeStoredInObject(const void*) { return false; } | 151 static bool wrapperCanBeStoredInObject(const void*) { return false; } |
208 static bool wrapperCanBeStoredInObject(const ScriptWrappable*) { return true ; } | 152 static bool wrapperCanBeStoredInObject(const ScriptWrappable*) { return true ; } |
209 | 153 |
(...skipping 14 matching lines...) Expand all Loading... | |
224 getPersistent(&persistent); | 168 getPersistent(&persistent); |
225 returnValue.Set(persistent); | 169 returnValue.Set(persistent); |
226 return containsWrapper(); | 170 return containsWrapper(); |
227 } | 171 } |
228 | 172 |
229 void markAsDependentGroup(ScriptWrappable* groupRoot, v8::Isolate* isolate) | 173 void markAsDependentGroup(ScriptWrappable* groupRoot, v8::Isolate* isolate) |
230 { | 174 { |
231 ASSERT(containsWrapper()); | 175 ASSERT(containsWrapper()); |
232 ASSERT(groupRoot && groupRoot->containsWrapper()); | 176 ASSERT(groupRoot && groupRoot->containsWrapper()); |
233 | 177 |
234 v8::UniqueId groupId(groupRoot->m_wrapperOrTypeInfo); | 178 v8::UniqueId groupId(reinterpret_cast<intptr_t>(groupRoot->m_wrapper)); |
235 v8::Persistent<v8::Object> wrapper; | 179 v8::Persistent<v8::Object> wrapper; |
236 getPersistent(&wrapper); | 180 getPersistent(&wrapper); |
237 wrapper.MarkPartiallyDependent(); | 181 wrapper.MarkPartiallyDependent(); |
238 isolate->SetObjectGroupId(v8::Persistent<v8::Value>::Cast(wrapper), grou pId); | 182 isolate->SetObjectGroupId(v8::Persistent<v8::Value>::Cast(wrapper), grou pId); |
239 } | 183 } |
240 | 184 |
241 void setReference(const v8::Persistent<v8::Object>& parent, v8::Isolate* iso late) | 185 void setReference(const v8::Persistent<v8::Object>& parent, v8::Isolate* iso late) |
242 { | 186 { |
243 v8::Persistent<v8::Object> persistent; | 187 v8::Persistent<v8::Object> persistent; |
244 getPersistent(&persistent); | 188 getPersistent(&persistent); |
(...skipping 12 matching lines...) Expand all Loading... | |
257 static void assertWrapperSanity(void* object, T* objectAsT) | 201 static void assertWrapperSanity(void* object, T* objectAsT) |
258 { | 202 { |
259 ASSERT_NOT_REACHED(); | 203 ASSERT_NOT_REACHED(); |
260 } | 204 } |
261 | 205 |
262 template<typename V8T, typename T> | 206 template<typename V8T, typename T> |
263 static void assertWrapperSanity(ScriptWrappable* object, T* objectAsT) | 207 static void assertWrapperSanity(ScriptWrappable* object, T* objectAsT) |
264 { | 208 { |
265 ASSERT(object); | 209 ASSERT(object); |
266 ASSERT(objectAsT); | 210 ASSERT(objectAsT); |
267 v8::Object* value = object->getRawValue(); | 211 v8::Object* value = object->m_wrapper; |
268 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(value == 0 | 212 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(value == 0 |
269 || value->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex ) == V8T::toScriptWrappableBase(objectAsT)); | 213 || value->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex ) == V8T::toScriptWrappableBase(objectAsT)); |
270 } | 214 } |
271 | 215 |
272 using ScriptWrappableBase::assertWrapperSanity; | 216 using ScriptWrappableBase::assertWrapperSanity; |
273 | 217 |
274 inline bool containsWrapper() const { return (m_wrapperOrTypeInfo & 1); } | 218 bool containsWrapper() const { return m_wrapper != 0; } |
haraken
2014/09/05 16:46:16
return !!m_wrapper;
Blink's coding style doesn't
Yuki
2014/09/06 09:40:06
Done.
| |
275 inline bool containsTypeInfo() const { return m_wrapperOrTypeInfo && !(m_wra pperOrTypeInfo & 1); } | |
276 | 219 |
277 #if !ENABLE(OILPAN) | 220 #if !ENABLE(OILPAN) |
278 protected: | 221 protected: |
279 virtual ~ScriptWrappable() | 222 virtual ~ScriptWrappable() |
280 { | 223 { |
281 // We must not get deleted as long as we contain a wrapper. If this happ ens, we screwed up ref | 224 // We must not get deleted as long as we contain a wrapper. If this happ ens, we screwed up ref |
282 // counting somewhere. Crash here instead of crashing during a later gc cycle. | 225 // counting somewhere. Crash here instead of crashing during a later gc cycle. |
283 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!containsWrapper()); | 226 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!containsWrapper()); |
284 ASSERT(m_wrapperOrTypeInfo); // Assert initialization via init() even if not subsequently wrapped. | 227 m_wrapper = 0; // Break UAF attempts to wrap. |
285 m_wrapperOrTypeInfo = 0; // Break UAF attempts to wrap. | |
286 } | 228 } |
287 #endif | 229 #endif |
288 // With Oilpan we don't need a ScriptWrappable destructor. | 230 // With Oilpan we don't need a ScriptWrappable destructor. |
289 // | 231 // |
290 // - 'RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!containsWrapper())' is not n eeded | 232 // - 'RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!containsWrapper())' is not n eeded |
291 // because Oilpan is not using reference counting at all. If containsWrapper () is true, | 233 // because Oilpan is not using reference counting at all. If containsWrapper () is true, |
292 // it means that ScriptWrappable still has a wrapper. In this case, the dest ructor | 234 // it means that ScriptWrappable still has a wrapper. In this case, the dest ructor |
293 // must not be called since the wrapper has a persistent handle back to this ScriptWrappable object. | 235 // must not be called since the wrapper has a persistent handle back to this ScriptWrappable object. |
294 // Assuming that Oilpan's GC is correct (If we cannot assume this, a lot of more things are | 236 // Assuming that Oilpan's GC is correct (If we cannot assume this, a lot of more things are |
295 // already broken), we must not hit the RELEASE_ASSERT. | 237 // already broken), we must not hit the RELEASE_ASSERT. |
296 // | 238 // |
297 // - 'm_wrapperOrTypeInfo = 0' is not needed because Oilpan's GC zeroes out memory when | 239 // - 'm_wrapper = 0' is not needed because Oilpan's GC zeroes out memory whe n |
298 // the memory is collected and added to a free list. | 240 // the memory is collected and added to a free list. |
299 | 241 |
300 private: | 242 private: |
301 void getPersistent(v8::Persistent<v8::Object>* persistent) const | 243 void getPersistent(v8::Persistent<v8::Object>* persistent) const |
302 { | 244 { |
303 ASSERT(persistent); | 245 ASSERT(persistent); |
304 | 246 |
305 // Horrible and super unsafe: Cast the Persistent to an Object*, so | 247 // Horrible and super unsafe: Cast the Persistent to an Object*, so |
306 // that we can inject the wrapped value. This only works because | 248 // that we can inject the wrapped value. This only works because |
307 // we previously 'stole' the object pointer from a Persistent in | 249 // we previously 'stole' the object pointer from a Persistent in |
308 // the setWrapper() method. | 250 // the setWrapper() method. |
309 *reinterpret_cast<v8::Object**>(persistent) = getRawValue(); | 251 *reinterpret_cast<v8::Object**>(persistent) = m_wrapper; |
310 } | 252 } |
311 | 253 |
312 inline v8::Object* getRawValue() const | 254 void disposeWrapper(v8::Local<v8::Object> wrapper) |
313 { | |
314 v8::Object* object = containsWrapper() ? reinterpret_cast<v8::Object*>(m _wrapperOrTypeInfo & ~1) : 0; | |
315 return object; | |
316 } | |
317 | |
318 inline void disposeWrapper(v8::Local<v8::Object> wrapper) | |
319 { | 255 { |
320 ASSERT(containsWrapper()); | 256 ASSERT(containsWrapper()); |
321 | 257 |
322 v8::Persistent<v8::Object> persistent; | 258 v8::Persistent<v8::Object> persistent; |
323 getPersistent(&persistent); | 259 getPersistent(&persistent); |
324 | 260 |
325 ASSERT(wrapper == persistent); | 261 ASSERT(wrapper == persistent); |
326 persistent.Reset(); | 262 persistent.Reset(); |
327 setTypeInfo(toWrapperTypeInfo(wrapper)); | 263 m_wrapper = 0; |
328 } | 264 } |
329 | 265 |
330 // If zero, then this contains nothing, otherwise: | |
331 // If the bottom bit it set, then this contains a pointer to a wrapper obj ect in the remainging bits. | |
332 // If the bottom bit is clear, then this contains a pointer to the wrapper type info in the remaining bits. | |
333 uintptr_t m_wrapperOrTypeInfo; | |
334 | |
335 static void setWeakCallback(const v8::WeakCallbackData<v8::Object, ScriptWra ppable>& data) | 266 static void setWeakCallback(const v8::WeakCallbackData<v8::Object, ScriptWra ppable>& data) |
336 { | 267 { |
337 v8::Persistent<v8::Object> persistent; | 268 v8::Persistent<v8::Object> persistent; |
338 data.GetParameter()->getPersistent(&persistent); | 269 data.GetParameter()->getPersistent(&persistent); |
339 ASSERT(persistent == data.GetValue()); | 270 ASSERT(persistent == data.GetValue()); |
340 data.GetParameter()->disposeWrapper(data.GetValue()); | 271 data.GetParameter()->disposeWrapper(data.GetValue()); |
341 | 272 |
342 // FIXME: I noticed that 50%~ of minor GC cycle times can be consumed | 273 // FIXME: I noticed that 50%~ of minor GC cycle times can be consumed |
343 // inside data.GetParameter()->deref(), which causes Node destructions. We should | 274 // inside data.GetParameter()->deref(), which causes Node destructions. We should |
344 // make Node destructions incremental. | 275 // make Node destructions incremental. |
345 releaseObject(data.GetValue()); | 276 releaseObject(data.GetValue()); |
346 } | 277 } |
278 | |
279 v8::Object* m_wrapper; | |
347 }; | 280 }; |
348 | 281 |
349 // Defines 'wrapperTypeInfo' virtual method which returns the WrapperTypeInfo of | 282 // Defines 'wrapperTypeInfo' virtual method which returns the WrapperTypeInfo of |
350 // the instance. Also declares a static member of type WrapperTypeInfo, of which | 283 // the instance. Also declares a static member of type WrapperTypeInfo, of which |
351 // the definition is given by the IDL code generator. | 284 // the definition is given by the IDL code generator. |
352 // | 285 // |
353 // Every DOM Class T must meet either of the following conditions: | 286 // Every DOM Class T must meet either of the following conditions: |
354 // - T.idl inherits from [NotScriptWrappable]. | 287 // - T.idl inherits from [NotScriptWrappable]. |
355 // - T inherits from ScriptWrappable and has DEFINE_WRAPPERTYPEINFO(). | 288 // - T inherits from ScriptWrappable and has DEFINE_WRAPPERTYPEINFO(). |
356 // | 289 // |
357 // If a DOM class T does not inherit from ScriptWrappable, you have to write | 290 // If a DOM class T does not inherit from ScriptWrappable, you have to write |
358 // [NotScriptWrappable] in the IDL file as an extended attribute in order to let | 291 // [NotScriptWrappable] in the IDL file as an extended attribute in order to let |
359 // IDL code generator know that T does not inherit from ScriptWrappable. Note | 292 // IDL code generator know that T does not inherit from ScriptWrappable. Note |
360 // that [NotScriptWrappable] is inheritable. | 293 // that [NotScriptWrappable] is inheritable. |
361 // | 294 // |
362 // All the derived classes of ScriptWrappable, regardless of directly or | 295 // All the derived classes of ScriptWrappable, regardless of directly or |
363 // indirectly, must write this macro in the class definition. | 296 // indirectly, must write this macro in the class definition. |
364 #define DEFINE_WRAPPERTYPEINFO() \ | 297 #define DEFINE_WRAPPERTYPEINFO() \ |
365 public: \ | 298 public: \ |
366 virtual const WrapperTypeInfo* wrapperTypeInfo() const OVERRIDE \ | 299 virtual const WrapperTypeInfo* wrapperTypeInfo() const OVERRIDE \ |
367 { \ | 300 { \ |
368 return &s_wrapperTypeInfo; \ | 301 return &s_wrapperTypeInfo; \ |
369 } \ | 302 } \ |
370 private: \ | 303 private: \ |
371 static const WrapperTypeInfo& s_wrapperTypeInfo | 304 static const WrapperTypeInfo& s_wrapperTypeInfo |
372 | 305 |
373 } // namespace blink | 306 } // namespace blink |
374 | 307 |
375 #endif // ScriptWrappable_h | 308 #endif // ScriptWrappable_h |
OLD | NEW |