1/* 2 * Copyright (C) 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 JSGenericTypedArrayView_h 27#define JSGenericTypedArrayView_h 28 29#include "JSArrayBufferView.h" 30#include "ToNativeFromValue.h" 31 32namespace JSC { 33 34JS_EXPORT_PRIVATE const ClassInfo* getInt8ArrayClassInfo(); 35JS_EXPORT_PRIVATE const ClassInfo* getInt16ArrayClassInfo(); 36JS_EXPORT_PRIVATE const ClassInfo* getInt32ArrayClassInfo(); 37JS_EXPORT_PRIVATE const ClassInfo* getUint8ArrayClassInfo(); 38JS_EXPORT_PRIVATE const ClassInfo* getUint8ClampedArrayClassInfo(); 39JS_EXPORT_PRIVATE const ClassInfo* getUint16ArrayClassInfo(); 40JS_EXPORT_PRIVATE const ClassInfo* getUint32ArrayClassInfo(); 41JS_EXPORT_PRIVATE const ClassInfo* getFloat32ArrayClassInfo(); 42JS_EXPORT_PRIVATE const ClassInfo* getFloat64ArrayClassInfo(); 43 44// A typed array view is our representation of a typed array object as seen 45// from JavaScript. For example: 46// 47// var o = new Int8Array(100); 48// 49// Here, 'o' points to a JSGenericTypedArrayView<int8_t>. 50// 51// Views contain five fields: 52// 53// Structure* S // from JSCell 54// Butterfly* B // from JSObject 55// ElementType* V 56// uint32_t L 57// TypedArrayMode M 58// 59// These fields take up a total of four pointer-width words. FIXME: Make 60// it take less words! 61// 62// B is usually unused but may stored some additional "overflow" data for 63// one of the modes. V always points to the base of the typed array's data, 64// and may point to either GC-managed copied space, or data in the C heap; 65// which of those things it points to is governed by the mode although for 66// simple accesses to the view you can just read from the pointer either 67// way. M specifies the mode of the view. L is the length, in units that 68// depend on the view's type. 69 70// The JSGenericTypedArrayView is templatized by an Adaptor that controls 71// the element type and how it's converted; it should obey the following 72// interface; I use int8_t as an example: 73// 74// struct Adaptor { 75// typedef int8_t Type; 76// typedef Int8Array ViewType; 77// typedef JSInt8Array JSViewType; 78// static int8_t toNativeFromInt32(int32_t); 79// static int8_t toNativeFromUint32(uint32_t); 80// static int8_t toNativeFromDouble(double); 81// static JSValue toJSValue(int8_t); 82// static double toDouble(int8_t); 83// template<T> static T::Type convertTo(uint8_t); 84// }; 85 86template<typename Adaptor> 87class JSGenericTypedArrayView : public JSArrayBufferView { 88public: 89 typedef JSArrayBufferView Base; 90 static const unsigned elementSize = sizeof(typename Adaptor::Type); 91 92protected: 93 JSGenericTypedArrayView(VM&, ConstructionContext&); 94 95public: 96 static JSGenericTypedArrayView* create(ExecState*, Structure*, unsigned length); 97 static JSGenericTypedArrayView* createUninitialized(ExecState*, Structure*, unsigned length); 98 static JSGenericTypedArrayView* create(ExecState*, Structure*, PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length); 99 static JSGenericTypedArrayView* create(VM&, Structure*, PassRefPtr<typename Adaptor::ViewType> impl); 100 static JSGenericTypedArrayView* create(Structure*, JSGlobalObject*, PassRefPtr<typename Adaptor::ViewType> impl); 101 102 unsigned byteLength() const { return m_length * sizeof(typename Adaptor::Type); } 103 size_t byteSize() const { return sizeOf(m_length, sizeof(typename Adaptor::Type)); } 104 105 const typename Adaptor::Type* typedVector() const 106 { 107 return static_cast<const typename Adaptor::Type*>(m_vector); 108 } 109 typename Adaptor::Type* typedVector() 110 { 111 return static_cast<typename Adaptor::Type*>(m_vector); 112 } 113 114 // These methods are meant to match indexed access methods that JSObject 115 // supports - hence the slight redundancy. 116 bool canGetIndexQuickly(unsigned i) 117 { 118 return i < m_length; 119 } 120 bool canSetIndexQuickly(unsigned i) 121 { 122 return i < m_length; 123 } 124 125 typename Adaptor::Type getIndexQuicklyAsNativeValue(unsigned i) 126 { 127 ASSERT(i < m_length); 128 return typedVector()[i]; 129 } 130 131 double getIndexQuicklyAsDouble(unsigned i) 132 { 133 return Adaptor::toDouble(getIndexQuicklyAsNativeValue(i)); 134 } 135 136 JSValue getIndexQuickly(unsigned i) 137 { 138 return Adaptor::toJSValue(getIndexQuicklyAsNativeValue(i)); 139 } 140 141 void setIndexQuicklyToNativeValue(unsigned i, typename Adaptor::Type value) 142 { 143 ASSERT(i < m_length); 144 typedVector()[i] = value; 145 } 146 147 void setIndexQuicklyToDouble(unsigned i, double value) 148 { 149 setIndexQuicklyToNativeValue(i, toNativeFromValue<Adaptor>(value)); 150 } 151 152 void setIndexQuickly(unsigned i, JSValue value) 153 { 154 setIndexQuicklyToNativeValue(i, toNativeFromValue<Adaptor>(value)); 155 } 156 157 bool setIndex(ExecState* exec, unsigned i, JSValue jsValue) 158 { 159 typename Adaptor::Type value = toNativeFromValue<Adaptor>(exec, jsValue); 160 if (exec->hadException()) 161 return false; 162 163 if (i >= m_length) 164 return false; 165 166 setIndexQuicklyToNativeValue(i, value); 167 return true; 168 } 169 170 bool canAccessRangeQuickly(unsigned offset, unsigned length) 171 { 172 return offset <= m_length 173 && offset + length <= m_length 174 // check overflow 175 && offset + length >= offset; 176 } 177 178 // Like canSetQuickly, except: if it returns false, it will throw the 179 // appropriate exception. 180 bool validateRange(ExecState*, unsigned offset, unsigned length); 181 182 // Returns true if successful, and false on error; if it returns false 183 // then it will have thrown an exception. 184 bool set(ExecState*, JSObject*, unsigned offset, unsigned length); 185 186 PassRefPtr<typename Adaptor::ViewType> typedImpl() 187 { 188 return Adaptor::ViewType::create(buffer(), byteOffset(), length()); 189 } 190 191 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) 192 { 193 return Structure::create(vm, globalObject, prototype, TypeInfo(typeForTypedArrayType(Adaptor::typeValue), StructureFlags), info(), NonArray); 194 } 195 196 static const ClassInfo s_info; // This is never accessed directly, since that would break linkage on some compilers. 197 198 static const ClassInfo* info() 199 { 200 switch (Adaptor::typeValue) { 201 case TypeInt8: 202 return getInt8ArrayClassInfo(); 203 case TypeInt16: 204 return getInt16ArrayClassInfo(); 205 case TypeInt32: 206 return getInt32ArrayClassInfo(); 207 case TypeUint8: 208 return getUint8ArrayClassInfo(); 209 case TypeUint8Clamped: 210 return getUint8ClampedArrayClassInfo(); 211 case TypeUint16: 212 return getUint16ArrayClassInfo(); 213 case TypeUint32: 214 return getUint32ArrayClassInfo(); 215 case TypeFloat32: 216 return getFloat32ArrayClassInfo(); 217 case TypeFloat64: 218 return getFloat64ArrayClassInfo(); 219 default: 220 RELEASE_ASSERT_NOT_REACHED(); 221 return 0; 222 } 223 } 224 225 ArrayBuffer* existingBuffer(); 226 227 static const TypedArrayType TypedArrayStorageType = Adaptor::typeValue; 228 229protected: 230 friend struct TypedArrayClassInfos; 231 232 static const unsigned StructureFlags = OverridesGetPropertyNames | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | Base::StructureFlags; 233 234 static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); 235 static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); 236 static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); 237 static bool deleteProperty(JSCell*, ExecState*, PropertyName); 238 239 static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&); 240 static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); 241 static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); 242 243 static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); 244 static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); 245 246 static void visitChildren(JSCell*, SlotVisitor&); 247 static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken); 248 249 // Allocates the full-on native buffer and moves data into the C heap if 250 // necessary. Note that this never allocates in the GC heap. 251 static ArrayBuffer* slowDownAndWasteMemory(JSArrayBufferView*); 252 static PassRefPtr<ArrayBufferView> getTypedArrayImpl(JSArrayBufferView*); 253 254private: 255 // Returns true if successful, and false on error; it will throw on error. 256 template<typename OtherAdaptor> 257 bool setWithSpecificType( 258 ExecState*, JSGenericTypedArrayView<OtherAdaptor>*, 259 unsigned offset, unsigned length); 260}; 261 262template<typename Adaptor> 263inline PassRefPtr<typename Adaptor::ViewType> toNativeTypedView(JSValue value) 264{ 265 typename Adaptor::JSViewType* wrapper = jsDynamicCast<typename Adaptor::JSViewType*>(value); 266 if (!wrapper) 267 return 0; 268 return wrapper->typedImpl(); 269} 270 271} // namespace JSC 272 273#endif // JSGenericTypedArrayView_h 274 275