/* * Copyright (C) 2013-2020 Apple 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. AND ITS CONTRIBUTORS ``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 ITS 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. */ #pragma once #include #include #include #include #include #include #if ASAN_ENABLED extern "C" void __asan_poison_memory_region(void const volatile *addr, size_t size); extern "C" void __asan_unpoison_memory_region(void const volatile *addr, size_t size); extern "C" int __asan_address_is_poisoned(void const volatile *addr); #endif namespace WTF { inline void adopted(const void*) { } template class Ref; template> Ref adoptRef(T&); template class Ref { public: using PtrTraits = Traits; static constexpr bool isRef = true; ~Ref() { #if ASAN_ENABLED if (__asan_address_is_poisoned(this)) __asan_unpoison_memory_region(this, sizeof(*this)); #endif if (auto* ptr = PtrTraits::exchange(m_ptr, nullptr)) ptr->deref(); } Ref(T& object) : m_ptr(&object) { object.ref(); } Ref(const Ref& other) : m_ptr(other.ptr()) { m_ptr->ref(); } template Ref(const Ref& other) : m_ptr(other.ptr()) { m_ptr->ref(); } Ref(Ref&& other) : m_ptr(&other.leakRef()) { ASSERT(m_ptr); } template Ref(Ref&& other) : m_ptr(&other.leakRef()) { ASSERT(m_ptr); } Ref& operator=(T&); Ref& operator=(Ref&&); template Ref& operator=(Ref&&); Ref& operator=(const Ref&); template Ref& operator=(const Ref&); template void swap(Ref&); // Hash table deleted values, which are only constructed and never copied or destroyed. Ref(HashTableDeletedValueType) : m_ptr(PtrTraits::hashTableDeletedValue()) { } bool isHashTableDeletedValue() const { return PtrTraits::isHashTableDeletedValue(m_ptr); } Ref(HashTableEmptyValueType) : m_ptr(hashTableEmptyValue()) { } bool isHashTableEmptyValue() const { return m_ptr == hashTableEmptyValue(); } static T* hashTableEmptyValue() { return nullptr; } const T* ptrAllowingHashTableEmptyValue() const { ASSERT(m_ptr || isHashTableEmptyValue()); return PtrTraits::unwrap(m_ptr); } T* ptrAllowingHashTableEmptyValue() { ASSERT(m_ptr || isHashTableEmptyValue()); return PtrTraits::unwrap(m_ptr); } T* operator->() const { ASSERT(m_ptr); return PtrTraits::unwrap(m_ptr); } T* ptr() const RETURNS_NONNULL { ASSERT(m_ptr); return PtrTraits::unwrap(m_ptr); } T& get() const { ASSERT(m_ptr); return *PtrTraits::unwrap(m_ptr); } operator T&() const { ASSERT(m_ptr); return *PtrTraits::unwrap(m_ptr); } bool operator!() const { ASSERT(m_ptr); return !*m_ptr; } template Ref replace(Ref&&) WARN_UNUSED_RETURN; // The following function is deprecated. Ref copyRef() && = delete; Ref copyRef() const & WARN_UNUSED_RETURN { return Ref(*m_ptr); } T& leakRef() WARN_UNUSED_RETURN { ASSERT(m_ptr); T& result = *PtrTraits::exchange(m_ptr, nullptr); #if ASAN_ENABLED __asan_poison_memory_region(this, sizeof(*this)); #endif return result; } private: friend Ref adoptRef(T&); template friend class Ref; enum AdoptTag { Adopt }; Ref(T& object, AdoptTag) : m_ptr(&object) { } typename PtrTraits::StorageType m_ptr; }; template Ref adoptRef(T&); template Ref makeRef(T&); template inline Ref& Ref::operator=(T& reference) { Ref copiedReference = reference; swap(copiedReference); return *this; } template inline Ref& Ref::operator=(Ref&& reference) { #if ASAN_ENABLED if (__asan_address_is_poisoned(this)) __asan_unpoison_memory_region(this, sizeof(*this)); #endif Ref movedReference = WTFMove(reference); swap(movedReference); return *this; } template template inline Ref& Ref::operator=(Ref&& reference) { #if ASAN_ENABLED if (__asan_address_is_poisoned(this)) __asan_unpoison_memory_region(this, sizeof(*this)); #endif Ref movedReference = WTFMove(reference); swap(movedReference); return *this; } template inline Ref& Ref::operator=(const Ref& reference) { #if ASAN_ENABLED if (__asan_address_is_poisoned(this)) __asan_unpoison_memory_region(this, sizeof(*this)); #endif Ref copiedReference = reference; swap(copiedReference); return *this; } template template inline Ref& Ref::operator=(const Ref& reference) { #if ASAN_ENABLED if (__asan_address_is_poisoned(this)) __asan_unpoison_memory_region(this, sizeof(*this)); #endif Ref copiedReference = reference; swap(copiedReference); return *this; } template template inline void Ref::swap(Ref& other) { U::swap(m_ptr, other.m_ptr); } template>::value || !std::is_same>::value>> inline void swap(Ref& a, Ref& b) { a.swap(b); } template template inline Ref Ref::replace(Ref&& reference) { #if ASAN_ENABLED if (__asan_address_is_poisoned(this)) __asan_unpoison_memory_region(this, sizeof(*this)); #endif auto oldReference = adoptRef(*m_ptr); m_ptr = &reference.leakRef(); return oldReference; } template, typename X, typename Y> inline Ref static_reference_cast(Ref& reference) { return Ref(static_cast(reference.get())); } template, typename X, typename Y> inline Ref static_reference_cast(Ref&& reference) { return adoptRef(static_cast(reference.leakRef())); } template, typename X, typename Y> inline Ref static_reference_cast(const Ref& reference) { return Ref(static_cast(reference.copyRef().get())); } template struct GetPtrHelper> { typedef T* PtrType; static T* getPtr(const Ref& p) { return const_cast(p.ptr()); } }; template struct IsSmartPtr> { static constexpr bool value = true; }; template inline Ref adoptRef(T& reference) { adopted(&reference); return Ref(reference, Ref::Adopt); } template inline Ref makeRef(T& reference) { return Ref(reference); } template inline bool is(Ref& source) { return is(source.get()); } template inline bool is(const Ref& source) { return is(source.get()); } template inline bool operator==(const Ref& a, const Ref& b) { return a.ptr() == b.ptr(); } template inline bool operator==(const Ref& a, V& b) { return a.ptr() == &b; } template inline bool operator==(T& a, const Ref& b) { return &a == b.ptr(); } template inline bool operator!=(const Ref& a, const Ref& b) { return a.ptr() != b.ptr(); } template inline bool operator!=(const Ref& a, V& b) { return a.ptr() != &b; } template inline bool operator!=(T& a, const Ref& b) { return &a != b.ptr(); } } // namespace WTF using WTF::Ref; using WTF::adoptRef; using WTF::makeRef; using WTF::static_reference_cast;