Remove remaining poisoning code.
[WebKit-https.git] / Source / WTF / wtf / RefCountedArray.h
1 /*
2  * Copyright (C) 2011-2019 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #pragma once
27
28 #include <wtf/DumbPtrTraits.h>
29 #include <wtf/FastMalloc.h>
30 #include <wtf/StdLibExtras.h>
31 #include <wtf/Vector.h>
32
33 // This implements a reference counted array for POD** values, which is optimized for:
34 // - An empty array only uses one word.
35 // - A copy of the array only uses one word (i.e. assignment means aliasing).
36 // - The vector can't grow beyond 2^32-1 elements.
37 // - In all other regards this has similar space usage to a Vector.
38 //
39 // ** This could be modified to support non-POD values quite easily. It just
40 //    hasn't been, so far, because there has been no need. Moreover, even now,
41 //    it's used for things that aren't quite POD according to the official
42 //    defintion, such as JSC::Instruction.
43
44 namespace WTF {
45
46 template<typename T, typename PtrTraits = DumbPtrTraits<T>>
47 class RefCountedArray {
48     enum CommonCopyConstructorTag { CommonCopyConstructor };
49
50 public:
51     RefCountedArray() = default;
52     
53     RefCountedArray(const RefCountedArray& other)
54         : RefCountedArray(CommonCopyConstructor, other)
55     { }
56
57     template<typename OtherTraits>
58     RefCountedArray(const RefCountedArray<T, OtherTraits>& other)
59         : RefCountedArray(CommonCopyConstructor, other)
60     { }
61
62     explicit RefCountedArray(size_t size)
63     {
64         if (!size) {
65             // NOTE: JSC's LowLevelInterpreter relies on this being nullptr when the size is zero.
66             PtrTraits::exchange(m_data, nullptr);
67             return;
68         }
69
70         T* data = (static_cast<Header*>(fastMalloc(Header::size() + sizeof(T) * size)))->payload();
71         m_data = data;
72         Header::fromPayload(data)->refCount = 1;
73         Header::fromPayload(data)->length = size;
74         ASSERT(Header::fromPayload(data)->length == size);
75         VectorTypeOperations<T>::initializeIfNonPOD(begin(), end());
76     }
77
78     template<typename OtherTraits = PtrTraits>
79     RefCountedArray<T, OtherTraits> clone() const
80     {
81         RefCountedArray<T, OtherTraits> result(size());
82         const T* data = this->data();
83         T* resultData = result.data();
84         for (unsigned i = size(); i--;)
85             resultData[i] = data[i];
86         return result;
87     }
88
89     template<size_t inlineCapacity, typename OverflowHandler>
90     explicit RefCountedArray(const Vector<T, inlineCapacity, OverflowHandler>& other)
91     {
92         if (other.isEmpty()) {
93             PtrTraits::exchange(m_data, nullptr);
94             return;
95         }
96         
97         T* data = (static_cast<Header*>(fastMalloc(Header::size() + sizeof(T) * other.size())))->payload();
98         m_data = data;
99         Header::fromPayload(data)->refCount = 1;
100         Header::fromPayload(data)->length = other.size();
101         ASSERT(Header::fromPayload(data)->length == other.size());
102         VectorTypeOperations<T>::uninitializedCopy(other.begin(), other.end(), data);
103     }
104     
105     template<typename OtherTraits = PtrTraits>
106     RefCountedArray& operator=(const RefCountedArray<T, OtherTraits>& other)
107     {
108         return assign<OtherTraits>(other);
109     }
110
111     RefCountedArray& operator=(const RefCountedArray& other)
112     {
113         return assign<PtrTraits>(other);
114     }
115
116     ~RefCountedArray()
117     {
118         if (!m_data)
119             return;
120         T* data = this->data();
121         if (--Header::fromPayload(data)->refCount)
122             return;
123         VectorTypeOperations<T>::destruct(begin(), end());
124         fastFree(Header::fromPayload(data));
125     }
126     
127     unsigned refCount() const
128     {
129         if (!m_data)
130             return 0;
131         return Header::fromPayload(data())->refCount;
132     }
133     
134     size_t size() const
135     {
136         if (!m_data)
137             return 0;
138         return Header::fromPayload(data())->length;
139     }
140     
141     size_t byteSize() const { return size() * sizeof(T); }
142     
143     T* data() { return PtrTraits::unwrap(m_data); }
144     T* begin() { return data(); }
145     T* end()
146     {
147         if (!m_data)
148             return 0;
149         T* data = this->data();
150         return data + Header::fromPayload(data)->length;
151     }
152     
153     const T* data() const { return const_cast<RefCountedArray*>(this)->data(); }
154     const T* begin() const { return const_cast<RefCountedArray*>(this)->begin(); }
155     const T* end() const { return const_cast<RefCountedArray*>(this)->end(); }
156     
157     T& at(size_t i)
158     {
159         ASSERT_WITH_SECURITY_IMPLICATION(i < size());
160         return begin()[i];
161     }
162     
163     const T& at(size_t i) const
164     {
165         ASSERT_WITH_SECURITY_IMPLICATION(i < size());
166         return begin()[i];
167     }
168     
169     T& operator[](size_t i) { return at(i); }
170     const T& operator[](size_t i) const { return at(i); }
171
172     template<typename OtherTraits = PtrTraits>
173     bool operator==(const RefCountedArray<T, OtherTraits>& other) const
174     {
175         T* data = const_cast<T*>(this->data());
176         T* otherData = const_cast<T*>(other.data());
177         if (data == otherData)
178             return true;
179         if (!data || !otherData)
180             return false;
181         unsigned length = Header::fromPayload(data)->length;
182         if (length != Header::fromPayload(otherData)->length)
183             return false;
184         for (unsigned i = 0; i < length; ++i) {
185             if (data[i] != otherData[i])
186                 return false;
187         }
188         return true;
189     }
190
191     bool operator==(const RefCountedArray& other) const { return this->operator==<PtrTraits>(other); }
192     
193 private:
194     template<typename OtherTraits = PtrTraits>
195     RefCountedArray& assign(const RefCountedArray<T, OtherTraits>& other)
196     {
197         T* oldData = data();
198         T* otherData = const_cast<T*>(other.data());
199         if (otherData)
200             Header::fromPayload(otherData)->refCount++;
201         m_data = otherData;
202
203         if (!oldData)
204             return *this;
205         if (--Header::fromPayload(oldData)->refCount)
206             return *this;
207         VectorTypeOperations<T>::destruct(oldData, oldData + Header::fromPayload(oldData)->length);
208         fastFree(Header::fromPayload(oldData));
209         return *this;
210     }
211
212     struct Header {
213         unsigned refCount;
214         unsigned length;
215         
216         static size_t size()
217         {
218             return (sizeof(Header) + 7) & ~7;
219         }
220         
221         T* payload()
222         {
223             char* result = reinterpret_cast<char*>(this) + size();
224             ASSERT(!(bitwise_cast<uintptr_t>(result) & 7));
225             return reinterpret_cast_ptr<T*>(result);
226         }
227         
228         static Header* fromPayload(T* payload)
229         {
230             return reinterpret_cast_ptr<Header*>(reinterpret_cast<char*>(payload) - size());
231         }
232
233         static const Header* fromPayload(const T* payload)
234         {
235             return fromPayload(const_cast<T*>(payload));
236         }
237     };
238
239     template<typename OtherTraits>
240     RefCountedArray(CommonCopyConstructorTag, const RefCountedArray<T, OtherTraits>& other)
241         : m_data(const_cast<T*>(other.data()))
242     {
243         if (m_data)
244             Header::fromPayload(data())->refCount++;
245     }
246
247     friend class JSC::LLIntOffsetsExtractor;
248     typename PtrTraits::StorageType m_data { nullptr };
249 };
250
251 } // namespace WTF
252
253 using WTF::RefCountedArray;