Title: [226015] trunk
Revision
226015
Author
[email protected]
Date
2017-12-17 15:22:18 -0800 (Sun, 17 Dec 2017)

Log Message

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.

Source/WTF:

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.

Tools:

* 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):

Modified Paths

Added Paths

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
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to