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 39namespace 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 91template<typename T, bool isGarbageCollected> 92class SupplementBase; 93 94template<typename T, bool isGarbageCollected> 95class SupplementableBase; 96 97template<typename T, bool isGarbageCollected> 98struct SupplementableTraits; 99 100template<typename T> 101struct SupplementableTraits<T, true> { 102 typedef RawPtr<SupplementBase<T, true> > SupplementArgumentType; 103}; 104 105template<typename T> 106struct SupplementableTraits<T, false> { 107 typedef PassOwnPtr<SupplementBase<T, false> > SupplementArgumentType; 108}; 109 110template<bool> 111class SupplementTracing; 112 113template<> 114class SupplementTracing<true> : public GarbageCollectedMixin { }; 115 116template<> 117class SupplementTracing<false> { 118public: 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 129template<typename T, bool isGarbageCollected = false> 130class SupplementBase : public SupplementTracing<isGarbageCollected> { 131public: 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 152template<typename T, bool isGarbageCollected> 153class SupplementableTracing; 154 155template<typename T> 156class SupplementableTracing<T, true> : public GarbageCollectedMixin { 157public: 158 virtual void trace(Visitor* visitor) 159 { 160 visitor->trace(m_supplements); 161 } 162 163protected: 164 typedef HeapHashMap<const char*, Member<SupplementBase<T, true> >, PtrHash<const char*> > SupplementMap; 165 SupplementMap m_supplements; 166}; 167 168template<typename T> 169class SupplementableTracing<T, false> { 170protected: 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. 176template<typename T, bool isGarbageCollected = false> 177class SupplementableBase : public SupplementableTracing<T, isGarbageCollected> { 178public: 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) 206protected: 207 SupplementableBase() : m_threadId(currentThread()) { } 208 209private: 210 ThreadIdentifier m_threadId; 211#endif 212}; 213 214template<typename T> 215class HeapSupplement : public SupplementBase<T, true> { }; 216 217template<typename T> 218class HeapSupplementable : public SupplementableBase<T, true> { }; 219 220template<typename T> 221class Supplement : public SupplementBase<T, false> { }; 222 223template<typename T> 224class Supplementable : public SupplementableBase<T, false> { }; 225 226template<typename T> 227struct ThreadingTrait<SupplementBase<T, true> > { 228 static const ThreadAffinity Affinity = ThreadingTrait<T>::Affinity; 229}; 230 231template<typename T> 232struct ThreadingTrait<SupplementableBase<T, true> > { 233 static const ThreadAffinity Affinity = ThreadingTrait<T>::Affinity; 234}; 235 236} // namespace blink 237 238#endif // Supplementable_h 239