1/*
2 * Copyright (C) 2010 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 ScriptWrappable_h
32#define ScriptWrappable_h
33
34#include "bindings/core/v8/WrapperTypeInfo.h"
35#include "platform/ScriptForbiddenScope.h"
36#include "platform/heap/Handle.h"
37#include <v8.h>
38
39namespace blink {
40
41/**
42 * The base class of all wrappable objects.
43 *
44 * This class provides the internal pointer to be stored in the wrapper objects,
45 * and its conversions from / to the DOM instances.
46 *
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.
50 */
51#if COMPILER(MSVC)
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,
55//
56//   class EmptyBase1 {};
57//   class EmptyBase2 {};
58//   class Derived : public EmptyBase1, public EmptyBase2 {};
59//   Derived d;
60//   // &d                           == 0x1000
61//   // static_cast<EmptyBase1*>(&d) == 0x1000
62//   // static_cast<EmptyBase2*>(&d) == 0x1001  // Not 4 byte alignment!
63//
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.
66//
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.
69__declspec(align(4))
70#endif
71class ScriptWrappableBase {
72public:
73    template<typename T>
74    T* toImpl()
75    {
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);
84    }
85    ScriptWrappableBase* toScriptWrappableBase()
86    {
87        // The internal pointers must be aligned to at least 4 byte alignment.
88        ASSERT((reinterpret_cast<intptr_t>(this) & 0x3) == 0);
89        return this;
90    }
91
92    void assertWrapperSanity(v8::Local<v8::Object> object)
93    {
94        RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(object.IsEmpty()
95            || object->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex) == toScriptWrappableBase());
96    }
97};
98
99/**
100 * ScriptWrappable wraps a V8 object and its WrapperTypeInfo.
101 *
102 * ScriptWrappable acts much like a v8::Persistent<> in that it keeps a
103 * V8 object alive.
104 *
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.
110 */
111class ScriptWrappable : public ScriptWrappableBase {
112public:
113    ScriptWrappable() : m_wrapper(0) { }
114
115    // Returns the WrapperTypeInfo of the instance.
116    //
117    // This method must be overridden by DEFINE_WRAPPERTYPEINFO macro.
118    virtual const WrapperTypeInfo* wrapperTypeInfo() const = 0;
119
120    // Creates and returns a new wrapper object.
121    virtual v8::Handle<v8::Object> wrap(v8::Handle<v8::Object> creationContext, v8::Isolate*);
122
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*);
125
126    void setWrapper(v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
127    {
128        ASSERT(!containsWrapper());
129        if (!*wrapper) {
130            m_wrapper = 0;
131            return;
132        }
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());
138    }
139
140    v8::Local<v8::Object> newLocalWrapper(v8::Isolate* isolate) const
141    {
142        v8::Persistent<v8::Object> persistent;
143        getPersistent(&persistent);
144        return v8::Local<v8::Object>::New(isolate, persistent);
145    }
146
147    bool isEqualTo(const v8::Local<v8::Object>& other) const
148    {
149        v8::Persistent<v8::Object> persistent;
150        getPersistent(&persistent);
151        return persistent == other;
152    }
153
154    static bool wrapperCanBeStoredInObject(const void*) { return false; }
155    static bool wrapperCanBeStoredInObject(const ScriptWrappable*) { return true; }
156
157    static ScriptWrappable* fromObject(const void*)
158    {
159        ASSERT_NOT_REACHED();
160        return 0;
161    }
162
163    static ScriptWrappable* fromObject(ScriptWrappable* object)
164    {
165        return object;
166    }
167
168    bool setReturnValue(v8::ReturnValue<v8::Value> returnValue)
169    {
170        v8::Persistent<v8::Object> persistent;
171        getPersistent(&persistent);
172        returnValue.Set(persistent);
173        return containsWrapper();
174    }
175
176    void markAsDependentGroup(ScriptWrappable* groupRoot, v8::Isolate* isolate)
177    {
178        ASSERT(containsWrapper());
179        ASSERT(groupRoot && groupRoot->containsWrapper());
180
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);
186    }
187
188    void setReference(const v8::Persistent<v8::Object>& parent, v8::Isolate* isolate)
189    {
190        v8::Persistent<v8::Object> persistent;
191        getPersistent(&persistent);
192        isolate->SetReference(parent, persistent);
193    }
194
195    template<typename V8T, typename T>
196    static void assertWrapperSanity(v8::Local<v8::Object> object, T* objectAsT)
197    {
198        ASSERT(objectAsT);
199        RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(object.IsEmpty()
200            || object->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex) == V8T::toScriptWrappableBase(objectAsT));
201    }
202
203    template<typename V8T, typename T>
204    static void assertWrapperSanity(void* object, T* objectAsT)
205    {
206        ASSERT_NOT_REACHED();
207    }
208
209    template<typename V8T, typename T>
210    static void assertWrapperSanity(ScriptWrappable* object, T* objectAsT)
211    {
212        ASSERT(object);
213        ASSERT(objectAsT);
214        v8::Object* value = object->m_wrapper;
215        RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(value == 0
216            || value->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex) == V8T::toScriptWrappableBase(objectAsT));
217    }
218
219    using ScriptWrappableBase::assertWrapperSanity;
220
221    bool containsWrapper() const { return m_wrapper; }
222
223#if !ENABLE(OILPAN)
224protected:
225    virtual ~ScriptWrappable()
226    {
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.
231    }
232#endif
233    // With Oilpan we don't need a ScriptWrappable destructor.
234    //
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.
241    //
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.
244
245private:
246    void getPersistent(v8::Persistent<v8::Object>* persistent) const
247    {
248        ASSERT(persistent);
249
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;
255    }
256
257    void disposeWrapper(v8::Local<v8::Object> wrapper)
258    {
259        ASSERT(containsWrapper());
260
261        v8::Persistent<v8::Object> persistent;
262        getPersistent(&persistent);
263
264        ASSERT(wrapper == persistent);
265        persistent.Reset();
266        m_wrapper = 0;
267    }
268
269    static void setWeakCallback(const v8::WeakCallbackData<v8::Object, ScriptWrappable>& data)
270    {
271        v8::Persistent<v8::Object> persistent;
272        data.GetParameter()->getPersistent(&persistent);
273        ASSERT(persistent == data.GetValue());
274        data.GetParameter()->disposeWrapper(data.GetValue());
275
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());
280    }
281
282    v8::Object* m_wrapper;
283};
284
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.
288//
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().
292//
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.
297//
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() \
301public: \
302    virtual const WrapperTypeInfo* wrapperTypeInfo() const OVERRIDE \
303    { \
304        return &s_wrapperTypeInfo; \
305    } \
306private: \
307    static const WrapperTypeInfo& s_wrapperTypeInfo
308
309} // namespace blink
310
311#endif // ScriptWrappable_h
312