2 * Copyright (C) 2009, 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "GCIncomingRefCounted.h"
31 #include <wtf/PassRefPtr.h>
32 #include <wtf/StdLibExtras.h>
33 #include <wtf/Vector.h>
38 class ArrayBufferView
;
41 class ArrayBufferContents
{
42 WTF_MAKE_NONCOPYABLE(ArrayBufferContents
);
49 inline ~ArrayBufferContents();
51 void* data() { return m_data
; }
52 unsigned sizeInBytes() { return m_sizeInBytes
; }
55 ArrayBufferContents(void* data
, unsigned sizeInBytes
)
57 , m_sizeInBytes(sizeInBytes
)
60 friend class ArrayBuffer
;
62 enum InitializationPolicy
{
67 static inline void tryAllocate(unsigned numElements
, unsigned elementByteSize
, InitializationPolicy
, ArrayBufferContents
&);
68 void transfer(ArrayBufferContents
& other
)
70 ASSERT(!other
.m_data
);
71 other
.m_data
= m_data
;
72 other
.m_sizeInBytes
= m_sizeInBytes
;
77 void copyTo(ArrayBufferContents
& other
)
79 ASSERT(!other
.m_data
);
80 ArrayBufferContents::tryAllocate(m_sizeInBytes
, sizeof(char), ArrayBufferContents::DontInitialize
, other
);
83 memcpy(other
.m_data
, m_data
, m_sizeInBytes
);
84 other
.m_sizeInBytes
= m_sizeInBytes
;
88 unsigned m_sizeInBytes
;
91 class ArrayBuffer
: public GCIncomingRefCounted
<ArrayBuffer
> {
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
);
99 // Only for use by Uint8ClampedArray::createUninitialized and SharedBuffer::createArrayBuffer.
100 static inline PassRefPtr
<ArrayBuffer
> createUninitialized(unsigned numElements
, unsigned elementByteSize
);
103 inline const void* data() const;
104 inline unsigned byteLength() const;
106 inline size_t gcSizeEstimateInBytes() const;
108 inline PassRefPtr
<ArrayBuffer
> slice(int begin
, int end
) const;
109 inline PassRefPtr
<ArrayBuffer
> slice(int begin
) const;
114 JS_EXPORT_PRIVATE
bool transfer(ArrayBufferContents
&);
115 bool isNeutered() { return !m_contents
.m_data
; }
117 static ptrdiff_t offsetOfData() { return OBJECT_OFFSETOF(ArrayBuffer
, m_contents
) + OBJECT_OFFSETOF(ArrayBufferContents
, m_data
); }
122 static inline PassRefPtr
<ArrayBuffer
> create(unsigned numElements
, unsigned elementByteSize
, ArrayBufferContents::InitializationPolicy
);
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
);
130 ArrayBufferContents m_contents
;
133 Weak
<JSArrayBuffer
> m_wrapper
;
136 int ArrayBuffer::clampValue(int x
, int left
, int right
)
138 ASSERT(left
<= right
);
146 PassRefPtr
<ArrayBuffer
> ArrayBuffer::create(unsigned numElements
, unsigned elementByteSize
)
148 return create(numElements
, elementByteSize
, ArrayBufferContents::ZeroInitialize
);
151 PassRefPtr
<ArrayBuffer
> ArrayBuffer::create(ArrayBuffer
* other
)
153 return ArrayBuffer::create(other
->data(), other
->byteLength());
156 PassRefPtr
<ArrayBuffer
> ArrayBuffer::create(const void* source
, unsigned byteLength
)
158 ArrayBufferContents contents
;
159 ArrayBufferContents::tryAllocate(byteLength
, 1, ArrayBufferContents::ZeroInitialize
, contents
);
160 if (!contents
.m_data
)
162 RefPtr
<ArrayBuffer
> buffer
= adoptRef(new ArrayBuffer(contents
));
163 ASSERT(!byteLength
|| source
);
164 memcpy(buffer
->data(), source
, byteLength
);
165 return buffer
.release();
168 PassRefPtr
<ArrayBuffer
> ArrayBuffer::create(ArrayBufferContents
& contents
)
170 return adoptRef(new ArrayBuffer(contents
));
173 PassRefPtr
<ArrayBuffer
> ArrayBuffer::createAdopted(const void* data
, unsigned byteLength
)
175 ArrayBufferContents
contents(const_cast<void*>(data
), byteLength
);
176 return create(contents
);
179 PassRefPtr
<ArrayBuffer
> ArrayBuffer::createUninitialized(unsigned numElements
, unsigned elementByteSize
)
181 return create(numElements
, elementByteSize
, ArrayBufferContents::DontInitialize
);
184 PassRefPtr
<ArrayBuffer
> ArrayBuffer::create(unsigned numElements
, unsigned elementByteSize
, ArrayBufferContents::InitializationPolicy policy
)
186 ArrayBufferContents contents
;
187 ArrayBufferContents::tryAllocate(numElements
, elementByteSize
, policy
, contents
);
188 if (!contents
.m_data
)
190 return adoptRef(new ArrayBuffer(contents
));
193 ArrayBuffer::ArrayBuffer(ArrayBufferContents
& contents
)
196 contents
.transfer(m_contents
);
199 void* ArrayBuffer::data()
201 return m_contents
.m_data
;
204 const void* ArrayBuffer::data() const
206 return m_contents
.m_data
;
209 unsigned ArrayBuffer::byteLength() const
211 return m_contents
.m_sizeInBytes
;
214 size_t ArrayBuffer::gcSizeEstimateInBytes() const
216 return sizeof(ArrayBuffer
) + static_cast<size_t>(byteLength());
219 PassRefPtr
<ArrayBuffer
> ArrayBuffer::slice(int begin
, int end
) const
221 return sliceImpl(clampIndex(begin
), clampIndex(end
));
224 PassRefPtr
<ArrayBuffer
> ArrayBuffer::slice(int begin
) const
226 return sliceImpl(clampIndex(begin
), byteLength());
229 PassRefPtr
<ArrayBuffer
> ArrayBuffer::sliceImpl(unsigned begin
, unsigned end
) const
231 unsigned size
= begin
<= end
? end
- begin
: 0;
232 return ArrayBuffer::create(static_cast<const char*>(data()) + begin
, size
);
235 unsigned ArrayBuffer::clampIndex(int index
) const
237 unsigned currentLength
= byteLength();
239 index
= currentLength
+ index
;
240 return clampValue(index
, 0, currentLength
);
243 void ArrayBuffer::pin()
248 void ArrayBuffer::unpin()
253 void ArrayBufferContents::tryAllocate(unsigned numElements
, unsigned elementByteSize
, ArrayBufferContents::InitializationPolicy policy
, ArrayBufferContents
& result
)
255 // Do not allow 31-bit overflow of the total size.
257 unsigned totalSize
= numElements
* elementByteSize
;
258 if (totalSize
/ numElements
!= elementByteSize
259 || totalSize
> static_cast<unsigned>(std::numeric_limits
<int32_t>::max())) {
264 bool allocationSucceeded
= false;
265 if (policy
== ZeroInitialize
)
266 allocationSucceeded
= WTF::tryFastCalloc(numElements
, elementByteSize
).getValue(result
.m_data
);
268 ASSERT(policy
== DontInitialize
);
269 allocationSucceeded
= WTF::tryFastMalloc(numElements
* elementByteSize
).getValue(result
.m_data
);
272 if (allocationSucceeded
) {
273 result
.m_sizeInBytes
= numElements
* elementByteSize
;
279 ArrayBufferContents::~ArrayBufferContents()
281 WTF::fastFree(m_data
);
286 using JSC::ArrayBuffer
;
288 #endif // ArrayBuffer_h