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
39 namespace blink {
40
41 class ActiveDOMObject;
42 class EventTarget;
43 class Node;
44 class ScriptWrappableBase;
45
46 static const int v8DOMWrapperTypeIndex = static_cast<int>(gin::kWrapperInfoIndex);
47 static const int v8DOMWrapperObjectIndex = static_cast<int>(gin::kEncodedValueIndex);
48 static const int v8DefaultWrapperInternalFieldCount = static_cast<int>(gin::kNumberOfInternalFields);
49 static const int v8PrototypeTypeIndex = 0;
50 static const int v8PrototypeInternalFieldcount = 1;
51
52 typedef v8::Handle<v8::FunctionTemplate> (*DomTemplateFunction)(v8::Isolate*);
53 typedef void (*RefObjectFunction)(ScriptWrappableBase* internalPointer);
54 typedef void (*DerefObjectFunction)(ScriptWrappableBase* internalPointer);
55 typedef WrapperPersistentNode* (*CreatePersistentHandleFunction)(ScriptWrappableBase* internalPointer);
56 typedef ActiveDOMObject* (*ToActiveDOMObjectFunction)(v8::Handle<v8::Object>);
57 typedef EventTarget* (*ToEventTargetFunction)(v8::Handle<v8::Object>);
58 typedef void (*ResolveWrapperReachabilityFunction)(ScriptWrappableBase* internalPointer, const v8::Persistent<v8::Object>&, v8::Isolate*);
59 typedef void (*InstallConditionallyEnabledMethodsFunction)(v8::Handle<v8::Object>, v8::Isolate*);
60 typedef void (*InstallConditionallyEnabledPropertiesFunction)(v8::Handle<v8::Object>, v8::Isolate*);
61
setObjectGroup(ScriptWrappableBase * internalPointer,const v8::Persistent<v8::Object> & wrapper,v8::Isolate * isolate)62 inline 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.
70 struct 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
unwrapWrapperTypeInfo92 static const WrapperTypeInfo* unwrap(v8::Handle<v8::Value> typeInfoWrapper)
93 {
94 return reinterpret_cast<const WrapperTypeInfo*>(v8::External::Cast(*typeInfoWrapper)->Value());
95 }
96
97
equalsWrapperTypeInfo98 bool equals(const WrapperTypeInfo* that) const
99 {
100 return this == that;
101 }
102
isSubclassWrapperTypeInfo103 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
configureWrapperWrapperTypeInfo113 void configureWrapper(v8::PersistentBase<v8::Object>* wrapper) const
114 {
115 wrapper->SetWrapperClassId(wrapperClassId);
116 if (lifetime == Independent)
117 wrapper->MarkIndependent();
118 }
119
domTemplateWrapperTypeInfo120 v8::Handle<v8::FunctionTemplate> domTemplate(v8::Isolate* isolate) const
121 {
122 return domTemplateFunction(isolate);
123 }
124
refObjectWrapperTypeInfo125 void refObject(ScriptWrappableBase* internalPointer) const
126 {
127 ASSERT(refObjectFunction);
128 refObjectFunction(internalPointer);
129 }
130
derefObjectWrapperTypeInfo131 void derefObject(ScriptWrappableBase* internalPointer) const
132 {
133 ASSERT(derefObjectFunction);
134 derefObjectFunction(internalPointer);
135 }
136
createPersistentHandleWrapperTypeInfo137 WrapperPersistentNode* createPersistentHandle(ScriptWrappableBase* internalPointer) const
138 {
139 ASSERT(createPersistentHandleFunction);
140 return createPersistentHandleFunction(internalPointer);
141 }
142
installConditionallyEnabledMethodsWrapperTypeInfo143 void installConditionallyEnabledMethods(v8::Handle<v8::Object> prototypeTemplate, v8::Isolate* isolate) const
144 {
145 if (installConditionallyEnabledMethodsFunction)
146 installConditionallyEnabledMethodsFunction(prototypeTemplate, isolate);
147 }
148
installConditionallyEnabledPropertiesWrapperTypeInfo149 void installConditionallyEnabledProperties(v8::Handle<v8::Object> prototypeTemplate, v8::Isolate* isolate) const
150 {
151 if (installConditionallyEnabledPropertiesFunction)
152 installConditionallyEnabledPropertiesFunction(prototypeTemplate, isolate);
153 }
154
toActiveDOMObjectWrapperTypeInfo155 ActiveDOMObject* toActiveDOMObject(v8::Handle<v8::Object> object) const
156 {
157 if (!toActiveDOMObjectFunction)
158 return 0;
159 return toActiveDOMObjectFunction(object);
160 }
161
toEventTargetWrapperTypeInfo162 EventTarget* toEventTarget(v8::Handle<v8::Object> object) const
163 {
164 if (!toEventTargetFunction)
165 return 0;
166 return toEventTargetFunction(object);
167 }
168
visitDOMWrapperWrapperTypeInfo169 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
196 COMPILE_ASSERT(offsetof(struct WrapperTypeInfo, ginEmbedder) == offsetof(struct gin::WrapperInfo, embedder), wrapper_type_info_compatible_to_gin);
197
198 template<typename T, int offset>
getInternalField(const v8::Persistent<v8::Object> & persistent)199 inline 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
207 template<typename T, int offset>
getInternalField(v8::Handle<v8::Object> wrapper)208 inline T* getInternalField(v8::Handle<v8::Object> wrapper)
209 {
210 ASSERT(offset < wrapper->InternalFieldCount());
211 return static_cast<T*>(wrapper->GetAlignedPointerFromInternalField(offset));
212 }
213
toScriptWrappableBase(v8::Handle<v8::Object> wrapper)214 inline ScriptWrappableBase* toScriptWrappableBase(v8::Handle<v8::Object> wrapper)
215 {
216 return getInternalField<ScriptWrappableBase, v8DOMWrapperObjectIndex>(wrapper);
217 }
218
toWrapperTypeInfo(const v8::Persistent<v8::Object> & wrapper)219 inline const WrapperTypeInfo* toWrapperTypeInfo(const v8::Persistent<v8::Object>& wrapper)
220 {
221 return getInternalField<WrapperTypeInfo, v8DOMWrapperTypeIndex>(wrapper);
222 }
223
toWrapperTypeInfo(v8::Handle<v8::Object> wrapper)224 inline const WrapperTypeInfo* toWrapperTypeInfo(v8::Handle<v8::Object> wrapper)
225 {
226 return getInternalField<WrapperTypeInfo, v8DOMWrapperTypeIndex>(wrapper);
227 }
228
toPersistentHandle(const v8::Handle<v8::Object> & wrapper)229 inline 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
releaseObject(v8::Handle<v8::Object> wrapper)235 inline 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