summaryrefslogtreecommitdiff
path: root/js/src/jstypedarray.h
blob: f666e5220431855d663ee3027bcd0d544ead0337 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=8 sts=4 et sw=4 tw=99:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef jstypedarray_h
#define jstypedarray_h

#include "jsapi.h"
#include "jsclass.h"
#include "jsobj.h"

#include "gc/Barrier.h"

typedef struct JSProperty JSProperty;

namespace js {

typedef Vector<ArrayBufferObject *, 0, SystemAllocPolicy> ArrayBufferVector;

/*
 * ArrayBufferObject
 *
 * This class holds the underlying raw buffer that the various ArrayBufferView
 * subclasses (DataView and the TypedArrays) access. It can be created
 * explicitly and passed to an ArrayBufferView subclass, or can be created
 * implicitly by constructing a TypedArray with a size.
 */
class ArrayBufferObject : public JSObject
{
    static bool byteLengthGetterImpl(JSContext *cx, CallArgs args);
    static bool fun_slice_impl(JSContext *cx, CallArgs args);

  public:
    static Class class_;

    static Class protoClass;
    static const JSFunctionSpec jsfuncs[];

    static JSBool byteLengthGetter(JSContext *cx, unsigned argc, Value *vp);

    static JSBool fun_slice(JSContext *cx, unsigned argc, Value *vp);

    static JSBool class_constructor(JSContext *cx, unsigned argc, Value *vp);

    static JSObject *create(JSContext *cx, uint32_t nbytes, uint8_t *contents = NULL);

    static JSObject *createSlice(JSContext *cx, ArrayBufferObject &arrayBuffer,
                                 uint32_t begin, uint32_t end);

    static bool createDataViewForThisImpl(JSContext *cx, CallArgs args);
    static JSBool createDataViewForThis(JSContext *cx, unsigned argc, Value *vp);

    template<typename T>
    static bool createTypedArrayFromBufferImpl(JSContext *cx, CallArgs args);

    template<typename T>
    static JSBool createTypedArrayFromBuffer(JSContext *cx, unsigned argc, Value *vp);

    static void obj_trace(JSTracer *trc, JSObject *obj);

    static JSBool obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
                                    MutableHandleObject objp, MutableHandleShape propp);
    static JSBool obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                     MutableHandleObject objp, MutableHandleShape propp);
    static JSBool obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
                                    MutableHandleObject objp, MutableHandleShape propp);
    static JSBool obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
                                    MutableHandleObject objp, MutableHandleShape propp);

    static JSBool obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
                                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
    static JSBool obj_defineProperty(JSContext *cx, HandleObject obj,
                                     HandlePropertyName name, HandleValue v,
                                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
    static JSBool obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
                                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
    static JSBool obj_defineSpecial(JSContext *cx, HandleObject obj,
                                    HandleSpecialId sid, HandleValue v,
                                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs);

    static JSBool obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
                                 HandleId id, MutableHandleValue vp);

    static JSBool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
                                  HandlePropertyName name, MutableHandleValue vp);

    static JSBool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
                                 uint32_t index, MutableHandleValue vp);
    static JSBool obj_getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
                                          uint32_t index, MutableHandleValue vp, bool *present);

    static JSBool obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver,
                                 HandleSpecialId sid, MutableHandleValue vp);

    static JSBool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
                                 MutableHandleValue vp, JSBool strict);
    static JSBool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                  MutableHandleValue vp, JSBool strict);
    static JSBool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
                                 MutableHandleValue vp, JSBool strict);
    static JSBool obj_setSpecial(JSContext *cx, HandleObject obj,
                                 HandleSpecialId sid, MutableHandleValue vp, JSBool strict);

    static JSBool obj_getGenericAttributes(JSContext *cx, HandleObject obj,
                                           HandleId id, unsigned *attrsp);
    static JSBool obj_getPropertyAttributes(JSContext *cx, HandleObject obj,
                                            HandlePropertyName name, unsigned *attrsp);
    static JSBool obj_getElementAttributes(JSContext *cx, HandleObject obj,
                                           uint32_t index, unsigned *attrsp);
    static JSBool obj_getSpecialAttributes(JSContext *cx, HandleObject obj,
                                           HandleSpecialId sid, unsigned *attrsp);

    static JSBool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
                                           HandleId id, unsigned *attrsp);
    static JSBool obj_setPropertyAttributes(JSContext *cx, HandleObject obj,
                                            HandlePropertyName name, unsigned *attrsp);
    static JSBool obj_setElementAttributes(JSContext *cx, HandleObject obj,
                                           uint32_t index, unsigned *attrsp);
    static JSBool obj_setSpecialAttributes(JSContext *cx, HandleObject obj,
                                           HandleSpecialId sid, unsigned *attrsp);

    static JSBool obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                     JSBool *succeeded);
    static JSBool obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
                                    JSBool *succeeded);
    static JSBool obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
                                    JSBool *succeeded);

    static JSBool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
                                MutableHandleValue statep, MutableHandleId idp);

    static void sweep(JSCompartment *rt);

    static void resetArrayBufferList(JSCompartment *rt);
    static bool saveArrayBufferList(JSCompartment *c, ArrayBufferVector &vector);
    static void restoreArrayBufferLists(ArrayBufferVector &vector);

    static bool stealContents(JSContext *cx, JSObject *obj, void **contents,
                              uint8_t **data);

    static inline void setElementsHeader(js::ObjectElements *header, uint32_t bytes);
    static inline uint32_t getElementsHeaderInitializedLength(const js::ObjectElements *header);

    void addView(JSObject *view);

    bool allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents = NULL);
    void changeContents(JSContext *cx, ObjectElements *newHeader);

    /*
     * Ensure that the data is not stored inline. Used when handing back a
     * GC-safe pointer.
     */
    bool uninlineData(JSContext *cx);

    inline uint32_t byteLength() const;

    inline uint8_t * dataPointer() const;

   /*
     * Check if the arrayBuffer contains any data. This will return false for
     * ArrayBuffer.prototype and neutered ArrayBuffers.
     */
    inline bool hasData() const;

    inline bool isAsmJSArrayBuffer() const;
    static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer);
    static void neuterAsmJSArrayBuffer(ArrayBufferObject &buffer);
    static void releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj);
};

