Home | History | Annotate | Download | only in v8
      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