Diff
Modified: trunk/Source/WTF/ChangeLog (226014 => 226015)
--- trunk/Source/WTF/ChangeLog 2017-12-17 21:15:28 UTC (rev 226014)
+++ trunk/Source/WTF/ChangeLog 2017-12-17 23:22:18 UTC (rev 226015)
@@ -1,3 +1,64 @@
+2017-12-17 Mark Lam <[email protected]>
+
+ Enhance Ref and RefPtr to be able to work with smart pointers.
+ https://bugs.webkit.org/show_bug.cgi?id=180762
+ <rdar://problem/36027122>
+
+ Reviewed by JF Bastien and Darin Adler.
+
+ This is so we can use them with ConstExprPoisoned pointers to make PoisonedRef
+ and PoisonedRefPtr.
+
+ * WTF.xcodeproj/project.pbxproj:
+ * wtf/CMakeLists.txt:
+ * wtf/DumbPtrTraits.h: Added.
+ (WTF::DumbPtrTraits::exchange):
+ (WTF::DumbPtrTraits::swap):
+ (WTF::DumbPtrTraits::unwrap):
+ * wtf/Forward.h:
+ * wtf/Poisoned.h:
+ (WTF::ConstExprPoisonedPtrTraits::exchange):
+ (WTF::ConstExprPoisonedPtrTraits::swap):
+ (WTF::ConstExprPoisonedPtrTraits::unwrap):
+ * wtf/Ref.h:
+ (WTF::Ref::~Ref):
+ (WTF::Ref::Ref):
+ (WTF::Ref::ptrAllowingHashTableEmptyValue const):
+ (WTF::Ref::ptrAllowingHashTableEmptyValue):
+ (WTF::Ref::operator-> const):
+ (WTF::Ref::get const):
+ (WTF::Ref::operator T& const):
+ (WTF::=):
+ (WTF::U>::swap):
+ (WTF::swap):
+ (WTF::U>::replace):
+ (WTF::static_reference_cast):
+ (WTF::adoptRef):
+ (WTF::is):
+ (WTF::Ref<T>::swap): Deleted.
+ (WTF::Ref<T>::replace): Deleted.
+ (WTF::GetPtrHelper<Ref<T>>::getPtr): Deleted.
+ * wtf/RefPtr.cpp: Added.
+ * wtf/RefPtr.h:
+ (WTF::RefPtr::RefPtr):
+ (WTF::RefPtr::~RefPtr):
+ (WTF::RefPtr::get const):
+ (WTF::RefPtr::operator* const):
+ (WTF::RefPtr::operator-> const):
+ (WTF::U>::RefPtr):
+ (WTF::U>::leakRef):
+ (WTF::=):
+ (WTF::U>::swap):
+ (WTF::swap):
+ (WTF::operator==):
+ (WTF::operator!=):
+ (WTF::static_pointer_cast):
+ (WTF::adoptRef):
+ (WTF::is):
+ (WTF::RefPtr<T>::RefPtr): Deleted.
+ (WTF::RefPtr<T>::leakRef): Deleted.
+ (WTF::RefPtr<T>::swap): Deleted.
+
2017-12-16 Yusuke Suzuki <[email protected]>
Remove unnecessary boolean result of start() functions
Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (226014 => 226015)
--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj 2017-12-17 21:15:28 UTC (rev 226014)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj 2017-12-17 23:22:18 UTC (rev 226015)
@@ -150,6 +150,7 @@
E3A32BC41FC830E2007D7E76 /* JSValueMalloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3A32BC21FC830E2007D7E76 /* JSValueMalloc.cpp */; };
E4A0AD391A96245500536DF6 /* WorkQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A0AD371A96245500536DF6 /* WorkQueue.cpp */; };
E4A0AD3D1A96253C00536DF6 /* WorkQueueCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A0AD3C1A96253C00536DF6 /* WorkQueueCocoa.cpp */; };
+ FE05FAFF1FE5007500093230 /* RefPtr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAFE1FE5007500093230 /* RefPtr.cpp */; };
FE85416E1FBE285D008DA5DA /* Poisoned.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE85416C1FBE285B008DA5DA /* Poisoned.cpp */; };
FEDACD3D1630F83F00C69634 /* StackStats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEDACD3B1630F83F00C69634 /* StackStats.cpp */; };
/* End PBXBuildFile section */
@@ -616,6 +617,8 @@
EB95E1EF161A72410089A2F5 /* ByteOrder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByteOrder.h; sourceTree = "<group>"; };
EF7D6CD59D8642A8A0DA86AD /* StackTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackTrace.h; sourceTree = "<group>"; };
F72BBDB107FA424886178B9E /* SymbolImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolImpl.cpp; sourceTree = "<group>"; };
+ FE05FAE61FDB214300093230 /* DumbPtrTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumbPtrTraits.h; sourceTree = "<group>"; };
+ FE05FAFE1FE5007500093230 /* RefPtr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RefPtr.cpp; sourceTree = "<group>"; };
FE8225301B2A1E5B00BA68FD /* NakedPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NakedPtr.h; sourceTree = "<group>"; };
FE85416C1FBE285B008DA5DA /* Poisoned.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Poisoned.cpp; sourceTree = "<group>"; };
FE85416D1FBE285C008DA5DA /* Poisoned.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Poisoned.h; sourceTree = "<group>"; };
@@ -848,6 +851,7 @@
A8A4727F151A825A004123FF /* DispatchPtr.h */,
0F4570421BE5B58F0062A629 /* Dominators.h */,
A8A47280151A825A004123FF /* DoublyLinkedList.h */,
+ FE05FAE61FDB214300093230 /* DumbPtrTraits.h */,
A8A47297151A825A004123FF /* dtoa.cpp */,
A8A47298151A825A004123FF /* dtoa.h */,
1AEA88E11D6BBCF400E5AD64 /* EnumTraits.h */,
@@ -1004,6 +1008,7 @@
A8A47301151A825B004123FF /* RefCountedLeakCounter.cpp */,
A8A47302151A825B004123FF /* RefCountedLeakCounter.h */,
86F46F5F1A2840EE00CCBF22 /* RefCounter.h */,
+ FE05FAFE1FE5007500093230 /* RefPtr.cpp */,
A8A47303151A825B004123FF /* RefPtr.h */,
A8A47305151A825B004123FF /* RetainPtr.h */,
2CDED0F118115C85004DBA70 /* RunLoop.cpp */,
@@ -1411,6 +1416,7 @@
0F66B28A1DC97BAB004A1D3F /* ClockType.cpp in Sources */,
A8A47460151A825B004123FF /* CollatorDefault.cpp in Sources */,
A8A47463151A825B004123FF /* CollatorICU.cpp in Sources */,
+ FE05FAFF1FE5007500093230 /* RefPtr.cpp in Sources */,
0F8F2B92172E0103007DBDA5 /* CompilationThread.cpp in Sources */,
E38C41281EB4E0680042957D /* CPUTime.cpp in Sources */,
E38C41251EB4E04C0042957D /* CPUTimeCocoa.mm in Sources */,
Modified: trunk/Source/WTF/wtf/CMakeLists.txt (226014 => 226015)
--- trunk/Source/WTF/wtf/CMakeLists.txt 2017-12-17 21:15:28 UTC (rev 226014)
+++ trunk/Source/WTF/wtf/CMakeLists.txt 2017-12-17 23:22:18 UTC (rev 226015)
@@ -37,6 +37,7 @@
Deque.h
DisallowCType.h
DoublyLinkedList.h
+ DumbPtrTraits.h
FastMalloc.h
FastTLS.h
FeatureDefines.h
@@ -268,6 +269,7 @@
RandomNumber.cpp
ReadWriteLock.cpp
RefCountedLeakCounter.cpp
+ RefPtr.cpp
RunLoop.cpp
SHA1.cpp
Seconds.cpp
Added: trunk/Source/WTF/wtf/DumbPtrTraits.h (0 => 226015)
--- trunk/Source/WTF/wtf/DumbPtrTraits.h (rev 0)
+++ trunk/Source/WTF/wtf/DumbPtrTraits.h 2017-12-17 23:22:18 UTC (rev 226015)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 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. ``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.
+ */
+
+#pragma once
+
+#include <utility>
+
+namespace WTF {
+
+template<typename T>
+struct DumbPtrTraits {
+ using StorageType = T*;
+
+ template<typename U>
+ static ALWAYS_INLINE T* exchange(StorageType& ptr, U&& newValue) { return std::exchange(ptr, newValue); }
+
+ static ALWAYS_INLINE void swap(StorageType& a, StorageType& b) { std::swap(a, b); }
+ static ALWAYS_INLINE T* unwrap(const StorageType& ptr) { return ptr; }
+};
+
+} // namespace WTF
+
Modified: trunk/Source/WTF/wtf/Forward.h (226014 => 226015)
--- trunk/Source/WTF/wtf/Forward.h 2017-12-17 21:15:28 UTC (rev 226014)
+++ trunk/Source/WTF/wtf/Forward.h 2017-12-17 23:22:18 UTC (rev 226015)
@@ -48,12 +48,13 @@
struct FastMalloc;
template<typename> class CompletionHandler;
+template<typename T> struct DumbPtrTraits;
template<typename> class Function;
template<typename> class LazyNeverDestroyed;
template<typename> class NeverDestroyed;
template<typename> class OptionSet;
-template<typename> class Ref;
-template<typename> class RefPtr;
+template<typename T, typename = DumbPtrTraits<T>> class Ref;
+template<typename T, typename = DumbPtrTraits<T>> class RefPtr;
template<typename> class StringBuffer;
template<typename, typename = void> class StringTypeAdapter;
Modified: trunk/Source/WTF/wtf/Poisoned.h (226014 => 226015)
--- trunk/Source/WTF/wtf/Poisoned.h 2017-12-17 21:15:28 UTC (rev 226014)
+++ trunk/Source/WTF/wtf/Poisoned.h 2017-12-17 23:22:18 UTC (rev 226015)
@@ -228,6 +228,18 @@
template<uint32_t key, typename T>
using ConstExprPoisoned = PoisonedImpl<uintptr_t, makePoison(key), T>;
+template<uint32_t key, typename T>
+struct ConstExprPoisonedPtrTraits {
+ using StorageType = ConstExprPoisoned<key, T*>;
+
+ template<class U> static ALWAYS_INLINE T* exchange(StorageType& ptr, U&& newValue) { return ptr.exchange(newValue); }
+
+ template<typename K1, K1 k1, typename T1, typename K2, K2 k2, typename T2>
+ static ALWAYS_INLINE void swap(PoisonedImpl<K1, k1, T1>& a, PoisonedImpl<K2, k2, T2>& b) { a.swap(b); }
+
+ static ALWAYS_INLINE T* unwrap(const StorageType& ptr) { return ptr.unpoisoned(); }
+};
+
} // namespace WTF
using WTF::ConstExprPoisoned;
Modified: trunk/Source/WTF/wtf/Ref.h (226014 => 226015)
--- trunk/Source/WTF/wtf/Ref.h 2017-12-17 21:15:28 UTC (rev 226014)
+++ trunk/Source/WTF/wtf/Ref.h 2017-12-17 23:22:18 UTC (rev 226015)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,6 +27,8 @@
#define WTF_Ref_h
#include <wtf/Assertions.h>
+#include <wtf/DumbPtrTraits.h>
+#include <wtf/Forward.h>
#include <wtf/GetPtr.h>
#include <wtf/StdLibExtras.h>
#include <wtf/TypeCasts.h>
@@ -41,10 +43,11 @@
inline void adopted(const void*) { }
-template<typename T> class Ref;
-template<typename T> Ref<T> adoptRef(T&);
+template<typename T, typename PtrTraits> class Ref;
+template<typename T, typename PtrTraits = DumbPtrTraits<T>> Ref<T, PtrTraits> adoptRef(T&);
-template<typename T> class Ref {
+template<typename T, typename PtrTraits>
+class Ref {
public:
static constexpr bool isRef = true;
@@ -55,18 +58,18 @@
__asan_unpoison_memory_region(this, sizeof(*this));
#endif
if (m_ptr)
- m_ptr->deref();
+ PtrTraits::unwrap(m_ptr)->deref();
}
Ref(T& object)
: m_ptr(&object)
{
- m_ptr->ref();
+ object.ref();
}
// Use copyRef() instead.
Ref(const Ref& other) = delete;
- template<typename U> Ref(const Ref<U>& other) = delete;
+ template<typename X, typename Y> Ref(const Ref<X, Y>& other) = delete;
Ref(Ref&& other)
: m_ptr(&other.leakRef())
@@ -74,8 +77,8 @@
ASSERT(m_ptr);
}
- template<typename U>
- Ref(Ref<U>&& other)
+ template<typename X, typename Y>
+ Ref(Ref<X, Y>&& other)
: m_ptr(&other.leakRef())
{
ASSERT(m_ptr);
@@ -83,13 +86,13 @@
Ref& operator=(T&);
Ref& operator=(Ref&&);
- template<typename U> Ref& operator=(Ref<U>&&);
+ template<typename X, typename Y> Ref& operator=(Ref<X, Y>&&);
// Use copyRef() and the move assignment operators instead.
Ref& operator=(const Ref&) = delete;
- template<typename U> Ref& operator=(const Ref<U>&) = delete;
+ template<typename X, typename Y> Ref& operator=(const Ref<X, Y>&) = delete;
- void swap(Ref&);
+ template<typename X, typename Y> void swap(Ref<X, Y>&);
// Hash table deleted values, which are only constructed and never copied or destroyed.
Ref(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
@@ -100,8 +103,8 @@
bool isHashTableEmptyValue() const { return m_ptr == hashTableEmptyValue(); }
static T* hashTableEmptyValue() { return nullptr; }
- const T* ptrAllowingHashTableEmptyValue() const { ASSERT(m_ptr || isHashTableEmptyValue()); return m_ptr; }
- T* ptrAllowingHashTableEmptyValue() { ASSERT(m_ptr || isHashTableEmptyValue()); return m_ptr; }
+ const T* ptrAllowingHashTableEmptyValue() const { ASSERT(m_ptr || isHashTableEmptyValue()); return PtrTraits::unwrap(m_ptr); }
+ T* ptrAllowingHashTableEmptyValue() { ASSERT(m_ptr || isHashTableEmptyValue()); return PtrTraits::unwrap(m_ptr); }
void assignToHashTableEmptyValue(Ref&& reference)
{
@@ -110,13 +113,13 @@
ASSERT(m_ptr);
}
- T* operator->() const { ASSERT(m_ptr); return m_ptr; }
- T* ptr() const RETURNS_NONNULL { ASSERT(m_ptr); return m_ptr; }
- T& get() const { ASSERT(m_ptr); return *m_ptr; }
- operator T&() const { ASSERT(m_ptr); return *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<typename U> Ref<T> replace(Ref<U>&&) WARN_UNUSED_RETURN;
+ template<typename X, typename Y> Ref<T, PtrTraits> replace(Ref<X, Y>&&) WARN_UNUSED_RETURN;
#if COMPILER_SUPPORTS(CXX_REFERENCE_QUALIFIED_FUNCTIONS)
Ref copyRef() && = delete;
@@ -129,7 +132,7 @@
{
ASSERT(m_ptr);
- T& result = *std::exchange(m_ptr, nullptr);
+ T& result = *PtrTraits::exchange(m_ptr, nullptr);
#if ASAN_ENABLED
__asan_poison_memory_region(this, sizeof(*this));
#endif
@@ -138,6 +141,7 @@
private:
friend Ref adoptRef<T>(T&);
+ template<typename X, typename Y> friend class Ref;
enum AdoptTag { Adopt };
Ref(T& object, AdoptTag)
@@ -145,14 +149,14 @@
{
}
- T* m_ptr;
+ typename PtrTraits::StorageType m_ptr;
};
-template<typename T> void swap(Ref<T>&, Ref<T>&);
-template<typename T> Ref<T> adoptRef(T&);
+template<typename T, typename U> Ref<T, U> adoptRef(T&);
template<typename T> Ref<T> makeRef(T&);
-template<typename T> inline Ref<T>& Ref<T>::operator=(T& reference)
+template<typename T, typename U>
+inline Ref<T, U>& Ref<T, U>::operator=(T& reference)
{
Ref copiedReference = reference;
swap(copiedReference);
@@ -159,7 +163,8 @@
return *this;
}
-template<typename T> inline Ref<T>& Ref<T>::operator=(Ref&& reference)
+template<typename T, typename U>
+inline Ref<T, U>& Ref<T, U>::operator=(Ref&& reference)
{
Ref movedReference = WTFMove(reference);
swap(movedReference);
@@ -166,7 +171,9 @@
return *this;
}
-template<typename T> template<typename U> inline Ref<T>& Ref<T>::operator=(Ref<U>&& reference)
+template<typename T, typename U>
+template<typename X, typename Y>
+inline Ref<T, U>& Ref<T, U>::operator=(Ref<X, Y>&& reference)
{
Ref movedReference = WTFMove(reference);
swap(movedReference);
@@ -173,17 +180,22 @@
return *this;
}
-template<typename T> inline void Ref<T>::swap(Ref& other)
+template<typename T, typename U>
+template<typename X, typename Y>
+inline void Ref<T, U>::swap(Ref<X, Y>& other)
{
- std::swap(m_ptr, other.m_ptr);
+ U::swap(m_ptr, other.m_ptr);
}
-template<typename T> inline void swap(Ref<T>& a, Ref<T>& b)
+template<typename T, typename U, typename X, typename Y, typename = std::enable_if_t<!std::is_same<U, DumbPtrTraits<T>>::value || !std::is_same<Y, DumbPtrTraits<X>>::value>>
+inline void swap(Ref<T, U>& a, Ref<X, Y>& b)
{
a.swap(b);
}
-template<typename T> template<typename U> inline Ref<T> Ref<T>::replace(Ref<U>&& reference)
+template<typename T, typename U>
+template<typename X, typename Y>
+inline Ref<T, U> Ref<T, U>::replace(Ref<X, Y>&& reference)
{
auto oldReference = adoptRef(*m_ptr);
m_ptr = &reference.leakRef();
@@ -190,37 +202,40 @@
return oldReference;
}
-template<typename T, typename U> inline Ref<T> static_reference_cast(Ref<U>& reference)
+template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
+inline Ref<T, U> static_reference_cast(Ref<X, Y>& reference)
{
- return Ref<T>(static_cast<T&>(reference.get()));
+ return Ref<T, U>(static_cast<T&>(reference.get()));
}
-template<typename T, typename U> inline Ref<T> static_reference_cast(Ref<U>&& reference)
+template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
+inline Ref<T, U> static_reference_cast(Ref<X, Y>&& reference)
{
return adoptRef(static_cast<T&>(reference.leakRef()));
}
-template<typename T, typename U> inline Ref<T> static_reference_cast(const Ref<U>& reference)
+template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
+inline Ref<T, U> static_reference_cast(const Ref<X, Y>& reference)
{
- return Ref<T>(static_cast<T&>(reference.copyRef().get()));
+ return Ref<T, U>(static_cast<T&>(reference.copyRef().get()));
}
-template <typename T>
-struct GetPtrHelper<Ref<T>> {
+template <typename T, typename U>
+struct GetPtrHelper<Ref<T, U>> {
typedef T* PtrType;
- static T* getPtr(const Ref<T>& p) { return const_cast<T*>(p.ptr()); }
+ static T* getPtr(const Ref<T, U>& p) { return const_cast<T*>(p.ptr()); }
};
-template <typename T>
-struct IsSmartPtr<Ref<T>> {
+template <typename T, typename U>
+struct IsSmartPtr<Ref<T, U>> {
static const bool value = true;
};
-template<typename T>
-inline Ref<T> adoptRef(T& reference)
+template<typename T, typename U>
+inline Ref<T, U> adoptRef(T& reference)
{
adopted(&reference);
- return Ref<T>(reference, Ref<T>::Adopt);
+ return Ref<T, U>(reference, Ref<T, U>::Adopt);
}
template<typename T>
@@ -229,18 +244,26 @@
return Ref<T>(reference);
}
-template<typename ExpectedType, typename ArgType> inline bool is(Ref<ArgType>& source)
+template<typename ExpectedType, typename ArgType, typename PtrTraits>
+inline bool is(Ref<ArgType, PtrTraits>& source)
{
return is<ExpectedType>(source.get());
}
-template<typename ExpectedType, typename ArgType> inline bool is(const Ref<ArgType>& source)
+template<typename ExpectedType, typename ArgType, typename PtrTraits>
+inline bool is(const Ref<ArgType, PtrTraits>& source)
{
return is<ExpectedType>(source.get());
}
+template<uint32_t key, typename T> struct ConstExprPoisonedPtrTraits;
+
+template<uint32_t key, typename T>
+using PoisonedRef = Ref<T, ConstExprPoisonedPtrTraits<key, T>>;
+
} // namespace WTF
+using WTF::PoisonedRef;
using WTF::Ref;
using WTF::adoptRef;
using WTF::makeRef;
Added: trunk/Source/WTF/wtf/RefPtr.cpp (0 => 226015)
--- trunk/Source/WTF/wtf/RefPtr.cpp (rev 0)
+++ trunk/Source/WTF/wtf/RefPtr.cpp 2017-12-17 23:22:18 UTC (rev 226015)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 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. ``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.
+ */
+
+#include "config.h"
+#include "RefPtr.h"
+
+#include "Poisoned.h"
+
+namespace WTF {
+
+struct DummyClass { };
+
+static_assert(sizeof(Ref<DummyClass>) == sizeof(DummyClass*), "");
+static_assert(sizeof(PoisonedRef<0xffff, DummyClass>) == sizeof(DummyClass*), "");
+
+static_assert(sizeof(RefPtr<DummyClass>) == sizeof(DummyClass*), "");
+static_assert(sizeof(PoisonedRefPtr<0xffff, DummyClass>) == sizeof(DummyClass*), "");
+
+} // namespace WTF
+
Modified: trunk/Source/WTF/wtf/RefPtr.h (226014 => 226015)
--- trunk/Source/WTF/wtf/RefPtr.h 2017-12-17 21:15:28 UTC (rev 226014)
+++ trunk/Source/WTF/wtf/RefPtr.h 2017-12-17 23:22:18 UTC (rev 226015)
@@ -30,8 +30,8 @@
namespace WTF {
-template<typename T> class RefPtr;
-template<typename T> RefPtr<T> adoptRef(T*);
+template<typename T, typename PtrTraits> class RefPtr;
+template<typename T, typename PtrTraits = DumbPtrTraits<T>> RefPtr<T, PtrTraits> adoptRef(T*);
template<typename T> ALWAYS_INLINE void refIfNotNull(T* ptr)
{
@@ -45,7 +45,8 @@
ptr->deref();
}
-template<typename T> class RefPtr {
+template<typename T, typename PtrTraits>
+class RefPtr {
WTF_MAKE_FAST_ALLOCATED;
public:
typedef T ValueType;
@@ -55,20 +56,20 @@
ALWAYS_INLINE constexpr RefPtr() : m_ptr(nullptr) { }
ALWAYS_INLINE RefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); }
- ALWAYS_INLINE RefPtr(const RefPtr& o) : m_ptr(o.m_ptr) { refIfNotNull(m_ptr); }
- template<typename U> RefPtr(const RefPtr<U>& o) : m_ptr(o.get()) { refIfNotNull(m_ptr); }
+ ALWAYS_INLINE RefPtr(const RefPtr& o) : m_ptr(o.m_ptr) { refIfNotNull(PtrTraits::unwrap(m_ptr)); }
+ template<typename X, typename Y> RefPtr(const RefPtr<X, Y>& o) : m_ptr(o.get()) { refIfNotNull(PtrTraits::unwrap(m_ptr)); }
ALWAYS_INLINE RefPtr(RefPtr&& o) : m_ptr(o.leakRef()) { }
- template<typename U> RefPtr(RefPtr<U>&& o) : m_ptr(o.leakRef()) { }
- template<typename U> RefPtr(Ref<U>&&);
+ template<typename X, typename Y> RefPtr(RefPtr<X, Y>&& o) : m_ptr(o.leakRef()) { }
+ template<typename X, typename Y> RefPtr(Ref<X, Y>&&);
// Hash table deleted values, which are only constructed and never copied or destroyed.
RefPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
- ALWAYS_INLINE ~RefPtr() { derefIfNotNull(std::exchange(m_ptr, nullptr)); }
+ ALWAYS_INLINE ~RefPtr() { derefIfNotNull(PtrTraits::exchange(m_ptr, nullptr)); }
- T* get() const { return m_ptr; }
+ T* get() const { return PtrTraits::unwrap(m_ptr); }
Ref<T> releaseNonNull() { ASSERT(m_ptr); Ref<T> tmp(adoptRef(*m_ptr)); m_ptr = nullptr; return tmp; }
Ref<const T> releaseConstNonNull() { ASSERT(m_ptr); Ref<const T> tmp(adoptRef(*m_ptr)); m_ptr = nullptr; return tmp; }
@@ -75,8 +76,8 @@
T* leakRef() WARN_UNUSED_RETURN;
- T& operator*() const { ASSERT(m_ptr); return *m_ptr; }
- ALWAYS_INLINE T* operator->() const { return m_ptr; }
+ T& operator*() const { ASSERT(m_ptr); return *PtrTraits::unwrap(m_ptr); }
+ ALWAYS_INLINE T* operator->() const { return PtrTraits::unwrap(m_ptr); }
bool operator!() const { return !m_ptr; }
@@ -89,12 +90,12 @@
RefPtr& operator=(const RefPtr&);
RefPtr& operator=(T*);
RefPtr& operator=(std::nullptr_t);
- template<typename U> RefPtr& operator=(const RefPtr<U>&);
+ template<typename X, typename Y> RefPtr& operator=(const RefPtr<X, Y>&);
RefPtr& operator=(RefPtr&&);
- template<typename U> RefPtr& operator=(RefPtr<U>&&);
- template<typename U> RefPtr& operator=(Ref<U>&&);
+ template<typename X, typename Y> RefPtr& operator=(RefPtr<X, Y>&&);
+ template<typename X> RefPtr& operator=(Ref<X>&&);
- void swap(RefPtr&);
+ template<typename X, typename Y> void swap(RefPtr<X, Y>&);
static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); }
@@ -106,26 +107,30 @@
#endif
private:
- friend RefPtr adoptRef<T>(T*);
+ friend RefPtr adoptRef<T, PtrTraits>(T*);
+ template<typename X, typename Y> friend class RefPtr;
enum AdoptTag { Adopt };
RefPtr(T* ptr, AdoptTag) : m_ptr(ptr) { }
- T* m_ptr;
+ typename PtrTraits::StorageType m_ptr;
};
-template<typename T> template<typename U> inline RefPtr<T>::RefPtr(Ref<U>&& reference)
+template<typename T, typename U>
+template<typename X, typename Y>
+inline RefPtr<T, U>::RefPtr(Ref<X, Y>&& reference)
: m_ptr(&reference.leakRef())
{
}
-template<typename T>
-inline T* RefPtr<T>::leakRef()
+template<typename T, typename U>
+inline T* RefPtr<T, U>::leakRef()
{
- return std::exchange(m_ptr, nullptr);
+ return U::exchange(m_ptr, nullptr);
}
-template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr& o)
+template<typename T, typename U>
+inline RefPtr<T, U>& RefPtr<T, U>::operator=(const RefPtr& o)
{
RefPtr ptr = o;
swap(ptr);
@@ -132,7 +137,9 @@
return *this;
}
-template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr<U>& o)
+template<typename T, typename U>
+template<typename X, typename Y>
+inline RefPtr<T, U>& RefPtr<T, U>::operator=(const RefPtr<X, Y>& o)
{
RefPtr ptr = o;
swap(ptr);
@@ -139,7 +146,8 @@
return *this;
}
-template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(T* optr)
+template<typename T, typename U>
+inline RefPtr<T, U>& RefPtr<T, U>::operator=(T* optr)
{
RefPtr ptr = optr;
swap(ptr);
@@ -146,13 +154,15 @@
return *this;
}
-template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(std::nullptr_t)
+template<typename T, typename U>
+inline RefPtr<T, U>& RefPtr<T, U>::operator=(std::nullptr_t)
{
- derefIfNotNull(std::exchange(m_ptr, nullptr));
+ derefIfNotNull(U::exchange(m_ptr, nullptr));
return *this;
}
-template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(RefPtr&& o)
+template<typename T, typename U>
+inline RefPtr<T, U>& RefPtr<T, U>::operator=(RefPtr&& o)
{
RefPtr ptr = WTFMove(o);
swap(ptr);
@@ -159,7 +169,9 @@
return *this;
}
-template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(RefPtr<U>&& o)
+template<typename T, typename U>
+template<typename X, typename Y>
+inline RefPtr<T, U>& RefPtr<T, U>::operator=(RefPtr<X, Y>&& o)
{
RefPtr ptr = WTFMove(o);
swap(ptr);
@@ -166,7 +178,9 @@
return *this;
}
-template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(Ref<U>&& reference)
+template<typename T, typename V>
+template<typename U>
+inline RefPtr<T, V>& RefPtr<T, V>::operator=(Ref<U>&& reference)
{
RefPtr ptr = WTFMove(reference);
swap(ptr);
@@ -173,59 +187,71 @@
return *this;
}
-template<class T> inline void RefPtr<T>::swap(RefPtr& o)
+template<class T, typename U>
+template<typename X, typename Y>
+inline void RefPtr<T, U>::swap(RefPtr<X, Y>& o)
{
- std::swap(m_ptr, o.m_ptr);
+ U::swap(m_ptr, o.m_ptr);
}
-template<class T> inline void swap(RefPtr<T>& a, RefPtr<T>& b)
+template<typename T, typename U, typename X, typename Y, typename = std::enable_if_t<!std::is_same<U, DumbPtrTraits<T>>::value || !std::is_same<Y, DumbPtrTraits<X>>::value>>
+inline void swap(RefPtr<T, U>& a, RefPtr<X, Y>& b)
{
a.swap(b);
}
-template<typename T, typename U> inline bool operator==(const RefPtr<T>& a, const RefPtr<U>& b)
+template<typename T, typename U, typename X, typename Y>
+inline bool operator==(const RefPtr<T, U>& a, const RefPtr<X, Y>& b)
{
- return a.get() == b.get();
+ return a.get() == b.get();
}
-template<typename T, typename U> inline bool operator==(const RefPtr<T>& a, U* b)
+template<typename T, typename U, typename X>
+inline bool operator==(const RefPtr<T, U>& a, X* b)
{
return a.get() == b;
}
-template<typename T, typename U> inline bool operator==(T* a, const RefPtr<U>& b)
+template<typename T, typename X, typename Y>
+inline bool operator==(T* a, const RefPtr<X, Y>& b)
{
return a == b.get();
}
-template<typename T, typename U> inline bool operator!=(const RefPtr<T>& a, const RefPtr<U>& b)
+template<typename T, typename U, typename X, typename Y>
+inline bool operator!=(const RefPtr<T, U>& a, const RefPtr<X, Y>& b)
{
return a.get() != b.get();
}
-template<typename T, typename U> inline bool operator!=(const RefPtr<T>& a, U* b)
+template<typename T, typename U, typename X>
+inline bool operator!=(const RefPtr<T, U>& a, X* b)
{
return a.get() != b;
}
-template<typename T, typename U> inline bool operator!=(T* a, const RefPtr<U>& b)
+template<typename T, typename X, typename Y>
+inline bool operator!=(T* a, const RefPtr<X, Y>& b)
{
return a != b.get();
}
-template<typename T, typename U> inline RefPtr<T> static_pointer_cast(const RefPtr<U>& p)
+template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
+inline RefPtr<T, U> static_pointer_cast(const RefPtr<X, Y>& p)
{
- return RefPtr<T>(static_cast<T*>(p.get()));
+ return RefPtr<T, U>(static_cast<T*>(p.get()));
}
-template <typename T> struct IsSmartPtr<RefPtr<T>> {
+template <typename T, typename U>
+struct IsSmartPtr<RefPtr<T, U>> {
static const bool value = true;
};
-template<typename T> inline RefPtr<T> adoptRef(T* p)
+template<typename T, typename U>
+inline RefPtr<T, U> adoptRef(T* p)
{
adopted(p);
- return RefPtr<T>(p, RefPtr<T>::Adopt);
+ return RefPtr<T, U>(p, RefPtr<T, U>::Adopt);
}
template<typename T> inline RefPtr<T> makeRefPtr(T* pointer)
@@ -238,18 +264,26 @@
return &reference;
}
-template<typename ExpectedType, typename ArgType> inline bool is(RefPtr<ArgType>& source)
+template<typename ExpectedType, typename ArgType, typename PtrTraits>
+inline bool is(RefPtr<ArgType, PtrTraits>& source)
{
return is<ExpectedType>(source.get());
}
-template<typename ExpectedType, typename ArgType> inline bool is(const RefPtr<ArgType>& source)
+template<typename ExpectedType, typename ArgType, typename PtrTraits>
+inline bool is(const RefPtr<ArgType, PtrTraits>& source)
{
return is<ExpectedType>(source.get());
}
+template<uint32_t key, typename T> struct ConstExprPoisonedPtrTraits;
+
+template<uint32_t key, typename T>
+using PoisonedRefPtr = RefPtr<T, ConstExprPoisonedPtrTraits<key, T>>;
+
} // namespace WTF
+using WTF::PoisonedRefPtr;
using WTF::RefPtr;
using WTF::adoptRef;
using WTF::makeRefPtr;
Modified: trunk/Tools/ChangeLog (226014 => 226015)
--- trunk/Tools/ChangeLog 2017-12-17 21:15:28 UTC (rev 226014)
+++ trunk/Tools/ChangeLog 2017-12-17 23:22:18 UTC (rev 226015)
@@ -1,3 +1,35 @@
+2017-12-17 Mark Lam <[email protected]>
+
+ Enhance Ref and RefPtr to be able to work with smart pointers.
+ https://bugs.webkit.org/show_bug.cgi?id=180762
+ <rdar://problem/36027122>
+
+ Reviewed by JF Bastien and Darin Adler.
+
+ * TestWebKitAPI/CMakeLists.txt:
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WTF/ConstExprPoisoned.cpp:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WTF/Poisoned.cpp:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WTF/PoisonedRef.cpp: Added.
+ (TestWebKitAPI::TEST):
+ (TestWebKitAPI::passWithRef):
+ (TestWebKitAPI::PoisonedRefCheckingRefLogger::PoisonedRefCheckingRefLogger):
+ (TestWebKitAPI::PoisonedRefCheckingRefLogger::ref):
+ (TestWebKitAPI::PoisonedRefCheckingRefLogger::deref):
+ (TestWebKitAPI::DerivedPoisonedRefCheckingRefLogger::DerivedPoisonedRefCheckingRefLogger):
+ * TestWebKitAPI/Tests/WTF/PoisonedRefPtr.cpp: Added.
+ (TestWebKitAPI::TEST):
+ (TestWebKitAPI::f1):
+ (TestWebKitAPI::ConstRefCounted::create):
+ (TestWebKitAPI::returnConstRefCountedRef):
+ (TestWebKitAPI::returnRefCountedRef):
+ (TestWebKitAPI::PoisonedRefPtrCheckingRefLogger::PoisonedRefPtrCheckingRefLogger):
+ (TestWebKitAPI::loggerName):
+ (TestWebKitAPI::PoisonedRefPtrCheckingRefLogger::ref):
+ (TestWebKitAPI::PoisonedRefPtrCheckingRefLogger::deref):
+
2017-12-16 Youenn Fablet <[email protected]>
Add a script to automate W3c web-platform-tests pull request creations from WebKit commits
Modified: trunk/Tools/TestWebKitAPI/CMakeLists.txt (226014 => 226015)
--- trunk/Tools/TestWebKitAPI/CMakeLists.txt 2017-12-17 21:15:28 UTC (rev 226014)
+++ trunk/Tools/TestWebKitAPI/CMakeLists.txt 2017-12-17 23:22:18 UTC (rev 226015)
@@ -124,6 +124,8 @@
${TESTWEBKITAPI_DIR}/Tests/WTF/OptionSet.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/ParkingLot.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/Poisoned.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/PoisonedRef.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/PoisonedRefPtr.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/PriorityQueue.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/RedBlackTree.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/Ref.cpp
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (226014 => 226015)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2017-12-17 21:15:28 UTC (rev 226014)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2017-12-17 23:22:18 UTC (rev 226015)
@@ -757,6 +757,8 @@
F6B7BE9717469B96008A3445 /* associate-form-controls.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F6B7BE9617469B7E008A3445 /* associate-form-controls.html */; };
F6F49C6B15545CA70007F39D /* DOMWindowExtensionNoCache_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F49C6615545C8D0007F39D /* DOMWindowExtensionNoCache_Bundle.cpp */; };
F6FDDDD614241C6F004F1729 /* push-state.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F6FDDDD514241C48004F1729 /* push-state.html */; };
+ FE05FAEC1FDB510A00093230 /* PoisonedRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAEB1FDB510200093230 /* PoisonedRef.cpp */; };
+ FE05FAED1FDB510E00093230 /* PoisonedRefPtr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAEA1FDB510100093230 /* PoisonedRefPtr.cpp */; };
FE05FAEF1FE0645B00093230 /* Poisoned.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAEE1FE0643D00093230 /* Poisoned.cpp */; };
FE05FAF11FE08CD400093230 /* ConstExprPoisoned.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAF01FE08CCD00093230 /* ConstExprPoisoned.cpp */; };
/* End PBXBuildFile section */
@@ -1861,6 +1863,8 @@
F6F49C6715545C8D0007F39D /* DOMWindowExtensionNoCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMWindowExtensionNoCache.cpp; sourceTree = "<group>"; };
F6FDDDD214241AD4004F1729 /* PrivateBrowsingPushStateNoHistoryCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PrivateBrowsingPushStateNoHistoryCallback.cpp; sourceTree = "<group>"; };
F6FDDDD514241C48004F1729 /* push-state.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "push-state.html"; sourceTree = "<group>"; };
+ FE05FAEA1FDB510100093230 /* PoisonedRefPtr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PoisonedRefPtr.cpp; sourceTree = "<group>"; };
+ FE05FAEB1FDB510200093230 /* PoisonedRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PoisonedRef.cpp; sourceTree = "<group>"; };
FE05FAEE1FE0643D00093230 /* Poisoned.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Poisoned.cpp; sourceTree = "<group>"; };
FE05FAF01FE08CCD00093230 /* ConstExprPoisoned.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConstExprPoisoned.cpp; sourceTree = "<group>"; };
FEB6F74E1B2BA44E009E4922 /* NakedPtr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NakedPtr.cpp; sourceTree = "<group>"; };
@@ -2655,6 +2659,8 @@
CE50D8C81C8665CE0072EA5A /* OptionSet.cpp */,
0FE447971B76F1E3009498EB /* ParkingLot.cpp */,
FE05FAEE1FE0643D00093230 /* Poisoned.cpp */,
+ FE05FAEB1FDB510200093230 /* PoisonedRef.cpp */,
+ FE05FAEA1FDB510100093230 /* PoisonedRefPtr.cpp */,
53EC253F1E96BC80000831B9 /* PriorityQueue.cpp */,
0FC6C4CB141027E0005B7F0C /* RedBlackTree.cpp */,
93A427AA180DA26400CD24D7 /* Ref.cpp */,
@@ -3186,6 +3192,7 @@
7C83DEA91D0A590C00FEBCF3 /* CString.cpp in Sources */,
7C83DEAD1D0A590C00FEBCF3 /* Deque.cpp in Sources */,
1AF7B21F1D6CD14D008C126C /* EnumTraits.cpp in Sources */,
+ FE05FAED1FDB510E00093230 /* PoisonedRefPtr.cpp in Sources */,
AD7C434D1DD2A54E0026888B /* Expected.cpp in Sources */,
9310CD381EF708FB0050FFE0 /* Function.cpp in Sources */,
6BFD294C1D5E6C1D008EC968 /* HashCountedSet.cpp in Sources */,
@@ -3203,6 +3210,7 @@
7C83DEED1D0A590C00FEBCF3 /* MathExtras.cpp in Sources */,
7C83DEEF1D0A590C00FEBCF3 /* MD5.cpp in Sources */,
7C83DEF11D0A590C00FEBCF3 /* MediaTime.cpp in Sources */,
+ FE05FAEC1FDB510A00093230 /* PoisonedRef.cpp in Sources */,
7C83DEF61D0A590C00FEBCF3 /* MetaAllocator.cpp in Sources */,
7C83DEFE1D0A590C00FEBCF3 /* NakedPtr.cpp in Sources */,
A57D54F31F338C3600A97AA7 /* NeverDestroyed.cpp in Sources */,
Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/ConstExprPoisoned.cpp (226014 => 226015)
--- trunk/Tools/TestWebKitAPI/Tests/WTF/ConstExprPoisoned.cpp 2017-12-17 21:15:28 UTC (rev 226014)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/ConstExprPoisoned.cpp 2017-12-17 23:22:18 UTC (rev 226015)
@@ -49,6 +49,15 @@
ASSERT_EQ(&a, ptr.unpoisoned());
ASSERT_EQ(&a, &*ptr);
ASSERT_EQ(&a.name, &ptr->name);
+
+#if ENABLE(POISON)
+ uintptr_t ptrBits;
+ std::memcpy(&ptrBits, &ptr, sizeof(ptrBits));
+ ASSERT_TRUE(ptrBits != bitwise_cast<uintptr_t>(&a));
+#if ENABLE(POISON_ASSERTS)
+ ASSERT_TRUE((ConstExprPoisoned<PoisonA, RefLogger*>::isPoisoned(ptrBits)));
+#endif
+#endif // ENABLE(POISON)
}
{
Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/Poisoned.cpp (226014 => 226015)
--- trunk/Tools/TestWebKitAPI/Tests/WTF/Poisoned.cpp 2017-12-17 21:15:28 UTC (rev 226014)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/Poisoned.cpp 2017-12-17 23:22:18 UTC (rev 226015)
@@ -61,6 +61,15 @@
ASSERT_EQ(&a, ptr.unpoisoned());
ASSERT_EQ(&a, &*ptr);
ASSERT_EQ(&a.name, &ptr->name);
+
+#if ENABLE(POISON)
+ uintptr_t ptrBits;
+ std::memcpy(&ptrBits, &ptr, sizeof(ptrBits));
+ ASSERT_TRUE(ptrBits != bitwise_cast<uintptr_t>(&a));
+#if ENABLE(POISON_ASSERTS)
+ ASSERT_TRUE((Poisoned<g_testPoisonA, RefLogger*>::isPoisoned(ptrBits)));
+#endif
+#endif // ENABLE(POISON)
}
{
Added: trunk/Tools/TestWebKitAPI/Tests/WTF/PoisonedRef.cpp (0 => 226015)
--- trunk/Tools/TestWebKitAPI/Tests/WTF/PoisonedRef.cpp (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/PoisonedRef.cpp 2017-12-17 23:22:18 UTC (rev 226015)
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2017 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. ``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.
+ */
+
+#include "config.h"
+
+#include "RefLogger.h"
+#include <wtf/Poisoned.h>
+#include <wtf/RefPtr.h>
+
+namespace TestWebKitAPI {
+
+static const uint32_t PoisonA = 0xaaaa;
+static const uint32_t PoisonB = 0xbbbb;
+static const uint32_t PoisonC = 0xcccc;
+static const uint32_t PoisonD = 0xdddd;
+static const uint32_t PoisonE = 0xeeee;
+static const uint32_t PoisonF = 0xffff;
+
+TEST(WTF_PoisonedRef, Basic)
+{
+ DerivedRefLogger a("a");
+
+ {
+ PoisonedRef<PoisonA, RefLogger> ref(a);
+ EXPECT_EQ(&a, ref.ptr());
+ EXPECT_EQ(&a.name, &ref->name);
+
+#if ENABLE(POISON)
+ uintptr_t ptrBits;
+ std::memcpy(&ptrBits, &ref, sizeof(ptrBits));
+ ASSERT_TRUE(ptrBits != bitwise_cast<uintptr_t>(&a));
+ ASSERT_EQ(ptrBits, (ConstExprPoisoned<PoisonA, RefLogger*>(&a).bits()));
+#if ENABLE(POISON_ASSERTS)
+ ASSERT_TRUE((ConstExprPoisoned<PoisonA, RefLogger*>::isPoisoned(ptrBits)));
+#endif
+#endif // ENABLE(POISON)
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRef<PoisonB, RefLogger> ref(adoptRef(a));
+ EXPECT_EQ(&a, ref.ptr());
+ EXPECT_EQ(&a.name, &ref->name);
+ }
+ EXPECT_STREQ("deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_PoisonedRef, Assignment)
+{
+ DerivedRefLogger a("a");
+ RefLogger b("b");
+ DerivedRefLogger c("c");
+
+ {
+ PoisonedRef<PoisonC, RefLogger> ref(a);
+ EXPECT_EQ(&a, ref.ptr());
+ log() << "| ";
+ ref = b;
+ EXPECT_EQ(&b, ref.ptr());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRef<PoisonD, RefLogger> ref(a);
+ EXPECT_EQ(&a, ref.ptr());
+ log() << "| ";
+ ref = c;
+ EXPECT_EQ(&c, ref.ptr());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | ref(c) deref(a) | deref(c) ", takeLogStr().c_str());
+
+ {
+ PoisonedRef<PoisonE, RefLogger> ref(a);
+ EXPECT_EQ(&a, ref.ptr());
+ log() << "| ";
+ ref = adoptRef(b);
+ EXPECT_EQ(&b, ref.ptr());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRef<PoisonF, RefLogger> ref(a);
+ EXPECT_EQ(&a, ref.ptr());
+ log() << "| ";
+ ref = adoptRef(c);
+ EXPECT_EQ(&c, ref.ptr());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | deref(a) | deref(c) ", takeLogStr().c_str());
+}
+
+static PoisonedRef<PoisonB, RefLogger> passWithRef(PoisonedRef<PoisonC, RefLogger>&& reference)
+{
+ return WTFMove(reference);
+}
+
+TEST(WTF_PoisonedRef, ReturnValue)
+{
+ DerivedRefLogger a("a");
+ RefLogger b("b");
+ DerivedRefLogger c("c");
+
+ {
+ PoisonedRef<PoisonB, RefLogger> ref(passWithRef(PoisonedRef<PoisonC, RefLogger>(a)));
+ EXPECT_EQ(&a, ref.ptr());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRef<PoisonD, RefLogger> ref(a);
+ EXPECT_EQ(&a, ref.ptr());
+ log() << "| ";
+ ref = passWithRef(b);
+ EXPECT_EQ(&b, ref.ptr());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonE, RefLogger> ptr(passWithRef(a));
+ EXPECT_EQ(&a, ptr.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonF, DerivedRefLogger> ptr(&a);
+ PoisonedRefPtr<PoisonA, RefLogger> ptr2(WTFMove(ptr));
+ EXPECT_EQ(nullptr, ptr.get());
+ EXPECT_EQ(&a, ptr2.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRef<PoisonB, DerivedRefLogger> derivedReference(a);
+ PoisonedRef<PoisonC, RefLogger> baseReference(passWithRef(derivedReference.copyRef()));
+ EXPECT_EQ(&a, derivedReference.ptr());
+ EXPECT_EQ(&a, baseReference.ptr());
+ }
+ EXPECT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_PoisonedRef, Swap)
+{
+ RefLogger a("a");
+ RefLogger b("b");
+
+ {
+ PoisonedRef<PoisonD, RefLogger> p1(a);
+ PoisonedRef<PoisonE, RefLogger> p2(b);
+ log() << "| ";
+ EXPECT_EQ(&a, p1.ptr());
+ EXPECT_EQ(&b, p2.ptr());
+ p1.swap(p2);
+ EXPECT_EQ(&b, p1.ptr());
+ EXPECT_EQ(&a, p2.ptr());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRef<PoisonF, RefLogger> p1(a);
+ PoisonedRef<PoisonA, RefLogger> p2(b);
+ log() << "| ";
+ EXPECT_EQ(&a, p1.ptr());
+ EXPECT_EQ(&b, p2.ptr());
+ swap(p1, p2);
+ EXPECT_EQ(&b, p1.ptr());
+ EXPECT_EQ(&a, p2.ptr());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
+}
+
+struct PoisonedRefCheckingRefLogger : RefLogger {
+ using Ref = PoisonedRef<PoisonB, PoisonedRefCheckingRefLogger>;
+
+ PoisonedRefCheckingRefLogger(const char* name);
+ void ref();
+ void deref();
+ const Ref* slotToCheck { nullptr };
+};
+
+struct DerivedPoisonedRefCheckingRefLogger : PoisonedRefCheckingRefLogger {
+ DerivedPoisonedRefCheckingRefLogger(const char* name);
+};
+
+PoisonedRefCheckingRefLogger::PoisonedRefCheckingRefLogger(const char* name)
+ : RefLogger { name }
+{
+}
+
+void PoisonedRefCheckingRefLogger::ref()
+{
+ if (slotToCheck)
+ log() << "slot=" << slotToCheck->get().name << " ";
+ RefLogger::ref();
+}
+
+void PoisonedRefCheckingRefLogger::deref()
+{
+ if (slotToCheck)
+ log() << "slot=" << slotToCheck->get().name << " ";
+ RefLogger::deref();
+}
+
+DerivedPoisonedRefCheckingRefLogger::DerivedPoisonedRefCheckingRefLogger(const char* name)
+ : PoisonedRefCheckingRefLogger { name }
+{
+}
+
+TEST(WTF_PoisonedRef, AssignBeforeDeref)
+{
+ DerivedPoisonedRefCheckingRefLogger a("a");
+ PoisonedRefCheckingRefLogger b("b");
+ DerivedPoisonedRefCheckingRefLogger c("c");
+
+ {
+ PoisonedRefCheckingRefLogger::Ref ref(a);
+ EXPECT_EQ(&a, ref.ptr());
+ log() << "| ";
+ a.slotToCheck = &ref;
+ b.slotToCheck = &ref;
+ ref = b;
+ a.slotToCheck = nullptr;
+ b.slotToCheck = nullptr;
+ EXPECT_EQ(&b, ref.ptr());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | slot=a ref(b) slot=b deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefCheckingRefLogger::Ref ref(a);
+ EXPECT_EQ(&a, ref.ptr());
+ log() << "| ";
+ a.slotToCheck = &ref;
+ c.slotToCheck = &ref;
+ ref = c;
+ a.slotToCheck = nullptr;
+ c.slotToCheck = nullptr;
+ EXPECT_EQ(&c, ref.ptr());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | slot=a ref(c) slot=c deref(a) | deref(c) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefCheckingRefLogger::Ref ref(a);
+ EXPECT_EQ(&a, ref.ptr());
+ log() << "| ";
+ a.slotToCheck = &ref;
+ ref = adoptRef(b);
+ a.slotToCheck = nullptr;
+ EXPECT_EQ(&b, ref.ptr());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | slot=b deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefCheckingRefLogger::Ref ref(a);
+ EXPECT_EQ(&a, ref.ptr());
+ log() << "| ";
+ a.slotToCheck = &ref;
+ ref = adoptRef(c);
+ a.slotToCheck = nullptr;
+ EXPECT_EQ(&c, ref.ptr());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | slot=c deref(a) | deref(c) ", takeLogStr().c_str());
+}
+
+} // namespace TestWebKitAPI
Added: trunk/Tools/TestWebKitAPI/Tests/WTF/PoisonedRefPtr.cpp (0 => 226015)
--- trunk/Tools/TestWebKitAPI/Tests/WTF/PoisonedRefPtr.cpp (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/PoisonedRefPtr.cpp 2017-12-17 23:22:18 UTC (rev 226015)
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2017 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. ``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.
+ */
+
+#include "config.h"
+
+#include "RefLogger.h"
+#include <wtf/NeverDestroyed.h>
+#include <wtf/Poisoned.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace TestWebKitAPI {
+
+static const uint32_t PoisonA = 0xaaaa;
+static const uint32_t PoisonB = 0xbbbb;
+static const uint32_t PoisonC = 0xcccc;
+static const uint32_t PoisonD = 0xdddd;
+static const uint32_t PoisonE = 0xeeee;
+static const uint32_t PoisonF = 0xffff;
+
+TEST(WTF_PoisonedRefPtr, Basic)
+{
+ DerivedRefLogger a("a");
+
+ PoisonedRefPtr<PoisonA, RefLogger> empty;
+ EXPECT_EQ(nullptr, empty.get());
+
+ {
+ PoisonedRefPtr<PoisonB, RefLogger> ptr(&a);
+ EXPECT_EQ(&a, ptr.get());
+ EXPECT_EQ(&a, &*ptr);
+ EXPECT_EQ(&a.name, &ptr->name);
+
+#if ENABLE(POISON)
+ uintptr_t ptrBits;
+ std::memcpy(&ptrBits, &ptr, sizeof(ptrBits));
+ ASSERT_TRUE(ptrBits != bitwise_cast<uintptr_t>(&a));
+ ASSERT_EQ(ptrBits, (ConstExprPoisoned<PoisonB, RefLogger*>(&a).bits()));
+#if ENABLE(POISON_ASSERTS)
+ ASSERT_TRUE((ConstExprPoisoned<PoisonB, RefLogger*>::isPoisoned(ptrBits)));
+#endif
+#endif // ENABLE(POISON)
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonC, RefLogger> ptr = &a;
+ EXPECT_EQ(&a, ptr.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonD, RefLogger> p1 = &a;
+ PoisonedRefPtr<PoisonE, RefLogger> p2(p1);
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&a, p2.get());
+ }
+ EXPECT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonF, RefLogger> p1 = &a;
+ PoisonedRefPtr<PoisonB, RefLogger> p2 = p1;
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&a, p2.get());
+ }
+ EXPECT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonC, RefLogger> p1 = &a;
+ PoisonedRefPtr<PoisonD, RefLogger> p2 = WTFMove(p1);
+ EXPECT_EQ(nullptr, p1.get());
+ EXPECT_EQ(&a, p2.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonE, RefLogger> p1 = &a;
+ PoisonedRefPtr<PoisonF, RefLogger> p2(WTFMove(p1));
+ EXPECT_EQ(nullptr, p1.get());
+ EXPECT_EQ(&a, p2.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonB, DerivedRefLogger> p1 = &a;
+ PoisonedRefPtr<PoisonC, RefLogger> p2 = p1;
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&a, p2.get());
+ }
+ EXPECT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonD, DerivedRefLogger> p1 = &a;
+ PoisonedRefPtr<PoisonE, RefLogger> p2 = WTFMove(p1);
+ EXPECT_EQ(nullptr, p1.get());
+ EXPECT_EQ(&a, p2.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonF, RefLogger> ptr(&a);
+ EXPECT_EQ(&a, ptr.get());
+ ptr = nullptr;
+ EXPECT_EQ(nullptr, ptr.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_PoisonedRefPtr, AssignPassRefToPoisonedRefPtr)
+{
+ DerivedRefLogger a("a");
+ {
+ Ref<RefLogger> passRef(a);
+ PoisonedRefPtr<PoisonB, RefLogger> ptr = WTFMove(passRef);
+ EXPECT_EQ(&a, ptr.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_PoisonedRefPtr, Adopt)
+{
+ DerivedRefLogger a("a");
+
+ PoisonedRefPtr<PoisonC, RefLogger> empty;
+ EXPECT_EQ(nullptr, empty.get());
+
+ {
+ PoisonedRefPtr<PoisonD, RefLogger> ptr(adoptRef(&a));
+ EXPECT_EQ(&a, ptr.get());
+ EXPECT_EQ(&a, &*ptr);
+ EXPECT_EQ(&a.name, &ptr->name);
+ }
+ EXPECT_STREQ("deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonE, RefLogger> ptr = adoptRef(&a);
+ EXPECT_EQ(&a, ptr.get());
+ }
+ EXPECT_STREQ("deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_PoisonedRefPtr, Assignment)
+{
+ DerivedRefLogger a("a");
+ RefLogger b("b");
+ DerivedRefLogger c("c");
+
+ {
+ PoisonedRefPtr<PoisonF, RefLogger> p1(&a);
+ PoisonedRefPtr<PoisonB, RefLogger> p2(&b);
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&b, p2.get());
+ log() << "| ";
+ p1 = p2;
+ EXPECT_EQ(&b, p1.get());
+ EXPECT_EQ(&b, p2.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) ref(b) | ref(b) deref(a) | deref(b) deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonC, RefLogger> ptr(&a);
+ EXPECT_EQ(&a, ptr.get());
+ log() << "| ";
+ ptr = &b;
+ EXPECT_EQ(&b, ptr.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonD, RefLogger> ptr(&a);
+ EXPECT_EQ(&a, ptr.get());
+ log() << "| ";
+ ptr = adoptRef(&b);
+ EXPECT_EQ(&b, ptr.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonE, RefLogger> ptr(&a);
+ EXPECT_EQ(&a, ptr.get());
+ ptr = nullptr;
+ EXPECT_EQ(nullptr, ptr.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonB, RefLogger> p1(&a);
+ PoisonedRefPtr<PoisonC, RefLogger> p2(&b);
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&b, p2.get());
+ log() << "| ";
+ p1 = WTFMove(p2);
+ EXPECT_EQ(&b, p1.get());
+ EXPECT_EQ(nullptr, p2.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) ref(b) | deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonD, RefLogger> p1(&a);
+ PoisonedRefPtr<PoisonE, DerivedRefLogger> p2(&c);
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&c, p2.get());
+ log() << "| ";
+ p1 = p2;
+ EXPECT_EQ(&c, p1.get());
+ EXPECT_EQ(&c, p2.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) ref(c) | ref(c) deref(a) | deref(c) deref(c) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonF, RefLogger> ptr(&a);
+ EXPECT_EQ(&a, ptr.get());
+ log() << "| ";
+ ptr = &c;
+ EXPECT_EQ(&c, ptr.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | ref(c) deref(a) | deref(c) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonB, RefLogger> ptr(&a);
+ EXPECT_EQ(&a, ptr.get());
+ log() << "| ";
+ ptr = adoptRef(&c);
+ EXPECT_EQ(&c, ptr.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | deref(a) | deref(c) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonC, RefLogger> p1(&a);
+ PoisonedRefPtr<PoisonD, DerivedRefLogger> p2(&c);
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&c, p2.get());
+ log() << "| ";
+ p1 = WTFMove(p2);
+ EXPECT_EQ(&c, p1.get());
+ EXPECT_EQ(nullptr, p2.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) ref(c) | deref(a) | deref(c) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonE, RefLogger> ptr(&a);
+ EXPECT_EQ(&a, ptr.get());
+ log() << "| ";
+ ptr = ptr;
+ EXPECT_EQ(&a, ptr.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | ref(a) deref(a) | deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonF, RefLogger> ptr(&a);
+ EXPECT_EQ(&a, ptr.get());
+#if COMPILER(CLANG)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#pragma clang diagnostic ignored "-Wself-move"
+#endif
+ ptr = WTFMove(ptr);
+#if COMPILER(CLANG)
+#pragma clang diagnostic pop
+#endif
+ EXPECT_EQ(&a, ptr.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_PoisonedRefPtr, Swap)
+{
+ RefLogger a("a");
+ RefLogger b("b");
+
+ {
+ PoisonedRefPtr<PoisonB, RefLogger> p1(&a);
+ PoisonedRefPtr<PoisonC, RefLogger> p2(&b);
+ log() << "| ";
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&b, p2.get());
+ p1.swap(p2);
+ EXPECT_EQ(&b, p1.get());
+ EXPECT_EQ(&a, p2.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonD, RefLogger> p1(&a);
+ PoisonedRefPtr<PoisonE, RefLogger> p2(&b);
+ log() << "| ";
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&b, p2.get());
+ swap(p1, p2);
+ EXPECT_EQ(&b, p1.get());
+ EXPECT_EQ(&a, p2.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
+}
+
+TEST(WTF_PoisonedRefPtr, ReleaseNonNull)
+{
+ RefLogger a("a");
+
+ {
+ PoisonedRefPtr<PoisonF, RefLogger> refPtr = &a;
+ PoisonedRefPtr<PoisonB, RefLogger> ref = refPtr.releaseNonNull();
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_PoisonedRefPtr, Release)
+{
+ DerivedRefLogger a("a");
+ RefLogger b("b");
+ DerivedRefLogger c("c");
+
+ {
+ PoisonedRefPtr<PoisonC, RefLogger> p1 = &a;
+ PoisonedRefPtr<PoisonD, RefLogger> p2 = WTFMove(p1);
+ EXPECT_EQ(nullptr, p1.get());
+ EXPECT_EQ(&a, p2.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonE, RefLogger> p1 = &a;
+ PoisonedRefPtr<PoisonF, RefLogger> p2(WTFMove(p1));
+ EXPECT_EQ(nullptr, p1.get());
+ EXPECT_EQ(&a, p2.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonB, DerivedRefLogger> p1 = &a;
+ PoisonedRefPtr<PoisonC, RefLogger> p2 = WTFMove(p1);
+ EXPECT_EQ(nullptr, p1.get());
+ EXPECT_EQ(&a, p2.get());
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonD, RefLogger> p1(&a);
+ PoisonedRefPtr<PoisonE, RefLogger> p2(&b);
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&b, p2.get());
+ log() << "| ";
+ p1 = WTFMove(p2);
+ EXPECT_EQ(&b, p1.get());
+ EXPECT_EQ(nullptr, p2.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) ref(b) | deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtr<PoisonF, RefLogger> p1(&a);
+ PoisonedRefPtr<PoisonB, DerivedRefLogger> p2(&c);
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&c, p2.get());
+ log() << "| ";
+ p1 = WTFMove(p2);
+ EXPECT_EQ(&c, p1.get());
+ EXPECT_EQ(nullptr, p2.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) ref(c) | deref(a) | deref(c) ", takeLogStr().c_str());
+}
+
+static PoisonedRefPtr<PoisonC, RefLogger> f1(RefLogger& logger)
+{
+ return PoisonedRefPtr<PoisonC, RefLogger>(&logger);
+}
+
+TEST(WTF_PoisonedRefPtr, ReturnValue)
+{
+ DerivedRefLogger a("a");
+
+ {
+ f1(a);
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ auto ptr = f1(a);
+ }
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+struct ConstRefCounted : RefCounted<ConstRefCounted> {
+ static Ref<ConstRefCounted> create() { return adoptRef(*new ConstRefCounted); }
+};
+
+static const ConstRefCounted& returnConstRefCountedRef()
+{
+ static NeverDestroyed<ConstRefCounted> instance;
+ return instance.get();
+}
+static ConstRefCounted& returnRefCountedRef()
+{
+ static NeverDestroyed<ConstRefCounted> instance;
+ return instance.get();
+}
+
+TEST(WTF_PoisonedRefPtr, Const)
+{
+ // This test passes if it compiles without an error.
+ auto a = ConstRefCounted::create();
+ Ref<const ConstRefCounted> b = WTFMove(a);
+ PoisonedRefPtr<PoisonD, const ConstRefCounted> c = b.ptr();
+ Ref<const ConstRefCounted> d = returnConstRefCountedRef();
+ PoisonedRefPtr<PoisonE, const ConstRefCounted> e = &returnConstRefCountedRef();
+ PoisonedRefPtr<PoisonF, ConstRefCounted> f = ConstRefCounted::create();
+ PoisonedRefPtr<PoisonB, const ConstRefCounted> g = f;
+ PoisonedRefPtr<PoisonC, const ConstRefCounted> h(f);
+ Ref<const ConstRefCounted> i(returnRefCountedRef());
+}
+
+struct PoisonedRefPtrCheckingRefLogger : RefLogger {
+ using Ref = PoisonedRefPtr<PoisonD, PoisonedRefPtrCheckingRefLogger>;
+
+ PoisonedRefPtrCheckingRefLogger(const char* name);
+ void ref();
+ void deref();
+ const Ref* slotToCheck { nullptr };
+};
+
+PoisonedRefPtrCheckingRefLogger::PoisonedRefPtrCheckingRefLogger(const char* name)
+ : RefLogger { name }
+{
+}
+
+static const char* loggerName(const PoisonedRefPtrCheckingRefLogger::Ref& pointer)
+{
+ return pointer ? &pointer->name : "null";
+}
+
+void PoisonedRefPtrCheckingRefLogger::ref()
+{
+ if (slotToCheck)
+ log() << "slot=" << loggerName(*slotToCheck) << " ";
+ RefLogger::ref();
+}
+
+void PoisonedRefPtrCheckingRefLogger::deref()
+{
+ if (slotToCheck)
+ log() << "slot=" << loggerName(*slotToCheck) << " ";
+ RefLogger::deref();
+}
+
+TEST(WTF_PoisonedRefPtr, AssignBeforeDeref)
+{
+ PoisonedRefPtrCheckingRefLogger a("a");
+ PoisonedRefPtrCheckingRefLogger b("b");
+
+ {
+ PoisonedRefPtrCheckingRefLogger::Ref p1(&a);
+ PoisonedRefPtrCheckingRefLogger::Ref p2(&b);
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&b, p2.get());
+ log() << "| ";
+ a.slotToCheck = &p1;
+ b.slotToCheck = &p1;
+ p1 = p2;
+ a.slotToCheck = nullptr;
+ b.slotToCheck = nullptr;
+ EXPECT_EQ(&b, p1.get());
+ EXPECT_EQ(&b, p2.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) ref(b) | slot=a ref(b) slot=b deref(a) | deref(b) deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtrCheckingRefLogger::Ref ptr(&a);
+ EXPECT_EQ(&a, ptr.get());
+ log() << "| ";
+ a.slotToCheck = &ptr;
+ b.slotToCheck = &ptr;
+ ptr = &b;
+ a.slotToCheck = nullptr;
+ b.slotToCheck = nullptr;
+ EXPECT_EQ(&b, ptr.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) | slot=a ref(b) slot=b deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtrCheckingRefLogger::Ref ptr(&a);
+ EXPECT_EQ(&a, ptr.get());
+ a.slotToCheck = &ptr;
+ ptr = nullptr;
+ a.slotToCheck = nullptr;
+ EXPECT_EQ(nullptr, ptr.get());
+ }
+ EXPECT_STREQ("ref(a) slot=null deref(a) ", takeLogStr().c_str());
+
+ {
+ PoisonedRefPtrCheckingRefLogger::Ref p1(&a);
+ PoisonedRefPtrCheckingRefLogger::Ref p2(&b);
+ EXPECT_EQ(&a, p1.get());
+ EXPECT_EQ(&b, p2.get());
+ log() << "| ";
+ a.slotToCheck = &p1;
+ b.slotToCheck = &p1;
+ p1 = WTFMove(p2);
+ a.slotToCheck = nullptr;
+ b.slotToCheck = nullptr;
+ EXPECT_EQ(&b, p1.get());
+ EXPECT_EQ(nullptr, p2.get());
+ log() << "| ";
+ }
+ EXPECT_STREQ("ref(a) ref(b) | slot=b deref(a) | deref(b) ", takeLogStr().c_str());
+}
+
+TEST(WTF_PoisonedRefPtr, ReleaseNonNullBeforeDeref)
+{
+ PoisonedRefPtrCheckingRefLogger a("a");
+
+ {
+ PoisonedRefPtrCheckingRefLogger::Ref refPtr = &a;
+ a.slotToCheck = &refPtr;
+ refPtr.releaseNonNull();
+ a.slotToCheck = nullptr;
+ }
+
+ EXPECT_STREQ("ref(a) slot=null deref(a) ", takeLogStr().c_str());
+}
+
+} // namespace TestWebKitAPI