/*
 * BufferView
 *
 * Common definitions shared by all ArrayBufferViews. (The name ArrayBufferView
 * is currently being used for a namespace in jsfriendapi.h.)
 */

struct BufferView {
    /* Offset of view in underlying ArrayBuffer */
    static const size_t BYTEOFFSET_SLOT  = 0;

    /* Byte length of view */
    static const size_t BYTELENGTH_SLOT  = 1;

    /* Underlying ArrayBuffer */
    static const size_t BUFFER_SLOT      = 2;

    /* ArrayBuffers point to a linked list of views, chained through this slot */
    static const size_t NEXT_VIEW_SLOT   = 3;

    /*
     * When ArrayBuffers are traced during GC, they construct a linked list of
     * ArrayBuffers with more than one view, chained through this slot of the
     * first view of each ArrayBuffer
     */
    static const size_t NEXT_BUFFER_SLOT = 4;

    static const size_t NUM_SLOTS        = 5;
};

/*
 * TypedArray
 *
 * The non-templated base class for the specific typed implementations.
 * This class holds all the member variables that are used by
 * the subclasses.
 */

struct TypedArray : public BufferView {
    enum {
        TYPE_INT8 = 0,
        TYPE_UINT8,
        TYPE_INT16,
        TYPE_UINT16,
        TYPE_INT32,
        TYPE_UINT32,
        TYPE_FLOAT32,
        TYPE_FLOAT64,

        /*
         * Special type that's a uint8_t, but assignments are clamped to 0 .. 255.
         * Treat the raw data type as a uint8_t.
         */
        TYPE_UINT8_CLAMPED,

        TYPE_MAX
    };

    /*
     * Typed array properties stored in slots, beyond those shared by all
     * ArrayBufferViews.
     */
    static const size_t LENGTH_SLOT     = BufferView::NUM_SLOTS;
    static const size_t TYPE_SLOT       = BufferView::NUM_SLOTS + 1;
    static const size_t RESERVED_SLOTS  = BufferView::NUM_SLOTS + 2;
    static const size_t DATA_SLOT       = 7; // private slot, based on alloc kind

    static Class classes[TYPE_MAX];
    static Class protoClasses[TYPE_MAX];

