1 /* 2 * Copyright (C) 2012 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 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #ifndef Supplementable_h 27 #define Supplementable_h 28 29 #include "platform/heap/Handle.h" 30 #include "wtf/Assertions.h" 31 #include "wtf/HashMap.h" 32 #include "wtf/OwnPtr.h" 33 #include "wtf/PassOwnPtr.h" 34 35 #if ASSERT_ENABLED 36 #include "wtf/Threading.h" 37 #endif 38 39 namespace WebCore { 40 41 // What you should know about Supplementable and Supplement 42 // ======================================================== 43 // Supplementable and Supplement instances are meant to be thread local. They 44 // should only be accessed from within the thread that created them. The 45 // 2 classes are not designed for safe access from another thread. Violating 46 // this design assumption can result in memory corruption and unpredictable 47 // behavior. 48 // 49 // What you should know about the Supplement keys 50 // ============================================== 51 // The Supplement is expected to use the same const char* string instance 52 // as its key. The Supplementable's SupplementMap will use the address of the 53 // string as the key and not the characters themselves. Hence, 2 strings with 54 // the same characters will be treated as 2 different keys. 55 // 56 // In practice, it is recommended that Supplements implements a static method 57 // for returning its key to use. For example: 58 // 59 // class MyClass : public Supplement<MySupplementable> { 60 // ... 61 // static const char* supplementName(); 62 // } 63 // 64 // const char* MyClass::supplementName() 65 // { 66 // return "MyClass"; 67 // } 68 // 69 // An example of the using the key: 70 // 71 // MyClass* MyClass::from(MySupplementable* host) 72 // { 73 // return reinterpret_cast<MyClass*>(Supplement<MySupplementable>::from(host, supplementName())); 74 // } 75 // 76 // What you should know about thread checks 77 // ======================================== 78 // When assertion is enabled this class performs thread-safety check so that 79 // provideTo and from happen on the same thread. If you want to provide 80 // some value for Workers this thread check may not work very well though, 81 // since in most case you'd provide the value while worker preparation is 82 // being done on the main thread, even before the worker thread is started. 83 // If that's the case you can explicitly call reattachThread() when the 84 // Supplementable object is passed to the final destination thread (i.e. 85 // worker thread). Please be extremely careful to use the method though, 86 // as randomly calling the method could easily cause racy condition. 87 // 88 // Note that reattachThread() does nothing if assertion is not enabled. 89 // 90 91 template<typename T, bool isGarbageCollected> 92 class SupplementBase; 93 94 template<typename T, bool isGarbageCollected> 95 class SupplementableBase; 96 97 template<typename T, bool isGarbageCollected> 98 struct SupplementableTraits; 99 100 template<typename T> 101 struct SupplementableTraits<T, true> { 102 typedef RawPtr<SupplementBase<T, true> > SupplementArgumentType; 103 typedef HeapHashMap<const char*, Member<SupplementBase<T, true> >, PtrHash<const char*> > SupplementMap; 104 }; 105 106 template<typename T> 107 struct SupplementableTraits<T, false> { 108 typedef PassOwnPtr<SupplementBase<T, false> > SupplementArgumentType; 109 typedef HashMap<const char*, OwnPtr<SupplementBase<T, false> >, PtrHash<const char*> > SupplementMap; 110 }; 111 112 template<bool> 113 class SupplementTracing; 114 115 template<> 116 class SupplementTracing<true> : public GarbageCollectedMixin { }; 117 118 template<> 119 class SupplementTracing<false> { 120 public: 121 virtual ~SupplementTracing() { } 122 }; 123 124 template<typename T, bool isGarbageCollected = false> 125 class SupplementBase : public SupplementTracing<isGarbageCollected> { 126 public: 127 #if SECURITY_ASSERT_ENABLED 128 virtual bool isRefCountedWrapper() const { return false; } 129 #endif 130 131 static void provideTo(SupplementableBase<T, isGarbageCollected>& host, const char* key, typename SupplementableTraits<T, isGarbageCollected>::SupplementArgumentType supplement) 132 { 133 host.provideSupplement(key, supplement); 134 } 135 136 static SupplementBase<T, isGarbageCollected>* from(SupplementableBase<T, isGarbageCollected>& host, const char* key) 137 { 138 return host.requireSupplement(key); 139 } 140 141 static SupplementBase<T, isGarbageCollected>* from(SupplementableBase<T, isGarbageCollected>* host, const char* key) 142 { 143 return host ? host->requireSupplement(key) : 0; 144 } 145 146 virtual void trace(Visitor*) { } 147 virtual void willBeDestroyed() { } 148 149 // FIXME: Oilpan: Remove this callback once PersistentHeapSupplementable is removed again. 150 virtual void persistentHostHasBeenDestroyed() { } 151 }; 152 153 template<typename T, bool> 154 class SupplementableTracing; 155 156 template<typename T> 157 class SupplementableTracing<T, true> { }; 158 159 template<typename T> 160 class SupplementableTracing<T, false> { }; 161 162 template<typename T, bool isGarbageCollected = false> 163 class SupplementableBase : public SupplementableTracing<T, isGarbageCollected> { 164 public: 165 void provideSupplement(const char* key, typename SupplementableTraits<T, isGarbageCollected>::SupplementArgumentType supplement) 166 { 167 ASSERT(m_threadId == currentThread()); 168 ASSERT(!this->m_supplements.get(key)); 169 this->m_supplements.set(key, supplement); 170 } 171 172 void removeSupplement(const char* key) 173 { 174 ASSERT(m_threadId == currentThread()); 175 this->m_supplements.remove(key); 176 } 177 178 SupplementBase<T, isGarbageCollected>* requireSupplement(const char* key) 179 { 180 ASSERT(m_threadId == currentThread()); 181 return this->m_supplements.get(key); 182 } 183 184 void reattachThread() 185 { 186 #if ASSERT_ENABLED 187 m_threadId = currentThread(); 188 #endif 189 } 190 191 virtual void trace(Visitor* visitor) { visitor->trace(m_supplements); } 192 193 void willBeDestroyed() 194 { 195 typedef typename SupplementableTraits<T, isGarbageCollected>::SupplementMap::iterator SupplementIterator; 196 for (SupplementIterator it = m_supplements.begin(); it != m_supplements.end(); ++it) 197 it->value->willBeDestroyed(); 198 } 199 200 // FIXME: Oilpan: Make private and remove this ignore once PersistentHeapSupplementable is removed again. 201 protected: 202 GC_PLUGIN_IGNORE("") 203 typename SupplementableTraits<T, isGarbageCollected>::SupplementMap m_supplements; 204 205 #if ASSERT_ENABLED 206 protected: 207 SupplementableBase() : m_threadId(currentThread()) { } 208 209 private: 210 ThreadIdentifier m_threadId; 211 #endif 212 }; 213 214 template<typename T> 215 class HeapSupplement : public SupplementBase<T, true> { }; 216 217 // FIXME: Oilpan: Move GarbageCollectedMixin to SupplementableBase<T, true> once PersistentHeapSupplementable is removed again. 218 template<typename T> 219 class HeapSupplementable : public SupplementableBase<T, true>, public GarbageCollectedMixin { }; 220 221 template<typename T> 222 class PersistentHeapSupplementable : public SupplementableBase<T, true> { 223 public: 224 PersistentHeapSupplementable() : m_root(this) { } 225 virtual ~PersistentHeapSupplementable() 226 { 227 typedef typename SupplementableTraits<T, true>::SupplementMap::iterator SupplementIterator; 228 for (SupplementIterator it = this->m_supplements.begin(); it != this->m_supplements.end(); ++it) 229 it->value->persistentHostHasBeenDestroyed(); 230 } 231 private: 232 class TraceDelegate : PersistentBase<ThreadLocalPersistents<AnyThread>, TraceDelegate> { 233 public: 234 TraceDelegate(PersistentHeapSupplementable* owner) : m_owner(owner) { } 235 void trace(Visitor* visitor) { m_owner->trace(visitor); } 236 private: 237 PersistentHeapSupplementable* m_owner; 238 }; 239 240 TraceDelegate m_root; 241 }; 242 243 template<typename T> 244 class Supplement : public SupplementBase<T, false> { }; 245 246 template<typename T> 247 class Supplementable : public SupplementableBase<T, false> { }; 248 249 template<typename T> 250 struct ThreadingTrait<WebCore::SupplementBase<T, true> > { 251 static const ThreadAffinity Affinity = ThreadingTrait<T>::Affinity; 252 }; 253 254 template<typename T> 255 struct ThreadingTrait<WebCore::SupplementableBase<T, true> > { 256 static const ThreadAffinity Affinity = ThreadingTrait<T>::Affinity; 257 }; 258 259 } // namespace WebCore 260 261 #endif // Supplementable_h 262