GC can collect JS wrappers of nodes in the mutation records waiting to be delivered
[WebKit-https.git] / Source / WebCore / dom / GCReachableRef.h
1 /*
2  * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include <wtf/DumbPtrTraits.h>
29 #include <wtf/HashCountedSet.h>
30 #include <wtf/RefPtr.h>
31
32 namespace WebCore {
33
34 class Node;
35
36 class GCReachableRefMap {
37 public:
38     static inline bool contains(Node& node) { return map().contains(&node); }
39     static inline void add(Node& node) { map().add(&node); }
40     static inline void remove(Node& node) { map().remove(&node); }
41
42 private:
43     static HashCountedSet<Node*>& map();
44 };
45
46 template <typename T, typename = std::enable_if_t<std::is_same<T, typename std::remove_const<T>::type>::value>>
47 class GCReachableRef {
48     WTF_MAKE_NONCOPYABLE(GCReachableRef);
49 public:
50
51     template<typename = std::enable_if_t<std::is_base_of<Node, T>::value>>
52     GCReachableRef(T& object)
53         : m_ptr(&object)
54     {
55         GCReachableRefMap::add(*m_ptr);
56     }
57
58     ~GCReachableRef()
59     {
60         if (m_ptr)
61             GCReachableRefMap::remove(*m_ptr);
62     }
63
64     GCReachableRef(GCReachableRef&& other)
65         : m_ptr(WTFMove(other.m_ptr))
66     {
67     }
68
69     T* operator->() const { return &get(); }
70     T* ptr() const RETURNS_NONNULL { return &get(); }
71     T& get() const { ASSERT(m_ptr); return *m_ptr; }
72     operator T&() const { return get(); }
73     bool operator!() const { return !get(); }
74
75     // Hash table deleted values, which are only constructed and never copied or destroyed.
76     GCReachableRef(WTF::HashTableDeletedValueType)
77         : m_ptr(RefPtr<T>::hashTableDeletedValue())
78     { }
79     bool isHashTableDeletedValue() const { return m_ptr.isHashTableDeletedValue(); }
80
81     GCReachableRef(WTF::HashTableEmptyValueType)
82         : m_ptr(nullptr)
83     { }
84     bool isHashTableEmptyValue() const { return !m_ptr; }
85
86     const T* ptrAllowingHashTableEmptyValue() const { ASSERT(m_ptr || isHashTableEmptyValue()); return m_ptr.get(); }
87     T* ptrAllowingHashTableEmptyValue() { ASSERT(m_ptr || isHashTableEmptyValue()); return m_ptr.get(); }
88
89     void assignToHashTableEmptyValue(GCReachableRef&& reference)
90     {
91         ASSERT(!m_ptr);
92         m_ptr = WTFMove(reference.m_ptr);
93         ASSERT(m_ptr);
94     }
95
96 private:
97     RefPtr<T> m_ptr;
98 };
99
100 } // namespace WebCore
101
102 namespace WTF {
103
104 template<typename P> struct HashTraits<WebCore::GCReachableRef<P>> : SimpleClassHashTraits<WebCore::GCReachableRef<P>> {
105     static const bool emptyValueIsZero = true;
106     static WebCore::GCReachableRef<P> emptyValue() { return HashTableEmptyValue; }
107
108     template <typename>
109     static void constructEmptyValue(WebCore::GCReachableRef<P>& slot)
110     {
111         new (NotNull, std::addressof(slot)) WebCore::GCReachableRef<P>(HashTableEmptyValue);
112     }
113
114     static const bool hasIsEmptyValueFunction = true;
115     static bool isEmptyValue(const WebCore::GCReachableRef<P>& value) { return value.isHashTableEmptyValue(); }
116
117     static void assignToEmpty(WebCore::GCReachableRef<P>& emptyValue, WebCore::GCReachableRef<P>&& newValue)
118     {
119         ASSERT(isEmptyValue(emptyValue));
120         emptyValue.assignToHashTableEmptyValue(WTFMove(newValue));
121     }
122
123     typedef P* PeekType;
124     static PeekType peek(const Ref<P>& value) { return const_cast<PeekType>(value.ptrAllowingHashTableEmptyValue()); }
125     static PeekType peek(P* value) { return value; }
126
127     typedef std::optional<Ref<P>> TakeType;
128     static TakeType take(Ref<P>&& value) { return isEmptyValue(value) ? std::nullopt : std::optional<Ref<P>>(WTFMove(value)); }
129 };
130
131 template <typename T, typename U>
132 struct GetPtrHelper<WebCore::GCReachableRef<T, U>> {
133     typedef T* PtrType;
134     static T* getPtr(const WebCore::GCReachableRef<T, U>& reference) { return const_cast<T*>(reference.ptr()); }
135 };
136
137 template <typename T, typename U>
138 struct IsSmartPtr<WebCore::GCReachableRef<T, U>> {
139     static const bool value = true;
140 };
141
142 template<typename P> struct PtrHash<WebCore::GCReachableRef<P>> : PtrHashBase<WebCore::GCReachableRef<P>, IsSmartPtr<WebCore::GCReachableRef<P>>::value> {
143     static const bool safeToCompareToEmptyOrDeleted = false;
144 };
145
146 template<typename P> struct DefaultHash<WebCore::GCReachableRef<P>> {
147     typedef PtrHash<WebCore::GCReachableRef<P>> Hash;
148 };
149
150 } // namespace WTF
151