    static JSBool obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
                                    MutableHandleObject objp, MutableHandleShape propp);
    static JSBool obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                     MutableHandleObject objp, MutableHandleShape propp);
    static JSBool obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
                                    MutableHandleObject objp, MutableHandleShape propp);
    static JSBool obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
                                    MutableHandleObject objp, MutableHandleShape propp);

    static JSBool obj_getGenericAttributes(JSContext *cx, HandleObject obj,
                                           HandleId id, unsigned *attrsp);
    static JSBool obj_getPropertyAttributes(JSContext *cx, HandleObject obj,
                                            HandlePropertyName name, unsigned *attrsp);
    static JSBool obj_getElementAttributes(JSContext *cx, HandleObject obj,
                                           uint32_t index, unsigned *attrsp);
    static JSBool obj_getSpecialAttributes(JSContext *cx, HandleObject obj,
                                           HandleSpecialId sid, unsigned *attrsp);

    static JSBool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
                                           HandleId id, unsigned *attrsp);
    static JSBool obj_setPropertyAttributes(JSContext *cx, HandleObject obj,
                                            HandlePropertyName name, unsigned *attrsp);
    static JSBool obj_setElementAttributes(JSContext *cx, HandleObject obj,
                                           uint32_t index, unsigned *attrsp);
    static JSBool obj_setSpecialAttributes(JSContext *cx, HandleObject obj,
                                           HandleSpecialId sid, unsigned *attrsp);

    static inline Value bufferValue(JSObject *obj);
    static inline Value byteOffsetValue(JSObject *obj);
    static inline Value byteLengthValue(JSObject *obj);
    static inline Value lengthValue(JSObject *obj);

    static inline ArrayBufferObject * buffer(JSObject *obj);
    static inline uint32_t byteOffset(JSObject *obj);
    static inline uint32_t byteLength(JSObject *obj);
    static inline uint32_t length(JSObject *obj);

    static inline uint32_t type(JSObject *obj);
    static inline void * viewData(JSObject *obj);

  public:
    static bool isArrayIndex(JSObject *obj, jsid id, uint32_t *ip = NULL);

    static void neuter(JSObject *tarray);

    static inline uint32_t slotWidth(int atype);
    static inline int slotWidth(JSObject *obj);

    /*
     * Byte length above which created typed arrays and data views will have
     * singleton types regardless of the context in which they are created.
     */
    static const uint32_t SINGLETON_TYPE_BYTE_LENGTH = 1024 * 1024 * 10;

    static int lengthOffset();
    static int dataOffset();
};

inline bool
IsTypedArrayClass(const Class *clasp)
{
    return &TypedArray::classes[0] <= clasp &&
           clasp < &TypedArray::classes[TypedArray::TYPE_MAX];
}

inline bool
IsTypedArrayProtoClass(const Class *clasp)
{
    return &TypedArray::protoClasses[0] <= clasp &&
           clasp < &TypedArray::protoClasses[TypedArray::TYPE_MAX];
}

bool
IsTypedArrayConstructor(const Value &v, uint32_t type);

bool
IsTypedArrayBuffer(const Value &v);

static inline unsigned
TypedArrayShift(ArrayBufferView::ViewType viewType)
{
    switch (viewType) {
      case ArrayBufferView::TYPE_INT8:
      case ArrayBufferView::TYPE_UINT8:
      case ArrayBufferView::TYPE_UINT8_CLAMPED:
        return 0;
      case ArrayBufferView::TYPE_INT16:
      case ArrayBufferView::TYPE_UINT16:
        return 1;
      case ArrayBufferView::TYPE_INT32:
      case ArrayBufferView::TYPE_UINT32:
      case ArrayBufferView::TYPE_FLOAT32:
        return 2;
      case ArrayBufferView::TYPE_FLOAT64:
        return 3;
      default:;
    }
    JS_NOT_REACHED("Unexpected array type");
    return 0;
}

class DataViewObject : public JSObject, public BufferView
{
public:
    static Class class_;

private:
    static Class protoClass;

    static inline bool is(const Value &v);

    template<Value ValueGetter(DataViewObject &view)>
    static bool
    getterImpl(JSContext *cx, CallArgs args);

    template<Value ValueGetter(DataViewObject &view)>
    static JSBool
    getter(JSContext *cx, unsigned argc, Value *vp);

