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 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 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 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> 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> 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 214 inline ScriptWrappableBase* toScriptWrappableBase(v8::Handle<v8::Object> wrapper) 215 { 216 return getInternalField<ScriptWrappableBase, v8DOMWrapperObjectIndex>(wrapper); 217 } 218 219 inline const WrapperTypeInfo* toWrapperTypeInfo(const v8::Persistent<v8::Object>& wrapper) 220 { 221 return getInternalField<WrapperTypeInfo, v8DOMWrapperTypeIndex>(wrapper); 222 } 223 224 inline const WrapperTypeInfo* toWrapperTypeInfo(v8::Handle<v8::Object> wrapper) 225 { 226 return getInternalField<WrapperTypeInfo, v8DOMWrapperTypeIndex>(wrapper); 227 } 228 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 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