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 ENABLE(ASSERT) 36 #include "wtf/Threading.h" 37 #endif 38 39 namespace blink { 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 }; 104 105 template<typename T> 106 struct SupplementableTraits<T, false> { 107 typedef PassOwnPtr<SupplementBase<T, false> > SupplementArgumentType; 108 }; 109 110 template<bool> 111 class SupplementTracing; 112 113 template<> 114 class SupplementTracing<true> : public GarbageCollectedMixin { }; 115 116 template<> 117 class SupplementTracing<false> { 118 public: 119 virtual ~SupplementTracing() { } 120 // FIXME: Oilpan: this trace() method is only provided to minimize 121 // the use of ENABLE(OILPAN) for Supplements deriving from the 122 // transition type WillBeHeapSupplement<>. 123 // 124 // When that transition type is removed (or its use is substantially 125 // reduced), remove this dummy trace method also. 126 virtual void trace(Visitor*) { } 127 }; 128 129 template<typename T, bool isGarbageCollected = false> 130 class SupplementBase : public SupplementTracing<isGarbageCollected> { 131 public: 132 #if ENABLE(SECURITY_ASSERT) 133 virtual bool isRefCountedWrapper() const { return false; } 134 #endif 135 136 static void provideTo(SupplementableBase<T, isGarbageCollected>& host, const char* key, typename SupplementableTraits<T, isGarbageCollected>::SupplementArgumentType supplement) 137 { 138 host.provideSupplement(key, supplement); 139 } 140 141 static SupplementBase<T, isGarbageCollected>* from(SupplementableBase<T, isGarbageCollected>& host, const char* key) 142 { 143 return host.requireSupplement(key); 144 } 145 146 static SupplementBase<T, isGarbageCollected>* from(SupplementableBase<T, isGarbageCollected>* host, const char* key) 147 { 148 return host ? host->requireSupplement(key) : 0; 149 } 150 }; 151 152 template<typename T, bool isGarbageCollected> 153 class SupplementableTracing; 154 155 template<typename T> 156 class SupplementableTracing<T, true> : public GarbageCollectedMixin { 157 public: 158 virtual void trace(Visitor* visitor) 159 { 160 visitor->trace(m_supplements); 161 } 162 163 protected: 164 typedef HeapHashMap<const char*, Member<SupplementBase<T, true> >, PtrHash<const char*> > SupplementMap; 165 SupplementMap m_supplements; 166 }; 167 168 template<typename T> 169 class SupplementableTracing<T, false> { 170 protected: 171 typedef HashMap<const char*, OwnPtr<SupplementBase<T, false> >, PtrHash<const char*> > SupplementMap; 172 SupplementMap m_supplements; 173 }; 174 175 // Helper class for implementing Supplementable and HeapSupplementable. 176 template<typename T, bool isGarbageCollected = false> 177 class SupplementableBase : public SupplementableTracing<T, isGarbageCollected> { 178 public: 179 void provideSupplement(const char* key, typename SupplementableTraits<T, isGarbageCollected>::SupplementArgumentType supplement) 180 { 181 ASSERT(m_threadId == currentThread()); 182 ASSERT(!this->m_supplements.get(key)); 183 this->m_supplements.set(key, supplement); 184 } 185 186 void removeSupplement(const char* key) 187 { 188 ASSERT(m_threadId == currentThread()); 189 this->m_supplements.remove(key); 190 } 191 192 SupplementBase<T, isGarbageCollected>* requireSupplement(const char* key) 193 { 194 ASSERT(m_threadId == currentThread()); 195 return this->m_supplements.get(key); 196 } 197 198 void reattachThread() 199 { 200 #if ENABLE(ASSERT) 201 m_threadId = currentThread(); 202 #endif 203 } 204 205 #if ENABLE(ASSERT) 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 template<typename T> 218 class HeapSupplementable : public SupplementableBase<T, true> { }; 219 220 template<typename T> 221 class Supplement : public SupplementBase<T, false> { }; 222 223 template<typename T> 224 class Supplementable : public SupplementableBase<T, false> { }; 225 226 template<typename T> 227 struct ThreadingTrait<SupplementBase<T, true> > { 228 static const ThreadAffinity Affinity = ThreadingTrait<T>::Affinity; 229 }; 230 231 template<typename T> 232 struct ThreadingTrait<SupplementableBase<T, true> > { 233 static const ThreadAffinity Affinity = ThreadingTrait<T>::Affinity; 234 }; 235 236 } // namespace blink 237 238 #endif // Supplementable_h 239