Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef vm_TypedArrayObject_h
8 #define vm_TypedArrayObject_h
10 #include "jsobj.h"
12 #include "builtin/TypedObject.h"
13 #include "gc/Barrier.h"
14 #include "js/Class.h"
15 #include "vm/ArrayBufferObject.h"
17 typedef struct JSProperty JSProperty;
19 namespace js {
21 /*
22 * TypedArrayObject
23 *
24 * The non-templated base class for the specific typed implementations.
25 * This class holds all the member variables that are used by
26 * the subclasses.
27 */
29 class TypedArrayObject : public ArrayBufferViewObject
30 {
31 protected:
32 // Typed array properties stored in slots, beyond those shared by all
33 // ArrayBufferViews.
34 static const size_t LENGTH_SLOT = JS_TYPEDOBJ_SLOT_LENGTH;
35 static const size_t TYPE_SLOT = JS_TYPEDOBJ_SLOT_TYPE_DESCR;
36 static const size_t RESERVED_SLOTS = JS_TYPEDOBJ_SLOTS;
37 static const size_t DATA_SLOT = JS_TYPEDOBJ_SLOT_DATA;
39 static_assert(js::detail::TypedArrayLengthSlot == LENGTH_SLOT,
40 "bad inlined constant in jsfriendapi.h");
42 public:
43 static const Class classes[ScalarTypeDescr::TYPE_MAX];
44 static const Class protoClasses[ScalarTypeDescr::TYPE_MAX];
46 static const size_t FIXED_DATA_START = DATA_SLOT + 1;
48 // For typed arrays which can store their data inline, the array buffer
49 // object is created lazily.
50 static const uint32_t INLINE_BUFFER_LIMIT =
51 (JSObject::MAX_FIXED_SLOTS - FIXED_DATA_START) * sizeof(Value);
53 static gc::AllocKind
54 AllocKindForLazyBuffer(size_t nbytes)
55 {
56 JS_ASSERT(nbytes <= INLINE_BUFFER_LIMIT);
57 /* For GGC we need at least one slot in which to store a forwarding pointer. */
58 size_t dataSlots = Max(size_t(1), AlignBytes(nbytes, sizeof(Value)) / sizeof(Value));
59 JS_ASSERT(nbytes <= dataSlots * sizeof(Value));
60 return gc::GetGCObjectKind(FIXED_DATA_START + dataSlots);
61 }
63 static Value bufferValue(TypedArrayObject *tarr) {
64 return tarr->getFixedSlot(BUFFER_SLOT);
65 }
66 static Value byteOffsetValue(TypedArrayObject *tarr) {
67 return tarr->getFixedSlot(BYTEOFFSET_SLOT);
68 }
69 static Value byteLengthValue(TypedArrayObject *tarr) {
70 return tarr->getFixedSlot(BYTELENGTH_SLOT);
71 }
72 static Value lengthValue(TypedArrayObject *tarr) {
73 return tarr->getFixedSlot(LENGTH_SLOT);
74 }
76 static bool
77 ensureHasBuffer(JSContext *cx, Handle<TypedArrayObject *> tarray);
79 ArrayBufferObject *sharedBuffer() const;
80 ArrayBufferObject *buffer() const {
81 JSObject *obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
82 if (!obj)
83 return nullptr;
84 if (obj->is<ArrayBufferObject>())
85 return &obj->as<ArrayBufferObject>();
86 return sharedBuffer();
87 }
88 uint32_t byteOffset() const {
89 return byteOffsetValue(const_cast<TypedArrayObject*>(this)).toInt32();
90 }
91 uint32_t byteLength() const {
92 return byteLengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
93 }
94 uint32_t length() const {
95 return lengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
96 }
98 uint32_t type() const {
99 return getFixedSlot(TYPE_SLOT).toInt32();
100 }
101 void *viewData() const {
102 // Keep synced with js::Get<Type>ArrayLengthAndData in jsfriendapi.h!
103 return static_cast<void*>(getPrivate(DATA_SLOT));
104 }
106 Value getElement(uint32_t index);
107 static void setElement(TypedArrayObject &obj, uint32_t index, double d);
109 void neuter(void *newData);
111 static uint32_t slotWidth(int atype) {
112 switch (atype) {
113 case ScalarTypeDescr::TYPE_INT8:
114 case ScalarTypeDescr::TYPE_UINT8:
115 case ScalarTypeDescr::TYPE_UINT8_CLAMPED:
116 return 1;
117 case ScalarTypeDescr::TYPE_INT16:
118 case ScalarTypeDescr::TYPE_UINT16:
119 return 2;
120 case ScalarTypeDescr::TYPE_INT32:
121 case ScalarTypeDescr::TYPE_UINT32:
122 case ScalarTypeDescr::TYPE_FLOAT32:
123 return 4;
124 case ScalarTypeDescr::TYPE_FLOAT64:
125 return 8;
126 default:
127 MOZ_ASSUME_UNREACHABLE("invalid typed array type");
128 }
129 }
131 int slotWidth() {
132 return slotWidth(type());
133 }
135 /*
136 * Byte length above which created typed arrays and data views will have
137 * singleton types regardless of the context in which they are created.
138 */
139 static const uint32_t SINGLETON_TYPE_BYTE_LENGTH = 1024 * 1024 * 10;
141 static int lengthOffset();
142 static int dataOffset();
143 };
145 inline bool
146 IsTypedArrayClass(const Class *clasp)
147 {
148 return &TypedArrayObject::classes[0] <= clasp &&
149 clasp < &TypedArrayObject::classes[ScalarTypeDescr::TYPE_MAX];
150 }
152 inline bool
153 IsTypedArrayProtoClass(const Class *clasp)
154 {
155 return &TypedArrayObject::protoClasses[0] <= clasp &&
156 clasp < &TypedArrayObject::protoClasses[ScalarTypeDescr::TYPE_MAX];
157 }
159 bool
160 IsTypedArrayConstructor(HandleValue v, uint32_t type);
162 bool
163 IsTypedArrayBuffer(HandleValue v);
165 ArrayBufferObject &
166 AsTypedArrayBuffer(HandleValue v);
168 // Return value is whether the string is some integer. If the string is an
169 // integer which is not representable as a uint64_t, the return value is true
170 // and the resulting index is UINT64_MAX.
171 bool
172 StringIsTypedArrayIndex(JSLinearString *str, uint64_t *indexp);
174 inline bool
175 IsTypedArrayIndex(jsid id, uint64_t *indexp)
176 {
177 if (JSID_IS_INT(id)) {
178 int32_t i = JSID_TO_INT(id);
179 JS_ASSERT(i >= 0);
180 *indexp = (double)i;
181 return true;
182 }
184 if (MOZ_UNLIKELY(!JSID_IS_STRING(id)))
185 return false;
187 JSAtom *atom = JSID_TO_ATOM(id);
189 jschar c = atom->chars()[0];
190 if (!JS7_ISDEC(c) && c != '-')
191 return false;
193 return StringIsTypedArrayIndex(atom, indexp);
194 }
196 static inline unsigned
197 TypedArrayShift(ArrayBufferView::ViewType viewType)
198 {
199 switch (viewType) {
200 case ArrayBufferView::TYPE_INT8:
201 case ArrayBufferView::TYPE_UINT8:
202 case ArrayBufferView::TYPE_UINT8_CLAMPED:
203 return 0;
204 case ArrayBufferView::TYPE_INT16:
205 case ArrayBufferView::TYPE_UINT16:
206 return 1;
207 case ArrayBufferView::TYPE_INT32:
208 case ArrayBufferView::TYPE_UINT32:
209 case ArrayBufferView::TYPE_FLOAT32:
210 return 2;
211 case ArrayBufferView::TYPE_FLOAT64:
212 return 3;
213 default:;
214 }
215 MOZ_ASSUME_UNREACHABLE("Unexpected array type");
216 }
218 class DataViewObject : public ArrayBufferViewObject
219 {
220 static const size_t RESERVED_SLOTS = JS_DATAVIEW_SLOTS;
221 static const size_t DATA_SLOT = JS_TYPEDOBJ_SLOT_DATA;
223 private:
224 static const Class protoClass;
226 static bool is(HandleValue v) {
227 return v.isObject() && v.toObject().hasClass(&class_);
228 }
230 template <typename NativeType>
231 static uint8_t *
232 getDataPointer(JSContext *cx, Handle<DataViewObject*> obj, uint32_t offset);
234 template<Value ValueGetter(DataViewObject *view)>
235 static bool
236 getterImpl(JSContext *cx, CallArgs args);
238 template<Value ValueGetter(DataViewObject *view)>
239 static bool
240 getter(JSContext *cx, unsigned argc, Value *vp);
242 template<Value ValueGetter(DataViewObject *view)>
243 static bool
244 defineGetter(JSContext *cx, PropertyName *name, HandleObject proto);
246 public:
247 static const Class class_;
249 static Value byteOffsetValue(DataViewObject *view) {
250 Value v = view->getReservedSlot(BYTEOFFSET_SLOT);
251 JS_ASSERT(v.toInt32() >= 0);
252 return v;
253 }
255 static Value byteLengthValue(DataViewObject *view) {
256 Value v = view->getReservedSlot(BYTELENGTH_SLOT);
257 JS_ASSERT(v.toInt32() >= 0);
258 return v;
259 }
261 static Value bufferValue(DataViewObject *view) {
262 return view->getReservedSlot(BUFFER_SLOT);
263 }
265 uint32_t byteOffset() const {
266 return byteOffsetValue(const_cast<DataViewObject*>(this)).toInt32();
267 }
269 uint32_t byteLength() const {
270 return byteLengthValue(const_cast<DataViewObject*>(this)).toInt32();
271 }
273 ArrayBufferObject &arrayBuffer() const {
274 return bufferValue(const_cast<DataViewObject*>(this)).toObject().as<ArrayBufferObject>();
275 }
277 void *dataPointer() const {
278 return getPrivate();
279 }
281 static bool class_constructor(JSContext *cx, unsigned argc, Value *vp);
282 static bool constructWithProto(JSContext *cx, unsigned argc, Value *vp);
283 static bool construct(JSContext *cx, JSObject *bufobj, const CallArgs &args,
284 HandleObject proto);
286 static inline DataViewObject *
287 create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
288 Handle<ArrayBufferObject*> arrayBuffer, JSObject *proto);
290 static bool getInt8Impl(JSContext *cx, CallArgs args);
291 static bool fun_getInt8(JSContext *cx, unsigned argc, Value *vp);
293 static bool getUint8Impl(JSContext *cx, CallArgs args);
294 static bool fun_getUint8(JSContext *cx, unsigned argc, Value *vp);
296 static bool getInt16Impl(JSContext *cx, CallArgs args);
297 static bool fun_getInt16(JSContext *cx, unsigned argc, Value *vp);
299 static bool getUint16Impl(JSContext *cx, CallArgs args);
300 static bool fun_getUint16(JSContext *cx, unsigned argc, Value *vp);
302 static bool getInt32Impl(JSContext *cx, CallArgs args);
303 static bool fun_getInt32(JSContext *cx, unsigned argc, Value *vp);
305 static bool getUint32Impl(JSContext *cx, CallArgs args);
306 static bool fun_getUint32(JSContext *cx, unsigned argc, Value *vp);
308 static bool getFloat32Impl(JSContext *cx, CallArgs args);
309 static bool fun_getFloat32(JSContext *cx, unsigned argc, Value *vp);
311 static bool getFloat64Impl(JSContext *cx, CallArgs args);
312 static bool fun_getFloat64(JSContext *cx, unsigned argc, Value *vp);
314 static bool setInt8Impl(JSContext *cx, CallArgs args);
315 static bool fun_setInt8(JSContext *cx, unsigned argc, Value *vp);
317 static bool setUint8Impl(JSContext *cx, CallArgs args);
318 static bool fun_setUint8(JSContext *cx, unsigned argc, Value *vp);
320 static bool setInt16Impl(JSContext *cx, CallArgs args);
321 static bool fun_setInt16(JSContext *cx, unsigned argc, Value *vp);
323 static bool setUint16Impl(JSContext *cx, CallArgs args);
324 static bool fun_setUint16(JSContext *cx, unsigned argc, Value *vp);
326 static bool setInt32Impl(JSContext *cx, CallArgs args);
327 static bool fun_setInt32(JSContext *cx, unsigned argc, Value *vp);
329 static bool setUint32Impl(JSContext *cx, CallArgs args);
330 static bool fun_setUint32(JSContext *cx, unsigned argc, Value *vp);
332 static bool setFloat32Impl(JSContext *cx, CallArgs args);
333 static bool fun_setFloat32(JSContext *cx, unsigned argc, Value *vp);
335 static bool setFloat64Impl(JSContext *cx, CallArgs args);
336 static bool fun_setFloat64(JSContext *cx, unsigned argc, Value *vp);
338 static bool initClass(JSContext *cx);
339 static void neuter(JSObject *view);
340 template<typename NativeType>
341 static bool read(JSContext *cx, Handle<DataViewObject*> obj,
342 CallArgs &args, NativeType *val, const char *method);
343 template<typename NativeType>
344 static bool write(JSContext *cx, Handle<DataViewObject*> obj,
345 CallArgs &args, const char *method);
347 void neuter(void *newData);
349 private:
350 static const JSFunctionSpec jsfuncs[];
351 };
353 static inline int32_t
354 ClampIntForUint8Array(int32_t x)
355 {
356 if (x < 0)
357 return 0;
358 if (x > 255)
359 return 255;
360 return x;
361 }
363 } // namespace js
365 template <>
366 inline bool
367 JSObject::is<js::TypedArrayObject>() const
368 {
369 return js::IsTypedArrayClass(getClass());
370 }
372 template <>
373 inline bool
374 JSObject::is<js::ArrayBufferViewObject>() const
375 {
376 return is<js::DataViewObject>() || is<js::TypedArrayObject>() ||
377 IsTypedObjectClass(getClass());
378 }
380 #endif /* vm_TypedArrayObject_h */