2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
31 #ifndef ScriptWrappable_h
32 #define ScriptWrappable_h
34 #include "bindings/core/v8/WrapperTypeInfo.h"
35 #include "platform/ScriptForbiddenScope.h"
36 #include "platform/heap/Handle.h"
42 * The base class of all wrappable objects.
44 * This class provides the internal pointer to be stored in the wrapper objects,
45 * and its conversions from / to the DOM instances.
47 * Note that this class must not have vtbl (any virtual function) or any member
48 * variable which increase the size of instances. Some of the classes sensitive
49 * to the size inherit from this class. So this class must be zero size.
52 // VC++ 2013 doesn't support EBCO (Empty Base Class Optimization). It causes
53 // that not always pointers to an empty base class are aligned to 4 byte
54 // alignment. For example,
56 // class EmptyBase1 {};
57 // class EmptyBase2 {};
58 // class Derived : public EmptyBase1, public EmptyBase2 {};
61 // // static_cast<EmptyBase1*>(&d) == 0x1000
62 // // static_cast<EmptyBase2*>(&d) == 0x1001 // Not 4 byte alignment!
64 // This doesn't happen with other compilers which support EBCO. All the
65 // addresses in the above example will be 0x1000 with EBCO supported.
67 // Since v8::Object::SetAlignedPointerInInternalField requires the pointers to
68 // be aligned, we need a hack to specify at least 4 byte alignment to MSVC.
71 class ScriptWrappableBase {
76 // Check if T* is castable to ScriptWrappableBase*, which means T
77 // doesn't have two or more ScriptWrappableBase as superclasses.
78 // If T has two ScriptWrappableBase as superclasses, conversions
79 // from T* to ScriptWrappableBase* are ambiguous.
80 ASSERT(static_cast<ScriptWrappableBase*>(static_cast<T*>(this)));
81 // The internal pointers must be aligned to at least 4 byte alignment.
82 ASSERT((reinterpret_cast<intptr_t>(this) & 0x3) == 0);
83 return static_cast<T*>(this);
85 ScriptWrappableBase* toScriptWrappableBase()
87 // The internal pointers must be aligned to at least 4 byte alignment.
88 ASSERT((reinterpret_cast<intptr_t>(this) & 0x3) == 0);
92 void assertWrapperSanity(v8::Local<v8::Object> object)
94 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(object.IsEmpty()
95 || object->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex) == toScriptWrappableBase());
100 * ScriptWrappable wraps a V8 object and its WrapperTypeInfo.
102 * ScriptWrappable acts much like a v8::Persistent<> in that it keeps a
105 * The state transitions are:
106 * - new: an empty ScriptWrappable.
107 * - setWrapper: install a v8::Persistent (or empty)
108 * - disposeWrapper (via setWeakCallback, triggered by V8 garbage collecter):
109 * remove v8::Persistent and become empty.
111 class ScriptWrappable : public ScriptWrappableBase {
113 ScriptWrappable() : m_wrapper(0) { }
115 // Returns the WrapperTypeInfo of the instance.
117 // This method must be overridden by DEFINE_WRAPPERTYPEINFO macro.
118 virtual const WrapperTypeInfo* wrapperTypeInfo() const = 0;
120 // Creates and returns a new wrapper object.
121 virtual v8::Handle<v8::Object> wrap(v8::Handle<v8::Object> creationContext, v8::Isolate*);
123 // Associates the instance with the existing wrapper. Returns |wrapper|.
124 virtual v8::Handle<v8::Object> associateWithWrapper(const WrapperTypeInfo*, v8::Handle<v8::Object> wrapper, v8::Isolate*);
126 void setWrapper(v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
128 ASSERT(!containsWrapper());
133 v8::Persistent<v8::Object> persistent(isolate, wrapper);
134 wrapperTypeInfo->configureWrapper(&persistent);
135 persistent.SetWeak(this, &setWeakCallback);
136 m_wrapper = persistent.ClearAndLeak();
137 ASSERT(containsWrapper());
140 v8::Local<v8::Object> newLocalWrapper(v8::Isolate* isolate) const
142 v8::Persistent<v8::Object> persistent;
143 getPersistent(&persistent);
144 return v8::Local<v8::Object>::New(isolate, persistent);
147 bool isEqualTo(const v8::Local<v8::Object>& other) const
149 v8::Persistent<v8::Object> persistent;
150 getPersistent(&persistent);
151 return persistent == other;
154 static bool wrapperCanBeStoredInObject(const void*) { return false; }
155 static bool wrapperCanBeStoredInObject(const ScriptWrappable*) { return true; }
157 static ScriptWrappable* fromObject(const void*)
159 ASSERT_NOT_REACHED();
163 static ScriptWrappable* fromObject(ScriptWrappable* object)
168 bool setReturnValue(v8::ReturnValue<v8::Value> returnValue)
170 v8::Persistent<v8::Object> persistent;
171 getPersistent(&persistent);
172 returnValue.Set(persistent);
173 return containsWrapper();
176 void markAsDependentGroup(ScriptWrappable* groupRoot, v8::Isolate* isolate)
178 ASSERT(containsWrapper());
179 ASSERT(groupRoot && groupRoot->containsWrapper());
181 v8::UniqueId groupId(reinterpret_cast<intptr_t>(groupRoot->m_wrapper));
182 v8::Persistent<v8::Object> wrapper;
183 getPersistent(&wrapper);
184 wrapper.MarkPartiallyDependent();
185 isolate->SetObjectGroupId(v8::Persistent<v8::Value>::Cast(wrapper), groupId);
188 void setReference(const v8::Persistent<v8::Object>& parent, v8::Isolate* isolate)
190 v8::Persistent<v8::Object> persistent;
191 getPersistent(&persistent);
192 isolate->SetReference(parent, persistent);
195 template<typename V8T, typename T>
196 static void assertWrapperSanity(v8::Local<v8::Object> object, T* objectAsT)
199 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(object.IsEmpty()
200 || object->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex) == V8T::toScriptWrappableBase(objectAsT));
203 template<typename V8T, typename T>
204 static void assertWrapperSanity(void* object, T* objectAsT)
206 ASSERT_NOT_REACHED();
209 template<typename V8T, typename T>
210 static void assertWrapperSanity(ScriptWrappable* object, T* objectAsT)
214 v8::Object* value = object->m_wrapper;
215 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(value == 0
216 || value->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex) == V8T::toScriptWrappableBase(objectAsT));
219 using ScriptWrappableBase::assertWrapperSanity;
221 bool containsWrapper() const { return m_wrapper; }
225 virtual ~ScriptWrappable()
227 // We must not get deleted as long as we contain a wrapper. If this happens, we screwed up ref
228 // counting somewhere. Crash here instead of crashing during a later gc cycle.
229 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!containsWrapper());
230 m_wrapper = 0; // Break UAF attempts to wrap.
233 // With Oilpan we don't need a ScriptWrappable destructor.
235 // - 'RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!containsWrapper())' is not needed
236 // because Oilpan is not using reference counting at all. If containsWrapper() is true,
237 // it means that ScriptWrappable still has a wrapper. In this case, the destructor
238 // must not be called since the wrapper has a persistent handle back to this ScriptWrappable object.
239 // Assuming that Oilpan's GC is correct (If we cannot assume this, a lot of more things are
240 // already broken), we must not hit the RELEASE_ASSERT.
242 // - 'm_wrapper = 0' is not needed because Oilpan's GC zeroes out memory when
243 // the memory is collected and added to a free list.
246 void getPersistent(v8::Persistent<v8::Object>* persistent) const
250 // Horrible and super unsafe: Cast the Persistent to an Object*, so
251 // that we can inject the wrapped value. This only works because
252 // we previously 'stole' the object pointer from a Persistent in
253 // the setWrapper() method.
254 *reinterpret_cast<v8::Object**>(persistent) = m_wrapper;
257 void disposeWrapper(v8::Local<v8::Object> wrapper)
259 ASSERT(containsWrapper());
261 v8::Persistent<v8::Object> persistent;
262 getPersistent(&persistent);
264 ASSERT(wrapper == persistent);
269 static void setWeakCallback(const v8::WeakCallbackData<v8::Object, ScriptWrappable>& data)
271 v8::Persistent<v8::Object> persistent;
272 data.GetParameter()->getPersistent(&persistent);
273 ASSERT(persistent == data.GetValue());
274 data.GetParameter()->disposeWrapper(data.GetValue());
276 // FIXME: I noticed that 50%~ of minor GC cycle times can be consumed
277 // inside data.GetParameter()->deref(), which causes Node destructions. We should
278 // make Node destructions incremental.
279 releaseObject(data.GetValue());
282 v8::Object* m_wrapper;
285 // Defines 'wrapperTypeInfo' virtual method which returns the WrapperTypeInfo of
286 // the instance. Also declares a static member of type WrapperTypeInfo, of which
287 // the definition is given by the IDL code generator.
289 // Every DOM Class T must meet either of the following conditions:
290 // - T.idl inherits from [NotScriptWrappable].
291 // - T inherits from ScriptWrappable and has DEFINE_WRAPPERTYPEINFO().
293 // If a DOM class T does not inherit from ScriptWrappable, you have to write
294 // [NotScriptWrappable] in the IDL file as an extended attribute in order to let
295 // IDL code generator know that T does not inherit from ScriptWrappable. Note
296 // that [NotScriptWrappable] is inheritable.
298 // All the derived classes of ScriptWrappable, regardless of directly or
299 // indirectly, must write this macro in the class definition.
300 #define DEFINE_WRAPPERTYPEINFO() \
302 virtual const WrapperTypeInfo* wrapperTypeInfo() const OVERRIDE \
304 return &s_wrapperTypeInfo; \
307 static const WrapperTypeInfo& s_wrapperTypeInfo
311 #endif // ScriptWrappable_h