/* * Copyright (C) 2012 Google, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef SKY_ENGINE_PLATFORM_SUPPLEMENTABLE_H_ #define SKY_ENGINE_PLATFORM_SUPPLEMENTABLE_H_ #include "sky/engine/platform/heap/Handle.h" #include "sky/engine/wtf/Assertions.h" #include "sky/engine/wtf/HashMap.h" #include "sky/engine/wtf/OwnPtr.h" #include "sky/engine/wtf/PassOwnPtr.h" #if ENABLE(ASSERT) #include "sky/engine/wtf/Threading.h" #endif namespace blink { // What you should know about Supplementable and Supplement // ======================================================== // Supplementable and Supplement instances are meant to be thread local. They // should only be accessed from within the thread that created them. The // 2 classes are not designed for safe access from another thread. Violating // this design assumption can result in memory corruption and unpredictable // behavior. // // What you should know about the Supplement keys // ============================================== // The Supplement is expected to use the same const char* string instance // as its key. The Supplementable's SupplementMap will use the address of the // string as the key and not the characters themselves. Hence, 2 strings with // the same characters will be treated as 2 different keys. // // In practice, it is recommended that Supplements implements a static method // for returning its key to use. For example: // // class MyClass : public Supplement { // ... // static const char* supplementName(); // } // // const char* MyClass::supplementName() // { // return "MyClass"; // } // // An example of the using the key: // // MyClass* MyClass::from(MySupplementable* host) // { // return reinterpret_cast(Supplement::from(host, supplementName())); // } // // What you should know about thread checks // ======================================== // When assertion is enabled this class performs thread-safety check so that // provideTo and from happen on the same thread. If you want to provide // some value for Workers this thread check may not work very well though, // since in most case you'd provide the value while worker preparation is // being done on the main thread, even before the worker thread is started. // If that's the case you can explicitly call reattachThread() when the // Supplementable object is passed to the final destination thread (i.e. // worker thread). Please be extremely careful to use the method though, // as randomly calling the method could easily cause racy condition. // // Note that reattachThread() does nothing if assertion is not enabled. // template class SupplementBase; template class SupplementableBase; template struct SupplementableTraits; template struct SupplementableTraits { typedef PassOwnPtr > SupplementArgumentType; typedef HashMap >, PtrHash > SupplementMap; }; template class SupplementTracing; template<> class SupplementTracing { public: virtual ~SupplementTracing() { } }; template class SupplementBase : public SupplementTracing { public: #if ENABLE(SECURITY_ASSERT) virtual bool isRefCountedWrapper() const { return false; } #endif static void provideTo(SupplementableBase& host, const char* key, typename SupplementableTraits::SupplementArgumentType supplement) { host.provideSupplement(key, supplement); } static SupplementBase* from(SupplementableBase& host, const char* key) { return host.requireSupplement(key); } static SupplementBase* from(SupplementableBase* host, const char* key) { return host ? host->requireSupplement(key) : 0; } }; // Helper class for implementing Supplementable, HeapSupplementable, and // PersistentHeapSupplementable. template class SupplementableBase { public: void provideSupplement(const char* key, typename SupplementableTraits::SupplementArgumentType supplement) { ASSERT(m_threadId == currentThread()); ASSERT(!this->m_supplements.get(key)); this->m_supplements.set(key, supplement); } void removeSupplement(const char* key) { ASSERT(m_threadId == currentThread()); this->m_supplements.remove(key); } SupplementBase* requireSupplement(const char* key) { ASSERT(m_threadId == currentThread()); return this->m_supplements.get(key); } void reattachThread() { #if ENABLE(ASSERT) m_threadId = currentThread(); #endif } // We have a trace method in the SupplementableBase class to ensure we have // the vtable at the first word of the object. However we don't trace the // m_supplements here, but in the partially specialized template subclasses // since we only want to trace it for garbage collected classes. // FIXME: Oilpan: Make private and remove this ignore once PersistentHeapSupplementable is removed again. protected: typename SupplementableTraits::SupplementMap m_supplements; #if ENABLE(ASSERT) protected: SupplementableBase() : m_threadId(currentThread()) { } private: ThreadIdentifier m_threadId; #endif }; template class Supplement : public SupplementBase { }; // This class is used to make an off-heap class supplementable with off-heap // supplements (Supplement). template class Supplementable : public SupplementableBase { }; } // namespace blink #endif // SKY_ENGINE_PLATFORM_SUPPLEMENTABLE_H_