    template<Value ValueGetter(DataViewObject &view)>
    static bool
    defineGetter(JSContext *cx, PropertyName *name, HandleObject proto);

  public:
    static const size_t RESERVED_SLOTS = BufferView::NUM_SLOTS;
    static const size_t DATA_SLOT       = 7; // private slot, based on alloc kind

    static inline Value bufferValue(DataViewObject &view);
    static inline Value byteOffsetValue(DataViewObject &view);
    static inline Value byteLengthValue(DataViewObject &view);

    static JSBool class_constructor(JSContext *cx, unsigned argc, Value *vp);
    static JSBool constructWithProto(JSContext *cx, unsigned argc, Value *vp);
    static JSBool construct(JSContext *cx, JSObject *bufobj, const CallArgs &args,
                            HandleObject proto);

    static inline DataViewObject *
    create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
           Handle<ArrayBufferObject*> arrayBuffer, JSObject *proto);

    static bool getInt8Impl(JSContext *cx, CallArgs args);
    static JSBool fun_getInt8(JSContext *cx, unsigned argc, Value *vp);

    static bool getUint8Impl(JSContext *cx, CallArgs args);
    static JSBool fun_getUint8(JSContext *cx, unsigned argc, Value *vp);

    static bool getInt16Impl(JSContext *cx, CallArgs args);
    static JSBool fun_getInt16(JSContext *cx, unsigned argc, Value *vp);

    static bool getUint16Impl(JSContext *cx, CallArgs args);
    static JSBool fun_getUint16(JSContext *cx, unsigned argc, Value *vp);

    static bool getInt32Impl(JSContext *cx, CallArgs args);
    static JSBool fun_getInt32(JSContext *cx, unsigned argc, Value *vp);

    static bool getUint32Impl(JSContext *cx, CallArgs args);
    static JSBool fun_getUint32(JSContext *cx, unsigned argc, Value *vp);

    static bool getFloat32Impl(JSContext *cx, CallArgs args);
    static JSBool fun_getFloat32(JSContext *cx, unsigned argc, Value *vp);

    static bool getFloat64Impl(JSContext *cx, CallArgs args);
    static JSBool fun_getFloat64(JSContext *cx, unsigned argc, Value *vp);

    static bool setInt8Impl(JSContext *cx, CallArgs args);
    static JSBool fun_setInt8(JSContext *cx, unsigned argc, Value *vp);

    static bool setUint8Impl(JSContext *cx, CallArgs args);
    static JSBool fun_setUint8(JSContext *cx, unsigned argc, Value *vp);

    static bool setInt16Impl(JSContext *cx, CallArgs args);
    static JSBool fun_setInt16(JSContext *cx, unsigned argc, Value *vp);

    static bool setUint16Impl(JSContext *cx, CallArgs args);
    static JSBool fun_setUint16(JSContext *cx, unsigned argc, Value *vp);

    static bool setInt32Impl(JSContext *cx, CallArgs args);
    static JSBool fun_setInt32(JSContext *cx, unsigned argc, Value *vp);

    static bool setUint32Impl(JSContext *cx, CallArgs args);
    static JSBool fun_setUint32(JSContext *cx, unsigned argc, Value *vp);

    static bool setFloat32Impl(JSContext *cx, CallArgs args);
    static JSBool fun_setFloat32(JSContext *cx, unsigned argc, Value *vp);

    static bool setFloat64Impl(JSContext *cx, CallArgs args);
    static JSBool fun_setFloat64(JSContext *cx, unsigned argc, Value *vp);

    inline uint32_t byteLength();
    inline uint32_t byteOffset();
    inline ArrayBufferObject & arrayBuffer();
    inline void *dataPointer();
    inline bool hasBuffer() const;
    static JSObject *initClass(JSContext *cx);
    static bool getDataPointer(JSContext *cx, Handle<DataViewObject*> obj,
                               CallArgs args, size_t typeSize, uint8_t **data);
    template<typename NativeType>
    static bool read(JSContext *cx, Handle<DataViewObject*> obj,
                     CallArgs &args, NativeType *val, const char *method);
    template<typename NativeType>
    static bool write(JSContext *cx, Handle<DataViewObject*> obj,
                      CallArgs &args, const char *method);
  private:
    static const JSFunctionSpec jsfuncs[];
};

bool
IsDataView(JSObject *obj);

} // namespace js

#endif /* jstypedarray_h */