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/v8/UnsafePersistent.h" 35 #include "bindings/v8/V8Utilities.h" 36 #include "bindings/v8/WrapperTypeInfo.h" 37 #include <v8.h> 38 39 // Helper to call webCoreInitializeScriptWrappableForInterface in the global namespace. 40 template <class C> inline void initializeScriptWrappableHelper(C* object) 41 { 42 void webCoreInitializeScriptWrappableForInterface(C*); 43 webCoreInitializeScriptWrappableForInterface(object); 44 } 45 46 namespace WebCore { 47 48 class ScriptWrappable { 49 public: 50 ScriptWrappable() : m_wrapperOrTypeInfo(0) { } 51 52 // Wrappables need to be initialized with their most derrived type for which 53 // bindings exist, in much the same way that certain other types need to be 54 // adopted and so forth. The overloaded initializeScriptWrappableForInterface() 55 // functions are implemented by the generated V8 bindings code. Declaring the 56 // extern function in the template avoids making a centralized header of all 57 // the bindings in the universe. C++11's extern template feature may provide 58 // a cleaner solution someday. 59 template <class C> static void init(C* object) 60 { 61 initializeScriptWrappableHelper(object); 62 } 63 64 void setWrapper(v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperConfiguration& configuration) 65 { 66 ASSERT(!containsWrapper()); 67 if (!*wrapper) { 68 m_wrapperOrTypeInfo = 0; 69 return; 70 } 71 v8::Persistent<v8::Object> persistent(isolate, wrapper); 72 configuration.configureWrapper(&persistent, isolate); 73 persistent.MakeWeak(this, &makeWeakCallback); 74 m_wrapperOrTypeInfo = reinterpret_cast<uintptr_t>(persistent.ClearAndLeak()) | 1; 75 ASSERT(containsWrapper()); 76 } 77 78 v8::Local<v8::Object> newLocalWrapper(v8::Isolate* isolate) const 79 { 80 return unsafePersistent().newLocal(isolate); 81 } 82 83 const WrapperTypeInfo* typeInfo() 84 { 85 if (containsTypeInfo()) 86 return reinterpret_cast<const WrapperTypeInfo*>(m_wrapperOrTypeInfo); 87 88 if (containsWrapper()) { 89 return toWrapperTypeInfo(unsafePersistent().deprecatedHandle()); 90 } 91 92 return 0; 93 } 94 95 void setTypeInfo(const WrapperTypeInfo* info) 96 { 97 m_wrapperOrTypeInfo = reinterpret_cast<uintptr_t>(info); 98 ASSERT(containsTypeInfo()); 99 } 100 101 static bool wrapperCanBeStoredInObject(const void*) { return false; } 102 static bool wrapperCanBeStoredInObject(const ScriptWrappable*) { return true; } 103 104 static void setWrapperInObject(void*, v8::Handle<v8::Object>, v8::Isolate*, const WrapperConfiguration&) 105 { 106 ASSERT_NOT_REACHED(); 107 } 108 109 static void setWrapperInObject(ScriptWrappable* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperConfiguration& configuration) 110 { 111 object->setWrapper(wrapper, isolate, configuration); 112 } 113 114 static const WrapperTypeInfo* getTypeInfoFromObject(void* object) 115 { 116 ASSERT_NOT_REACHED(); 117 return 0; 118 } 119 120 static const WrapperTypeInfo* getTypeInfoFromObject(ScriptWrappable* object) 121 { 122 return object->typeInfo(); 123 } 124 125 static void setTypeInfoInObject(void* object, const WrapperTypeInfo* info) 126 { 127 ASSERT_NOT_REACHED(); 128 } 129 130 static void setTypeInfoInObject(ScriptWrappable* object, const WrapperTypeInfo* info) 131 { 132 object->setTypeInfo(info); 133 } 134 135 protected: 136 ~ScriptWrappable() 137 { 138 ASSERT(m_wrapperOrTypeInfo); // Assert initialization via init() even if not subsequently wrapped. 139 m_wrapperOrTypeInfo = 0; // Break UAF attempts to wrap. 140 } 141 142 private: 143 // For calling unsafePersistent and getWrapperFromObject. 144 friend class MinorGCWrapperVisitor; 145 friend class DOMDataStore; 146 147 UnsafePersistent<v8::Object> unsafePersistent() const 148 { 149 v8::Object* object = containsWrapper() ? reinterpret_cast<v8::Object*>(m_wrapperOrTypeInfo & ~1) : 0; 150 return UnsafePersistent<v8::Object>(object); 151 } 152 153 static UnsafePersistent<v8::Object> getUnsafeWrapperFromObject(void*) 154 { 155 ASSERT_NOT_REACHED(); 156 return UnsafePersistent<v8::Object>(); 157 } 158 159 static UnsafePersistent<v8::Object> getUnsafeWrapperFromObject(ScriptWrappable* object) 160 { 161 return object->unsafePersistent(); 162 } 163 164 inline bool containsWrapper() const { return (m_wrapperOrTypeInfo & 1) == 1; } 165 inline bool containsTypeInfo() const { return m_wrapperOrTypeInfo && (m_wrapperOrTypeInfo & 1) == 0; } 166 167 inline void disposeWrapper(v8::Persistent<v8::Object>* value, const WrapperTypeInfo* info) 168 { 169 ASSERT(containsWrapper()); 170 ASSERT(*reinterpret_cast<uintptr_t*>(value) == (m_wrapperOrTypeInfo & ~1)); 171 value->Dispose(); 172 setTypeInfo(info); 173 } 174 175 // If zero, then this contains nothing, otherwise: 176 // If the bottom bit it set, then this contains a pointer to a wrapper object in the remainging bits. 177 // If the bottom bit is clear, then this contains a pointer to the wrapper type info in the remaining bits. 178 uintptr_t m_wrapperOrTypeInfo; 179 180 static void makeWeakCallback(v8::Isolate* isolate, v8::Persistent<v8::Object>* wrapper, ScriptWrappable* key) 181 { 182 ASSERT(key->unsafePersistent().deprecatedHandle() == *wrapper); 183 184 // Note: |object| might not be equal to |key|, e.g., if ScriptWrappable isn't a left-most base class. 185 void* object = toNative(*wrapper); 186 WrapperTypeInfo* info = toWrapperTypeInfo(*wrapper); 187 ASSERT(info->derefObjectFunction); 188 189 key->disposeWrapper(wrapper, info); 190 // FIXME: I noticed that 50%~ of minor GC cycle times can be consumed 191 // inside key->deref(), which causes Node destructions. We should 192 // make Node destructions incremental. 193 info->derefObject(object); 194 } 195 }; 196 197 } // namespace WebCore 198 199 #endif // ScriptWrappable_h 200