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 WrapperTypeInfo_h
32#define WrapperTypeInfo_h
33
34#include "gin/public/wrapper_info.h"
35#include "platform/heap/Handle.h"
36#include "wtf/Assertions.h"
37#include <v8.h>
38
39namespace blink {
40
41class ActiveDOMObject;
42class EventTarget;
43class Node;
44class ScriptWrappableBase;
45
46static const int v8DOMWrapperTypeIndex = static_cast<int>(gin::kWrapperInfoIndex);
47static const int v8DOMWrapperObjectIndex = static_cast<int>(gin::kEncodedValueIndex);
48static const int v8DefaultWrapperInternalFieldCount = static_cast<int>(gin::kNumberOfInternalFields);
49static const int v8PrototypeTypeIndex = 0;
50static const int v8PrototypeInternalFieldcount = 1;
51
52typedef v8::Handle<v8::FunctionTemplate> (*DomTemplateFunction)(v8::Isolate*);
53typedef void (*RefObjectFunction)(ScriptWrappableBase* internalPointer);
54typedef void (*DerefObjectFunction)(ScriptWrappableBase* internalPointer);
55typedef WrapperPersistentNode* (*CreatePersistentHandleFunction)(ScriptWrappableBase* internalPointer);
56typedef ActiveDOMObject* (*ToActiveDOMObjectFunction)(v8::Handle<v8::Object>);
57typedef EventTarget* (*ToEventTargetFunction)(v8::Handle<v8::Object>);
58typedef void (*ResolveWrapperReachabilityFunction)(ScriptWrappableBase* internalPointer, const v8::Persistent<v8::Object>&, v8::Isolate*);
59typedef void (*InstallConditionallyEnabledMethodsFunction)(v8::Handle<v8::Object>, v8::Isolate*);
60typedef void (*InstallConditionallyEnabledPropertiesFunction)(v8::Handle<v8::Object>, v8::Isolate*);
61
62inline void setObjectGroup(ScriptWrappableBase* internalPointer, const v8::Persistent<v8::Object>& wrapper, v8::Isolate* isolate)
63{
64    isolate->SetObjectGroupId(wrapper, v8::UniqueId(reinterpret_cast<intptr_t>(internalPointer)));
65}
66
67// This struct provides a way to store a bunch of information that is helpful when unwrapping
68// v8 objects. Each v8 bindings class has exactly one static WrapperTypeInfo member, so
69// comparing pointers is a safe way to determine if types match.
70struct WrapperTypeInfo {
71    enum WrapperTypePrototype {
72        WrapperTypeObjectPrototype,
73        WrapperTypeExceptionPrototype,
74    };
75
76    enum WrapperClassId {
77        NodeClassId = 1, // NodeClassId must be smaller than ObjectClassId.
78        ObjectClassId,
79    };
80
81    enum Lifetime {
82        Dependent,
83        Independent,
84    };
85
86    enum GCType {
87        GarbageCollectedObject,
88        WillBeGarbageCollectedObject,
89        RefCountedObject,
90    };
91
92    static const WrapperTypeInfo* unwrap(v8::Handle<v8::Value> typeInfoWrapper)
93    {
94        return reinterpret_cast<const WrapperTypeInfo*>(v8::External::Cast(*typeInfoWrapper)->Value());
95    }
96
97
98    bool equals(const WrapperTypeInfo* that) const
99    {
100        return this == that;
101    }
102
103    bool isSubclass(const WrapperTypeInfo* that) const
104    {
105        for (const WrapperTypeInfo* current = this; current; current = current->parentClass) {
106            if (current == that)
107                return true;
108        }
109
110        return false;
111    }
112
113    void configureWrapper(v8::PersistentBase<v8::Object>* wrapper) const
114    {
115        wrapper->SetWrapperClassId(wrapperClassId);
116        if (lifetime == Independent)
117            wrapper->MarkIndependent();
118    }
119
120    v8::Handle<v8::FunctionTemplate> domTemplate(v8::Isolate* isolate) const
121    {
122        return domTemplateFunction(isolate);
123    }
124
125    void refObject(ScriptWrappableBase* internalPointer) const
126    {
127        ASSERT(refObjectFunction);
128        refObjectFunction(internalPointer);
129    }
130
131    void derefObject(ScriptWrappableBase* internalPointer) const
132    {
133        ASSERT(derefObjectFunction);
134        derefObjectFunction(internalPointer);
135    }
136
137    WrapperPersistentNode* createPersistentHandle(ScriptWrappableBase* internalPointer) const
138    {
139        ASSERT(createPersistentHandleFunction);
140        return createPersistentHandleFunction(internalPointer);
141    }
142
143    void installConditionallyEnabledMethods(v8::Handle<v8::Object> prototypeTemplate, v8::Isolate* isolate) const
144    {
145        if (installConditionallyEnabledMethodsFunction)
146            installConditionallyEnabledMethodsFunction(prototypeTemplate, isolate);
147    }
148
149    void installConditionallyEnabledProperties(v8::Handle<v8::Object> prototypeTemplate, v8::Isolate* isolate) const
150    {
151        if (installConditionallyEnabledPropertiesFunction)
152            installConditionallyEnabledPropertiesFunction(prototypeTemplate, isolate);
153    }
154
155    ActiveDOMObject* toActiveDOMObject(v8::Handle<v8::Object> object) const
156    {
157        if (!toActiveDOMObjectFunction)
158            return 0;
159        return toActiveDOMObjectFunction(object);
160    }
161
162    EventTarget* toEventTarget(v8::Handle<v8::Object> object) const
163    {
164        if (!toEventTargetFunction)
165            return 0;
166        return toEventTargetFunction(object);
167    }
168
169    void visitDOMWrapper(ScriptWrappableBase* internalPointer, const v8::Persistent<v8::Object>& wrapper, v8::Isolate* isolate) const
170    {
171        if (!visitDOMWrapperFunction)
172            setObjectGroup(internalPointer, wrapper, isolate);
173        else
174            visitDOMWrapperFunction(internalPointer, wrapper, isolate);
175    }
176
177    // This field must be the first member of the struct WrapperTypeInfo. This is also checked by a COMPILE_ASSERT() below.
178    const gin::GinEmbedder ginEmbedder;
179
180    const DomTemplateFunction domTemplateFunction;
181    const RefObjectFunction refObjectFunction;
182    const DerefObjectFunction derefObjectFunction;
183    const CreatePersistentHandleFunction createPersistentHandleFunction;
184    const ToActiveDOMObjectFunction toActiveDOMObjectFunction;
185    const ToEventTargetFunction toEventTargetFunction;
186    const ResolveWrapperReachabilityFunction visitDOMWrapperFunction;
187    const InstallConditionallyEnabledMethodsFunction installConditionallyEnabledMethodsFunction;
188    const InstallConditionallyEnabledPropertiesFunction installConditionallyEnabledPropertiesFunction;
189    const WrapperTypeInfo* parentClass;
190    const WrapperTypePrototype wrapperTypePrototype;
191    const WrapperClassId wrapperClassId;
192    const Lifetime lifetime;
193    const GCType gcType;
194};
195
196COMPILE_ASSERT(offsetof(struct WrapperTypeInfo, ginEmbedder) == offsetof(struct gin::WrapperInfo, embedder), wrapper_type_info_compatible_to_gin);
197
198template<typename T, int offset>
199inline T* getInternalField(const v8::Persistent<v8::Object>& persistent)
200{
201    // This would be unsafe, but InternalFieldCount and GetAlignedPointerFromInternalField are guaranteed not to allocate
202    const v8::Handle<v8::Object>& object = reinterpret_cast<const v8::Handle<v8::Object>&>(persistent);
203    ASSERT(offset < object->InternalFieldCount());
204    return static_cast<T*>(object->GetAlignedPointerFromInternalField(offset));
205}
206
207template<typename T, int offset>
208inline T* getInternalField(v8::Handle<v8::Object> wrapper)
209{
210    ASSERT(offset < wrapper->InternalFieldCount());
211    return static_cast<T*>(wrapper->GetAlignedPointerFromInternalField(offset));
212}
213
214inline ScriptWrappableBase* toScriptWrappableBase(v8::Handle<v8::Object> wrapper)
215{
216    return getInternalField<ScriptWrappableBase, v8DOMWrapperObjectIndex>(wrapper);
217}
218
219inline const WrapperTypeInfo* toWrapperTypeInfo(const v8::Persistent<v8::Object>& wrapper)
220{
221    return getInternalField<WrapperTypeInfo, v8DOMWrapperTypeIndex>(wrapper);
222}
223
224inline const WrapperTypeInfo* toWrapperTypeInfo(v8::Handle<v8::Object> wrapper)
225{
226    return getInternalField<WrapperTypeInfo, v8DOMWrapperTypeIndex>(wrapper);
227}
228
229inline const WrapperPersistentNode* toPersistentHandle(const v8::Handle<v8::Object>& wrapper)
230{
231    // Persistent handle is stored in the last internal field.
232    return static_cast<WrapperPersistentNode*>(wrapper->GetAlignedPointerFromInternalField(wrapper->InternalFieldCount() - 1));
233}
234
235inline void releaseObject(v8::Handle<v8::Object> wrapper)
236{
237    const WrapperTypeInfo* typeInfo = toWrapperTypeInfo(wrapper);
238    if (typeInfo->gcType == WrapperTypeInfo::GarbageCollectedObject) {
239        const WrapperPersistentNode* handle = toPersistentHandle(wrapper);
240        // This will be null iff a wrapper for a hidden wrapper object,
241        // see V8DOMWrapper::setNativeInfoForHiddenWrapper().
242        WrapperPersistentNode::destroy(handle);
243    } else if (typeInfo->gcType == WrapperTypeInfo::WillBeGarbageCollectedObject) {
244#if ENABLE(OILPAN)
245        const WrapperPersistentNode* handle = toPersistentHandle(wrapper);
246        // This will be null iff a wrapper for a hidden wrapper object,
247        // see V8DOMWrapper::setNativeInfoForHiddenWrapper().
248        WrapperPersistentNode::destroy(handle);
249#else
250        typeInfo->derefObject(toScriptWrappableBase(wrapper));
251#endif
252    } else {
253        typeInfo->derefObject(toScriptWrappableBase(wrapper));
254    }
255}
256
257} // namespace blink
258
259#endif // WrapperTypeInfo_h
260