]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/ArrayBuffer.h
JavaScriptCore-7600.1.4.17.5.tar.gz
[apple/javascriptcore.git] / runtime / ArrayBuffer.h
1 /*
2 * Copyright (C) 2009, 2013 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 #ifndef ArrayBuffer_h
27 #define ArrayBuffer_h
28
29 #include "GCIncomingRefCounted.h"
30 #include "Weak.h"
31 #include <wtf/PassRefPtr.h>
32 #include <wtf/StdLibExtras.h>
33 #include <wtf/Vector.h>
34
35 namespace JSC {
36
37 class ArrayBuffer;
38 class ArrayBufferView;
39 class JSArrayBuffer;
40
41 class ArrayBufferContents {
42 WTF_MAKE_NONCOPYABLE(ArrayBufferContents);
43 public:
44 ArrayBufferContents()
45 : m_data(0)
46 , m_sizeInBytes(0)
47 { }
48
49 inline ~ArrayBufferContents();
50
51 void* data() { return m_data; }
52 unsigned sizeInBytes() { return m_sizeInBytes; }
53
54 private:
55 ArrayBufferContents(void* data, unsigned sizeInBytes)
56 : m_data(data)
57 , m_sizeInBytes(sizeInBytes)
58 { }
59
60 friend class ArrayBuffer;
61
62 enum InitializationPolicy {
63 ZeroInitialize,
64 DontInitialize
65 };
66
67 static inline void tryAllocate(unsigned numElements, unsigned elementByteSize, InitializationPolicy, ArrayBufferContents&);
68 void transfer(ArrayBufferContents& other)
69 {
70 ASSERT(!other.m_data);
71 other.m_data = m_data;
72 other.m_sizeInBytes = m_sizeInBytes;
73 m_data = 0;
74 m_sizeInBytes = 0;
75 }
76
77 void copyTo(ArrayBufferContents& other)
78 {
79 ASSERT(!other.m_data);
80 ArrayBufferContents::tryAllocate(m_sizeInBytes, sizeof(char), ArrayBufferContents::DontInitialize, other);
81 if (!other.m_data)
82 return;
83 memcpy(other.m_data, m_data, m_sizeInBytes);
84 other.m_sizeInBytes = m_sizeInBytes;
85 }
86
87 void* m_data;
88 unsigned m_sizeInBytes;
89 };
90
91 class ArrayBuffer : public GCIncomingRefCounted<ArrayBuffer> {
92 public:
93 static inline PassRefPtr<ArrayBuffer> create(unsigned numElements, unsigned elementByteSize);
94 static inline PassRefPtr<ArrayBuffer> create(ArrayBuffer*);
95 static inline PassRefPtr<ArrayBuffer> create(const void* source, unsigned byteLength);
96 static inline PassRefPtr<ArrayBuffer> create(ArrayBufferContents&);
97 static inline PassRefPtr<ArrayBuffer> createAdopted(const void* data, unsigned byteLength);
98
99 // Only for use by Uint8ClampedArray::createUninitialized and SharedBuffer::createArrayBuffer.
100 static inline PassRefPtr<ArrayBuffer> createUninitialized(unsigned numElements, unsigned elementByteSize);
101
102 inline void* data();
103 inline const void* data() const;
104 inline unsigned byteLength() const;
105
106 inline size_t gcSizeEstimateInBytes() const;
107
108 inline PassRefPtr<ArrayBuffer> slice(int begin, int end) const;
109 inline PassRefPtr<ArrayBuffer> slice(int begin) const;
110
111 inline void pin();
112 inline void unpin();
113
114 JS_EXPORT_PRIVATE bool transfer(ArrayBufferContents&);
115 bool isNeutered() { return !m_contents.m_data; }
116
117 static ptrdiff_t offsetOfData() { return OBJECT_OFFSETOF(ArrayBuffer, m_contents) + OBJECT_OFFSETOF(ArrayBufferContents, m_data); }
118
119 ~ArrayBuffer() { }
120
121 private:
122 static inline PassRefPtr<ArrayBuffer> create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
123
124 inline ArrayBuffer(ArrayBufferContents&);
125 inline PassRefPtr<ArrayBuffer> sliceImpl(unsigned begin, unsigned end) const;
126 inline unsigned clampIndex(int index) const;
127 static inline int clampValue(int x, int left, int right);
128
129 unsigned m_pinCount;
130 ArrayBufferContents m_contents;
131
132 public:
133 Weak<JSArrayBuffer> m_wrapper;
134 };
135
136 int ArrayBuffer::clampValue(int x, int left, int right)
137 {
138 ASSERT(left <= right);
139 if (x < left)
140 x = left;
141 if (right < x)
142 x = right;
143 return x;
144 }
145
146 PassRefPtr<ArrayBuffer> ArrayBuffer::create(unsigned numElements, unsigned elementByteSize)
147 {
148 return create(numElements, elementByteSize, ArrayBufferContents::ZeroInitialize);
149 }
150
151 PassRefPtr<ArrayBuffer> ArrayBuffer::create(ArrayBuffer* other)
152 {
153 return ArrayBuffer::create(other->data(), other->byteLength());
154 }
155
156 PassRefPtr<ArrayBuffer> ArrayBuffer::create(const void* source, unsigned byteLength)
157 {
158 ArrayBufferContents contents;
159 ArrayBufferContents::tryAllocate(byteLength, 1, ArrayBufferContents::ZeroInitialize, contents);
160 if (!contents.m_data)
161 return 0;
162 RefPtr<ArrayBuffer> buffer = adoptRef(new ArrayBuffer(contents));
163 ASSERT(!byteLength || source);
164 memcpy(buffer->data(), source, byteLength);
165 return buffer.release();
166 }
167
168 PassRefPtr<ArrayBuffer> ArrayBuffer::create(ArrayBufferContents& contents)
169 {
170 return adoptRef(new ArrayBuffer(contents));
171 }
172
173 PassRefPtr<ArrayBuffer> ArrayBuffer::createAdopted(const void* data, unsigned byteLength)
174 {
175 ArrayBufferContents contents(const_cast<void*>(data), byteLength);
176 return create(contents);
177 }
178
179 PassRefPtr<ArrayBuffer> ArrayBuffer::createUninitialized(unsigned numElements, unsigned elementByteSize)
180 {
181 return create(numElements, elementByteSize, ArrayBufferContents::DontInitialize);
182 }
183
184 PassRefPtr<ArrayBuffer> ArrayBuffer::create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy)
185 {
186 ArrayBufferContents contents;
187 ArrayBufferContents::tryAllocate(numElements, elementByteSize, policy, contents);
188 if (!contents.m_data)
189 return 0;
190 return adoptRef(new ArrayBuffer(contents));
191 }
192
193 ArrayBuffer::ArrayBuffer(ArrayBufferContents& contents)
194 : m_pinCount(0)
195 {
196 contents.transfer(m_contents);
197 }
198
199 void* ArrayBuffer::data()
200 {
201 return m_contents.m_data;
202 }
203
204 const void* ArrayBuffer::data() const
205 {
206 return m_contents.m_data;
207 }
208
209 unsigned ArrayBuffer::byteLength() const
210 {
211 return m_contents.m_sizeInBytes;
212 }
213
214 size_t ArrayBuffer::gcSizeEstimateInBytes() const
215 {
216 return sizeof(ArrayBuffer) + static_cast<size_t>(byteLength());
217 }
218
219 PassRefPtr<ArrayBuffer> ArrayBuffer::slice(int begin, int end) const
220 {
221 return sliceImpl(clampIndex(begin), clampIndex(end));
222 }
223
224 PassRefPtr<ArrayBuffer> ArrayBuffer::slice(int begin) const
225 {
226 return sliceImpl(clampIndex(begin), byteLength());
227 }
228
229 PassRefPtr<ArrayBuffer> ArrayBuffer::sliceImpl(unsigned begin, unsigned end) const
230 {
231 unsigned size = begin <= end ? end - begin : 0;
232 return ArrayBuffer::create(static_cast<const char*>(data()) + begin, size);
233 }
234
235 unsigned ArrayBuffer::clampIndex(int index) const
236 {
237 unsigned currentLength = byteLength();
238 if (index < 0)
239 index = currentLength + index;
240 return clampValue(index, 0, currentLength);
241 }
242
243 void ArrayBuffer::pin()
244 {
245 m_pinCount++;
246 }
247
248 void ArrayBuffer::unpin()
249 {
250 m_pinCount--;
251 }
252
253 void ArrayBufferContents::tryAllocate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy, ArrayBufferContents& result)
254 {
255 // Do not allow 31-bit overflow of the total size.
256 if (numElements) {
257 unsigned totalSize = numElements * elementByteSize;
258 if (totalSize / numElements != elementByteSize
259 || totalSize > static_cast<unsigned>(std::numeric_limits<int32_t>::max())) {
260 result.m_data = 0;
261 return;
262 }
263 }
264 bool allocationSucceeded = false;
265 if (policy == ZeroInitialize)
266 allocationSucceeded = WTF::tryFastCalloc(numElements, elementByteSize).getValue(result.m_data);
267 else {
268 ASSERT(policy == DontInitialize);
269 allocationSucceeded = WTF::tryFastMalloc(numElements * elementByteSize).getValue(result.m_data);
270 }
271
272 if (allocationSucceeded) {
273 result.m_sizeInBytes = numElements * elementByteSize;
274 return;
275 }
276 result.m_data = 0;
277 }
278
279 ArrayBufferContents::~ArrayBufferContents()
280 {
281 WTF::fastFree(m_data);
282 }
283
284 } // namespace JSC
285
286 using JSC::ArrayBuffer;
287
288 #endif // ArrayBuffer_h
289