1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/ArrayBufferObject.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,402 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef vm_ArrayBufferObject_h 1.11 +#define vm_ArrayBufferObject_h 1.12 + 1.13 +#include "jsobj.h" 1.14 + 1.15 +#include "builtin/TypedObjectConstants.h" 1.16 +#include "vm/Runtime.h" 1.17 + 1.18 +typedef struct JSProperty JSProperty; 1.19 + 1.20 +namespace js { 1.21 + 1.22 +class ArrayBufferViewObject; 1.23 + 1.24 +// The inheritance hierarchy for the various classes relating to typed arrays 1.25 +// is as follows. 1.26 +// 1.27 +// - JSObject 1.28 +// - ArrayBufferObject 1.29 +// - SharedArrayBufferObject 1.30 +// - ArrayBufferViewObject 1.31 +// - DataViewObject 1.32 +// - TypedArrayObject (declared in vm/TypedArrayObject.h) 1.33 +// - TypedArrayObjectTemplate 1.34 +// - Int8ArrayObject 1.35 +// - Uint8ArrayObject 1.36 +// - ... 1.37 +// - TypedObject (declared in builtin/TypedObject.h) 1.38 +// 1.39 +// Note that |TypedArrayObjectTemplate| is just an implementation 1.40 +// detail that makes implementing its various subclasses easier. 1.41 + 1.42 +typedef Vector<ArrayBufferObject *, 0, SystemAllocPolicy> ArrayBufferVector; 1.43 + 1.44 +/* 1.45 + * ArrayBufferObject 1.46 + * 1.47 + * This class holds the underlying raw buffer that the various 1.48 + * ArrayBufferViewObject subclasses (DataViewObject and the TypedArrays) 1.49 + * access. It can be created explicitly and passed to an ArrayBufferViewObject 1.50 + * subclass, or can be created implicitly by constructing a TypedArrayObject 1.51 + * with a size. 1.52 + */ 1.53 +class ArrayBufferObject : public JSObject 1.54 +{ 1.55 + static bool byteLengthGetterImpl(JSContext *cx, CallArgs args); 1.56 + static bool fun_slice_impl(JSContext *cx, CallArgs args); 1.57 + 1.58 + public: 1.59 + static const uint8_t DATA_SLOT = 0; 1.60 + static const uint8_t BYTE_LENGTH_SLOT = 1; 1.61 + static const uint8_t VIEW_LIST_SLOT = 2; 1.62 + static const uint8_t FLAGS_SLOT = 3; 1.63 + 1.64 + static const uint8_t RESERVED_SLOTS = 4; 1.65 + 1.66 + static const size_t ARRAY_BUFFER_ALIGNMENT = 8; 1.67 + 1.68 + static const Class class_; 1.69 + 1.70 + static const Class protoClass; 1.71 + static const JSFunctionSpec jsfuncs[]; 1.72 + static const JSFunctionSpec jsstaticfuncs[]; 1.73 + 1.74 + static bool byteLengthGetter(JSContext *cx, unsigned argc, Value *vp); 1.75 + 1.76 + static bool fun_slice(JSContext *cx, unsigned argc, Value *vp); 1.77 + 1.78 + static bool fun_isView(JSContext *cx, unsigned argc, Value *vp); 1.79 + 1.80 + static bool class_constructor(JSContext *cx, unsigned argc, Value *vp); 1.81 + 1.82 + static ArrayBufferObject *create(JSContext *cx, uint32_t nbytes, void *contents = nullptr, 1.83 + NewObjectKind newKind = GenericObject, bool mapped = false); 1.84 + 1.85 + static JSObject *createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer, 1.86 + uint32_t begin, uint32_t end); 1.87 + 1.88 + static bool createDataViewForThisImpl(JSContext *cx, CallArgs args); 1.89 + static bool createDataViewForThis(JSContext *cx, unsigned argc, Value *vp); 1.90 + 1.91 + template<typename T> 1.92 + static bool createTypedArrayFromBufferImpl(JSContext *cx, CallArgs args); 1.93 + 1.94 + template<typename T> 1.95 + static bool createTypedArrayFromBuffer(JSContext *cx, unsigned argc, Value *vp); 1.96 + 1.97 + static void obj_trace(JSTracer *trc, JSObject *obj); 1.98 + 1.99 + static void sweep(JSCompartment *rt); 1.100 + 1.101 + static void resetArrayBufferList(JSCompartment *rt); 1.102 + static bool saveArrayBufferList(JSCompartment *c, ArrayBufferVector &vector); 1.103 + static void restoreArrayBufferLists(ArrayBufferVector &vector); 1.104 + 1.105 + static void *stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer); 1.106 + 1.107 + bool hasStealableContents() const { 1.108 + // Inline elements strictly adhere to the corresponding buffer. 1.109 + if (!ownsData()) 1.110 + return false; 1.111 + 1.112 + // asm.js buffer contents are transferred by copying, just like inline 1.113 + // elements. 1.114 + if (isAsmJSArrayBuffer()) 1.115 + return false; 1.116 + 1.117 + // Neutered contents aren't transferrable because we want a neutered 1.118 + // array's contents to be backed by zeroed memory equal in length to 1.119 + // the original buffer contents. Transferring these contents would 1.120 + // allocate new ones based on the current byteLength, which is 0 for a 1.121 + // neutered array -- not the original byteLength. 1.122 + return !isNeutered(); 1.123 + } 1.124 + 1.125 + static void addSizeOfExcludingThis(JSObject *obj, mozilla::MallocSizeOf mallocSizeOf, 1.126 + JS::ObjectsExtraSizes *sizes); 1.127 + 1.128 + void addView(ArrayBufferViewObject *view); 1.129 + 1.130 + void setNewOwnedData(FreeOp* fop, void *newData); 1.131 + void changeContents(JSContext *cx, void *newData); 1.132 + 1.133 + /* 1.134 + * Ensure data is not stored inline in the object. Used when handing back a 1.135 + * GC-safe pointer. 1.136 + */ 1.137 + static bool ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer); 1.138 + 1.139 + bool canNeuter(JSContext *cx); 1.140 + 1.141 + /* Neuter this buffer and all its views. */ 1.142 + static void neuter(JSContext *cx, Handle<ArrayBufferObject*> buffer, void *newData); 1.143 + 1.144 + uint8_t *dataPointer() const; 1.145 + size_t byteLength() const; 1.146 + 1.147 + void releaseData(FreeOp *fop); 1.148 + 1.149 + /* 1.150 + * Check if the arrayBuffer contains any data. This will return false for 1.151 + * ArrayBuffer.prototype and neutered ArrayBuffers. 1.152 + */ 1.153 + bool hasData() const { 1.154 + return getClass() == &class_; 1.155 + } 1.156 + 1.157 + bool isAsmJSArrayBuffer() const { return flags() & ASMJS_BUFFER; } 1.158 + bool isSharedArrayBuffer() const { return flags() & SHARED_BUFFER; } 1.159 + bool isMappedArrayBuffer() const { return flags() & MAPPED_BUFFER; } 1.160 + bool isNeutered() const { return flags() & NEUTERED_BUFFER; } 1.161 + 1.162 + static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer); 1.163 + static bool canNeuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer); 1.164 + 1.165 + static void finalize(FreeOp *fop, JSObject *obj); 1.166 + 1.167 + static void *createMappedContents(int fd, size_t offset, size_t length); 1.168 + 1.169 + static size_t flagsOffset() { 1.170 + return getFixedSlotOffset(FLAGS_SLOT); 1.171 + } 1.172 + 1.173 + static uint32_t neuteredFlag() { return NEUTERED_BUFFER; } 1.174 + 1.175 + protected: 1.176 + enum OwnsState { 1.177 + DoesntOwnData = 0, 1.178 + OwnsData = 1, 1.179 + }; 1.180 + 1.181 + void setDataPointer(void *data, OwnsState ownsState); 1.182 + void setByteLength(size_t length); 1.183 + 1.184 + ArrayBufferViewObject *viewList() const; 1.185 + void setViewList(ArrayBufferViewObject *viewsHead); 1.186 + void setViewListNoBarrier(ArrayBufferViewObject *viewsHead); 1.187 + 1.188 + enum ArrayBufferFlags { 1.189 + // In the gcLiveArrayBuffers list. 1.190 + IN_LIVE_LIST = 0x1, 1.191 + 1.192 + // The dataPointer() is owned by this buffer and should be released 1.193 + // when no longer in use. Releasing the pointer may be done by either 1.194 + // freeing or unmapping it, and how to do this is determined by the 1.195 + // buffer's other flags. 1.196 + OWNS_DATA = 0x2, 1.197 + 1.198 + ASMJS_BUFFER = 0x4, 1.199 + SHARED_BUFFER = 0x8, 1.200 + MAPPED_BUFFER = 0x10, 1.201 + NEUTERED_BUFFER = 0x20 1.202 + }; 1.203 + 1.204 + uint32_t flags() const; 1.205 + void setFlags(uint32_t flags); 1.206 + 1.207 + bool inLiveList() const { return flags() & IN_LIVE_LIST; } 1.208 + void setInLiveList(bool value) { 1.209 + setFlags(value ? (flags() | IN_LIVE_LIST) : (flags() & ~IN_LIVE_LIST)); 1.210 + } 1.211 + 1.212 + bool ownsData() const { return flags() & OWNS_DATA; } 1.213 + void setOwnsData(OwnsState owns) { 1.214 + setFlags(owns ? (flags() | OWNS_DATA) : (flags() & ~OWNS_DATA)); 1.215 + } 1.216 + 1.217 + void setIsAsmJSArrayBuffer() { setFlags(flags() | ASMJS_BUFFER); } 1.218 + void setIsSharedArrayBuffer() { setFlags(flags() | SHARED_BUFFER); } 1.219 + void setIsMappedArrayBuffer() { setFlags(flags() | MAPPED_BUFFER); } 1.220 + void setIsNeutered() { setFlags(flags() | NEUTERED_BUFFER); } 1.221 + 1.222 + void initialize(size_t byteLength, void *data, OwnsState ownsState) { 1.223 + setByteLength(byteLength); 1.224 + setFlags(0); 1.225 + setViewListNoBarrier(nullptr); 1.226 + setDataPointer(data, ownsState); 1.227 + } 1.228 + 1.229 + void releaseAsmJSArray(FreeOp *fop); 1.230 + void releaseMappedArray(); 1.231 +}; 1.232 + 1.233 +/* 1.234 + * ArrayBufferViewObject 1.235 + * 1.236 + * Common definitions shared by all ArrayBufferViews. 1.237 + */ 1.238 + 1.239 +class ArrayBufferViewObject : public JSObject 1.240 +{ 1.241 + protected: 1.242 + /* Offset of view in underlying ArrayBufferObject */ 1.243 + static const size_t BYTEOFFSET_SLOT = JS_TYPEDOBJ_SLOT_BYTEOFFSET; 1.244 + 1.245 + /* Byte length of view */ 1.246 + static const size_t BYTELENGTH_SLOT = JS_TYPEDOBJ_SLOT_BYTELENGTH; 1.247 + 1.248 + /* Underlying ArrayBufferObject */ 1.249 + static const size_t BUFFER_SLOT = JS_TYPEDOBJ_SLOT_OWNER; 1.250 + 1.251 + /* ArrayBufferObjects point to a linked list of views, chained through this slot */ 1.252 + static const size_t NEXT_VIEW_SLOT = JS_TYPEDOBJ_SLOT_NEXT_VIEW; 1.253 + 1.254 + public: 1.255 + static ArrayBufferObject *bufferObject(JSContext *cx, Handle<ArrayBufferViewObject *> obj); 1.256 + 1.257 + ArrayBufferViewObject *nextView() const { 1.258 + return static_cast<ArrayBufferViewObject*>(getFixedSlot(NEXT_VIEW_SLOT).toPrivate()); 1.259 + } 1.260 + 1.261 + inline void setNextView(ArrayBufferViewObject *view); 1.262 + 1.263 + void neuter(void *newData); 1.264 + 1.265 + static void trace(JSTracer *trc, JSObject *obj); 1.266 + 1.267 + uint8_t *dataPointer() { 1.268 + return static_cast<uint8_t *>(getPrivate()); 1.269 + } 1.270 +}; 1.271 + 1.272 +bool 1.273 +ToClampedIndex(JSContext *cx, HandleValue v, uint32_t length, uint32_t *out); 1.274 + 1.275 +inline void 1.276 +PostBarrierTypedArrayObject(JSObject *obj) 1.277 +{ 1.278 +#ifdef JSGC_GENERATIONAL 1.279 + JS_ASSERT(obj); 1.280 + JSRuntime *rt = obj->runtimeFromMainThread(); 1.281 + if (!rt->isHeapBusy() && !IsInsideNursery(rt, obj)) 1.282 + rt->gcStoreBuffer.putWholeCell(obj); 1.283 +#endif 1.284 +} 1.285 + 1.286 +inline void 1.287 +InitArrayBufferViewDataPointer(ArrayBufferViewObject *obj, ArrayBufferObject *buffer, size_t byteOffset) 1.288 +{ 1.289 + /* 1.290 + * N.B. The base of the array's data is stored in the object's 1.291 + * private data rather than a slot to avoid alignment restrictions 1.292 + * on private Values. 1.293 + */ 1.294 + MOZ_ASSERT(buffer->dataPointer() != nullptr); 1.295 + obj->initPrivate(buffer->dataPointer() + byteOffset); 1.296 + 1.297 + PostBarrierTypedArrayObject(obj); 1.298 +} 1.299 + 1.300 +/* 1.301 + * Tests for either ArrayBufferObject or SharedArrayBufferObject. 1.302 + * For specific class testing, use e.g., obj->is<ArrayBufferObject>(). 1.303 + */ 1.304 +bool IsArrayBuffer(HandleValue v); 1.305 +bool IsArrayBuffer(HandleObject obj); 1.306 +bool IsArrayBuffer(JSObject *obj); 1.307 +ArrayBufferObject &AsArrayBuffer(HandleObject obj); 1.308 +ArrayBufferObject &AsArrayBuffer(JSObject *obj); 1.309 + 1.310 +inline void 1.311 +ArrayBufferViewObject::setNextView(ArrayBufferViewObject *view) 1.312 +{ 1.313 + setFixedSlot(NEXT_VIEW_SLOT, PrivateValue(view)); 1.314 + PostBarrierTypedArrayObject(this); 1.315 +} 1.316 + 1.317 +extern uint32_t JS_FASTCALL 1.318 +ClampDoubleToUint8(const double x); 1.319 + 1.320 +struct uint8_clamped { 1.321 + uint8_t val; 1.322 + 1.323 + uint8_clamped() { } 1.324 + uint8_clamped(const uint8_clamped& other) : val(other.val) { } 1.325 + 1.326 + // invoke our assignment helpers for constructor conversion 1.327 + uint8_clamped(uint8_t x) { *this = x; } 1.328 + uint8_clamped(uint16_t x) { *this = x; } 1.329 + uint8_clamped(uint32_t x) { *this = x; } 1.330 + uint8_clamped(int8_t x) { *this = x; } 1.331 + uint8_clamped(int16_t x) { *this = x; } 1.332 + uint8_clamped(int32_t x) { *this = x; } 1.333 + uint8_clamped(double x) { *this = x; } 1.334 + 1.335 + uint8_clamped& operator=(const uint8_clamped& x) { 1.336 + val = x.val; 1.337 + return *this; 1.338 + } 1.339 + 1.340 + uint8_clamped& operator=(uint8_t x) { 1.341 + val = x; 1.342 + return *this; 1.343 + } 1.344 + 1.345 + uint8_clamped& operator=(uint16_t x) { 1.346 + val = (x > 255) ? 255 : uint8_t(x); 1.347 + return *this; 1.348 + } 1.349 + 1.350 + uint8_clamped& operator=(uint32_t x) { 1.351 + val = (x > 255) ? 255 : uint8_t(x); 1.352 + return *this; 1.353 + } 1.354 + 1.355 + uint8_clamped& operator=(int8_t x) { 1.356 + val = (x >= 0) ? uint8_t(x) : 0; 1.357 + return *this; 1.358 + } 1.359 + 1.360 + uint8_clamped& operator=(int16_t x) { 1.361 + val = (x >= 0) 1.362 + ? ((x < 255) 1.363 + ? uint8_t(x) 1.364 + : 255) 1.365 + : 0; 1.366 + return *this; 1.367 + } 1.368 + 1.369 + uint8_clamped& operator=(int32_t x) { 1.370 + val = (x >= 0) 1.371 + ? ((x < 255) 1.372 + ? uint8_t(x) 1.373 + : 255) 1.374 + : 0; 1.375 + return *this; 1.376 + } 1.377 + 1.378 + uint8_clamped& operator=(const double x) { 1.379 + val = uint8_t(ClampDoubleToUint8(x)); 1.380 + return *this; 1.381 + } 1.382 + 1.383 + operator uint8_t() const { 1.384 + return val; 1.385 + } 1.386 + 1.387 + void staticAsserts() { 1.388 + static_assert(sizeof(uint8_clamped) == 1, 1.389 + "uint8_clamped must be layout-compatible with uint8_t"); 1.390 + } 1.391 +}; 1.392 + 1.393 +/* Note that we can't use std::numeric_limits here due to uint8_clamped. */ 1.394 +template<typename T> inline const bool TypeIsFloatingPoint() { return false; } 1.395 +template<> inline const bool TypeIsFloatingPoint<float>() { return true; } 1.396 +template<> inline const bool TypeIsFloatingPoint<double>() { return true; } 1.397 + 1.398 +template<typename T> inline const bool TypeIsUnsigned() { return false; } 1.399 +template<> inline const bool TypeIsUnsigned<uint8_t>() { return true; } 1.400 +template<> inline const bool TypeIsUnsigned<uint16_t>() { return true; } 1.401 +template<> inline const bool TypeIsUnsigned<uint32_t>() { return true; } 1.402 + 1.403 +} // namespace js 1.404 + 1.405 +#endif // vm_ArrayBufferObject_h