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 35namespace JSC { 36 37class ArrayBuffer; 38class ArrayBufferView; 39class JSArrayBuffer; 40 41class ArrayBufferContents { 42 WTF_MAKE_NONCOPYABLE(ArrayBufferContents); 43public: 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 54private: 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 91class ArrayBuffer : public GCIncomingRefCounted<ArrayBuffer> { 92public: 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 121private: 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 132public: 133 Weak<JSArrayBuffer> m_wrapper; 134}; 135 136int 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 146PassRefPtr<ArrayBuffer> ArrayBuffer::create(unsigned numElements, unsigned elementByteSize) 147{ 148 return create(numElements, elementByteSize, ArrayBufferContents::ZeroInitialize); 149} 150 151PassRefPtr<ArrayBuffer> ArrayBuffer::create(ArrayBuffer* other) 152{ 153 return ArrayBuffer::create(other->data(), other->byteLength()); 154} 155 156PassRefPtr<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 168PassRefPtr<ArrayBuffer> ArrayBuffer::create(ArrayBufferContents& contents) 169{ 170 return adoptRef(new ArrayBuffer(contents)); 171} 172 173PassRefPtr<ArrayBuffer> ArrayBuffer::createAdopted(const void* data, unsigned byteLength) 174{ 175 ArrayBufferContents contents(const_cast<void*>(data), byteLength); 176 return create(contents); 177} 178 179PassRefPtr<ArrayBuffer> ArrayBuffer::createUninitialized(unsigned numElements, unsigned elementByteSize) 180{ 181 return create(numElements, elementByteSize, ArrayBufferContents::DontInitialize); 182} 183 184PassRefPtr<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 193ArrayBuffer::ArrayBuffer(ArrayBufferContents& contents) 194 : m_pinCount(0) 195{ 196 contents.transfer(m_contents); 197} 198 199void* ArrayBuffer::data() 200{ 201 return m_contents.m_data; 202} 203 204const void* ArrayBuffer::data() const 205{ 206 return m_contents.m_data; 207} 208 209unsigned ArrayBuffer::byteLength() const 210{ 211 return m_contents.m_sizeInBytes; 212} 213 214size_t ArrayBuffer::gcSizeEstimateInBytes() const 215{ 216 return sizeof(ArrayBuffer) + static_cast<size_t>(byteLength()); 217} 218 219PassRefPtr<ArrayBuffer> ArrayBuffer::slice(int begin, int end) const 220{ 221 return sliceImpl(clampIndex(begin), clampIndex(end)); 222} 223 224PassRefPtr<ArrayBuffer> ArrayBuffer::slice(int begin) const 225{ 226 return sliceImpl(clampIndex(begin), byteLength()); 227} 228 229PassRefPtr<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 235unsigned 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 243void ArrayBuffer::pin() 244{ 245 m_pinCount++; 246} 247 248void ArrayBuffer::unpin() 249{ 250 m_pinCount--; 251} 252 253void 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 279ArrayBufferContents::~ArrayBufferContents() 280{ 281 WTF::fastFree(m_data); 282} 283 284} // namespace JSC 285 286using JSC::ArrayBuffer; 287 288#endif // ArrayBuffer_h 289 290