1 /* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */
2 /* vim: set ts=40 sw=4 et tw=99: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Mozilla WebGL impl
18 * The Initial Developer of the Original Code is
20 * Portions created by the Initial Developer are Copyright (C) 2009
21 * the Initial Developer. All Rights Reserved.
24 * Vladimir Vukicevic <vladimir@pobox.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #define __STDC_LIMIT_MACROS
53 #include "jsbuiltins.h"
55 #include "jsversion.h"
61 #include "jsstaticcheck.h"
64 #include "jstypedarray.h"
66 #include "jsobjinlines.h"
73 * This class holds the underlying raw buffer that the TypedArray classes
74 * access. It can be created explicitly and passed to a TypedArray, or
75 * can be created implicitly by constructing a TypedArray with a size.
78 ArrayBuffer::fromJSObject(JSObject
*obj
)
80 JS_ASSERT(obj
->getClass() == &ArrayBuffer::jsclass
);
81 return reinterpret_cast<ArrayBuffer
*>(obj
->getPrivate());
85 ArrayBuffer::prop_getByteLength(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
87 ArrayBuffer
*abuf
= ArrayBuffer::fromJSObject(obj
);
89 *vp
= INT_TO_JSVAL(jsint(abuf
->byteLength
));
94 ArrayBuffer::class_finalize(JSContext
*cx
, JSObject
*obj
)
96 ArrayBuffer
*abuf
= ArrayBuffer::fromJSObject(obj
);
98 abuf
->freeStorage(cx
);
103 * new ArrayBuffer(byteLength)
106 ArrayBuffer::class_constructor(JSContext
*cx
, JSObject
*obj
,
107 uintN argc
, jsval
*argv
, jsval
*rval
)
109 if (!JS_IsConstructing(cx
)) {
110 obj
= NewObject(cx
, &ArrayBuffer::jsclass
, NULL
, NULL
);
113 *rval
= OBJECT_TO_JSVAL(obj
);
116 return create(cx
, obj
, argc
, argv
, rval
);
120 ArrayBuffer::create(JSContext
*cx
, JSObject
*obj
,
121 uintN argc
, jsval
*argv
, jsval
*rval
)
124 obj
= NewObject(cx
, &ArrayBuffer::jsclass
, NULL
, NULL
);
127 *rval
= OBJECT_TO_JSVAL(obj
);
131 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
132 JSMSG_TYPED_ARRAY_BAD_ARGS
);
137 if (!ValueToECMAInt32(cx
, argv
[0], &nbytes
))
139 if (nbytes
< 0 || !INT_FITS_IN_JSVAL(nbytes
)) {
141 * We're just not going to support arrays that are bigger than what will fit
142 * as an integer jsval; if someone actually ever complains (validly), then we
145 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
146 JSMSG_BAD_ARRAY_LENGTH
);
150 ArrayBuffer
*abuf
= new ArrayBuffer();
152 JS_ReportOutOfMemory(cx
);
156 if (!abuf
->allocateStorage(cx
, nbytes
)) {
161 obj
->setPrivate(abuf
);
166 ArrayBuffer::allocateStorage(JSContext
*cx
, uint32 nbytes
)
168 JS_ASSERT(data
== 0);
171 data
= cx
->calloc(nbytes
);
173 JS_ReportOutOfMemory(cx
);
183 ArrayBuffer::freeStorage(JSContext
*cx
)
188 // the destructor asserts that data is 0 in debug builds
194 ArrayBuffer::~ArrayBuffer()
196 JS_ASSERT(data
== NULL
);
202 * The non-templated base class for the specific typed implementations.
203 * This class holds all the member variables that are used by
208 TypedArray::fromJSObject(JSObject
*obj
)
210 return reinterpret_cast<TypedArray
*>(obj
->getPrivate());
214 TypedArray::isArrayIndex(JSContext
*cx
, jsid id
, jsuint
*ip
)
217 if (js_IdIsIndex(id
, &index
) && index
< length
) {
227 TypedArray::prop_getBuffer(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
229 TypedArray
*tarray
= fromJSObject(obj
);
231 *vp
= OBJECT_TO_JSVAL(tarray
->bufferJS
);
236 TypedArray::prop_getByteOffset(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
238 TypedArray
*tarray
= fromJSObject(obj
);
240 *vp
= INT_TO_JSVAL(tarray
->byteOffset
);
245 TypedArray::prop_getByteLength(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
247 TypedArray
*tarray
= fromJSObject(obj
);
249 *vp
= INT_TO_JSVAL(tarray
->byteLength
);
254 TypedArray::prop_getLength(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
256 TypedArray
*tarray
= fromJSObject(obj
);
258 *vp
= INT_TO_JSVAL(tarray
->length
);
263 TypedArray::obj_lookupProperty(JSContext
*cx
, JSObject
*obj
, jsid id
,
264 JSObject
**objp
, JSProperty
**propp
)
266 TypedArray
*tarray
= fromJSObject(obj
);
269 if (tarray
->isArrayIndex(cx
, id
)) {
270 *propp
= (JSProperty
*) id
;
275 JSObject
*proto
= obj
->getProto();
282 return proto
->lookupProperty(cx
, id
, objp
, propp
);
286 TypedArray::obj_dropProperty(JSContext
*cx
, JSObject
*obj
, JSProperty
*prop
)
289 TypedArray
*tarray
= fromJSObject(obj
);
290 JS_ASSERT_IF(tarray
, tarray
->isArrayIndex(cx
, (jsid
) prop
));
295 TypedArray::obj_trace(JSTracer
*trc
, JSObject
*obj
)
297 TypedArray
*tarray
= fromJSObject(obj
);
300 obj
->traceProtoAndParent(trc
);
302 JS_CALL_OBJECT_TRACER(trc
, tarray
->bufferJS
, "typedarray.buffer");
306 TypedArray::obj_getAttributes(JSContext
*cx
, JSObject
*obj
, jsid id
, JSProperty
*prop
,
309 *attrsp
= (id
== ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
))
310 ? JSPROP_PERMANENT
| JSPROP_READONLY
311 : JSPROP_PERMANENT
| JSPROP_ENUMERATE
;
316 TypedArray::obj_setAttributes(JSContext
*cx
, JSObject
*obj
, jsid id
, JSProperty
*prop
,
319 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
320 JSMSG_CANT_SET_ARRAY_ATTRS
);
324 /* Helper clamped uint8 type */
327 js_TypedArray_uint8_clamp_double(const double x
)
329 // Not < so that NaN coerces to 0
336 jsdouble toTruncate
= x
+ 0.5;
337 JSUint8 y
= JSUint8(toTruncate
);
340 * now val is rounded to nearest, ties rounded up. We want
341 * rounded to nearest ties to even, so check whether we had a
344 if (y
== toTruncate
) {
346 * It was a tie (since adding 0.5 gave us the exact integer
347 * we want). Since we rounded up, we either already have an
348 * even number or we have an odd number but the number we
349 * want is one less. So just unconditionally masking out the
350 * ones bit should do the trick to get us the value we
359 JS_DEFINE_CALLINFO_1(extern, INT32
, js_TypedArray_uint8_clamp_double
, DOUBLE
, 1, nanojit::ACC_NONE
)
362 struct uint8_clamped
{
366 uint8_clamped(const uint8_clamped
& other
) : val(other
.val
) { }
368 // invoke our assignment helpers for constructor conversion
369 uint8_clamped(uint8 x
) { *this = x
; }
370 uint8_clamped(uint16 x
) { *this = x
; }
371 uint8_clamped(uint32 x
) { *this = x
; }
372 uint8_clamped(int8 x
) { *this = x
; }
373 uint8_clamped(int16 x
) { *this = x
; }
374 uint8_clamped(int32 x
) { *this = x
; }
375 uint8_clamped(jsdouble x
) { *this = x
; }
377 inline uint8_clamped
& operator= (const uint8_clamped
& x
) {
382 inline uint8_clamped
& operator= (uint8 x
) {
387 inline uint8_clamped
& operator= (uint16 x
) {
388 val
= (x
> 255) ? 255 : uint8(x
);
392 inline uint8_clamped
& operator= (uint32 x
) {
393 val
= (x
> 255) ? 255 : uint8(x
);
397 inline uint8_clamped
& operator= (int8 x
) {
398 val
= (x
>= 0) ? uint8(x
) : 0;
402 inline uint8_clamped
& operator= (int16 x
) {
411 inline uint8_clamped
& operator= (int32 x
) {
420 inline uint8_clamped
& operator= (const jsdouble x
) {
421 val
= uint8(js_TypedArray_uint8_clamp_double(x
));
425 inline operator uint8() const {
430 /* Make sure the compiler isn't doing some funky stuff */
431 JS_STATIC_ASSERT(sizeof(uint8_clamped
) == 1);
433 template<typename NativeType
> static inline const int TypeIDOfType();
434 template<> inline const int TypeIDOfType
<int8
>() { return TypedArray::TYPE_INT8
; }
435 template<> inline const int TypeIDOfType
<uint8
>() { return TypedArray::TYPE_UINT8
; }
436 template<> inline const int TypeIDOfType
<int16
>() { return TypedArray::TYPE_INT16
; }
437 template<> inline const int TypeIDOfType
<uint16
>() { return TypedArray::TYPE_UINT16
; }
438 template<> inline const int TypeIDOfType
<int32
>() { return TypedArray::TYPE_INT32
; }
439 template<> inline const int TypeIDOfType
<uint32
>() { return TypedArray::TYPE_UINT32
; }
440 template<> inline const int TypeIDOfType
<float>() { return TypedArray::TYPE_FLOAT32
; }
441 template<> inline const int TypeIDOfType
<double>() { return TypedArray::TYPE_FLOAT64
; }
442 template<> inline const int TypeIDOfType
<uint8_clamped
>() { return TypedArray::TYPE_UINT8_CLAMPED
; }
444 template<typename NativeType
> static inline const bool TypeIsUnsigned() { return false; }
445 template<> inline const bool TypeIsUnsigned
<uint8
>() { return true; }
446 template<> inline const bool TypeIsUnsigned
<uint16
>() { return true; }
447 template<> inline const bool TypeIsUnsigned
<uint32
>() { return true; }
449 template<typename NativeType
> static inline const bool TypeIsFloatingPoint() { return false; }
450 template<> inline const bool TypeIsFloatingPoint
<float>() { return true; }
451 template<> inline const bool TypeIsFloatingPoint
<double>() { return true; }
453 template<typename NativeType
> class TypedArrayTemplate
;
455 typedef TypedArrayTemplate
<int8
> Int8Array
;
456 typedef TypedArrayTemplate
<uint8
> Uint8Array
;
457 typedef TypedArrayTemplate
<int16
> Int16Array
;
458 typedef TypedArrayTemplate
<uint16
> Uint16Array
;
459 typedef TypedArrayTemplate
<int32
> Int32Array
;
460 typedef TypedArrayTemplate
<uint32
> Uint32Array
;
461 typedef TypedArrayTemplate
<float> Float32Array
;
462 typedef TypedArrayTemplate
<double> Float64Array
;
463 typedef TypedArrayTemplate
<uint8_clamped
> Uint8ClampedArray
;
465 template<typename NativeType
>
466 class TypedArrayTemplate
470 typedef TypedArrayTemplate
<NativeType
> ThisTypeArray
;
471 static const int ArrayTypeID() { return TypeIDOfType
<NativeType
>(); }
472 static const bool ArrayTypeIsUnsigned() { return TypeIsUnsigned
<NativeType
>(); }
473 static const bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint
<NativeType
>(); }
475 static JSObjectOps fastObjectOps
;
476 static JSObjectMap fastObjectMap
;
478 static JSFunctionSpec jsfuncs
[];
480 static inline JSClass
*slowClass()
482 return &TypedArray::slowClasses
[ArrayTypeID()];
485 static inline JSClass
*fastClass()
487 return &TypedArray::fastClasses
[ArrayTypeID()];
490 static JSObjectOps
*getObjectOps(JSContext
*cx
, JSClass
*clasp
)
492 return &fastObjectOps
;
496 obj_getProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
498 ThisTypeArray
*tarray
= ThisTypeArray::fromJSObject(obj
);
501 if (id
== ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
)) {
502 *vp
= INT_TO_JSVAL(tarray
->length
);
507 if (tarray
->isArrayIndex(cx
, id
, &index
)) {
508 // this inline function is specialized for each type
509 tarray
->copyIndexToValue(cx
, index
, vp
);
513 JSScopeProperty
*sprop
;
515 JSObject
*proto
= obj
->getProto();
522 if (js_LookupPropertyWithFlags(cx
, proto
, id
, cx
->resolveFlags
, &obj2
, &prop
) < 0)
526 if (obj2
->isNative()) {
527 sprop
= (JSScopeProperty
*) prop
;
528 if (!js_NativeGet(cx
, obj
, obj2
, sprop
, JSGET_METHOD_BARRIER
, vp
))
531 obj2
->dropProperty(cx
, prop
);
539 obj_setProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
541 ThisTypeArray
*tarray
= ThisTypeArray::fromJSObject(obj
);
544 if (id
== ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
)) {
545 *vp
= INT_TO_JSVAL(tarray
->length
);
550 // We can't just chain to js_SetProperty, because we're not a normal object.
551 if (!tarray
->isArrayIndex(cx
, id
, &index
)) {
553 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
554 JSMSG_TYPED_ARRAY_BAD_INDEX
);
557 // Silent ignore is better than an exception here, because
558 // at some point we may want to support other properties on
559 // these objects. This is especially true when these arrays
560 // are used to implement HTML Canvas 2D's PixelArray objects,
561 // which used to be plain old arrays.
566 if (JSVAL_IS_INT(*vp
)) {
567 tarray
->setIndex(index
, NativeType(JSVAL_TO_INT(*vp
)));
573 if (JSVAL_IS_DOUBLE(*vp
)) {
574 d
= *JSVAL_TO_DOUBLE(*vp
);
575 } else if (JSVAL_IS_NULL(*vp
)) {
577 } else if (JSVAL_IS_PRIMITIVE(*vp
)) {
578 JS_ASSERT(JSVAL_IS_STRING(*vp
) || JSVAL_IS_SPECIAL(*vp
));
579 if (JSVAL_IS_STRING(*vp
)) {
580 // note that ValueToNumber will always succeed with a string arg
581 ValueToNumber(cx
, *vp
, &d
);
582 } else if (*vp
== JSVAL_VOID
) {
585 d
= (double) JSVAL_TO_BOOLEAN(*vp
);
588 // non-primitive assignments become NaN or 0 (for float/int arrays)
592 // If the array is an integer array, we only handle up to
593 // 32-bit ints from this point on. if we want to handle
594 // 64-bit ints, we'll need some changes.
596 // Assign based on characteristics of the destination type
597 if (ArrayTypeIsFloatingPoint()) {
598 tarray
->setIndex(index
, NativeType(d
));
599 } else if (ArrayTypeIsUnsigned()) {
600 JS_ASSERT(sizeof(NativeType
) <= 4);
601 uint32 n
= js_DoubleToECMAUint32(d
);
602 tarray
->setIndex(index
, NativeType(n
));
603 } else if (ArrayTypeID() == TypedArray::TYPE_UINT8_CLAMPED
) {
604 // The uint8_clamped type has a special rounding converter
606 tarray
->setIndex(index
, NativeType(d
));
608 JS_ASSERT(sizeof(NativeType
) <= 4);
609 int32 n
= js_DoubleToECMAInt32(d
);
610 tarray
->setIndex(index
, NativeType(n
));
617 obj_defineProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval value
,
618 JSPropertyOp getter
, JSPropertyOp setter
, uintN attrs
)
620 if (id
== ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
))
623 return obj_setProperty(cx
, obj
, id
, &value
);
627 obj_deleteProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*rval
)
629 if (id
== ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
)) {
634 TypedArray
*tarray
= TypedArray::fromJSObject(obj
);
637 if (tarray
->isArrayIndex(cx
, id
)) {
647 obj_enumerate(JSContext
*cx
, JSObject
*obj
, JSIterateOp enum_op
,
648 jsval
*statep
, jsid
*idp
)
650 ThisTypeArray
*tarray
= ThisTypeArray::fromJSObject(obj
);
655 case JSENUMERATE_INIT
:
656 *statep
= JSVAL_ZERO
;
658 *idp
= INT_TO_JSID(tarray
->length
);
661 case JSENUMERATE_NEXT
:
662 curVal
= JSVAL_TO_INT(*statep
);
663 *idp
= INT_TO_JSID(curVal
);
664 *statep
= (curVal
== int32(tarray
->length
))
666 : INT_TO_JSVAL(curVal
+1);
669 case JSENUMERATE_DESTROY
:
670 *statep
= JSVAL_NULL
;
678 obj_typeOf(JSContext
*cx
, JSObject
*obj
)
680 return JSTYPE_OBJECT
;
684 * new [Type]Array(length)
685 * new [Type]Array(otherTypedArray)
686 * new [Type]Array(JSArray)
687 * new [Type]Array(ArrayBuffer, [optional] byteOffset, [optional] length)
690 class_constructor(JSContext
*cx
, JSObject
*obj
,
691 uintN argc
, jsval
*argv
, jsval
*rval
)
694 // Note: this is a constructor for slowClass, not fastClass!
697 if (!JS_IsConstructing(cx
)) {
698 obj
= NewObject(cx
, slowClass(), NULL
, NULL
);
701 *rval
= OBJECT_TO_JSVAL(obj
);
704 return create(cx
, obj
, argc
, argv
, rval
);
708 create(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
711 obj
= NewObject(cx
, slowClass(), NULL
, NULL
);
714 *rval
= OBJECT_TO_JSVAL(obj
);
717 ThisTypeArray
*tarray
= 0;
719 // must have at least one arg
721 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
722 JSMSG_TYPED_ARRAY_BAD_ARGS
);
726 // figure out the type of the first argument
727 if (JSVAL_IS_INT(argv
[0])) {
728 int32 len
= JSVAL_TO_INT(argv
[0]);
730 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
731 JSMSG_BAD_ARRAY_LENGTH
);
736 tarray
= new ThisTypeArray();
738 JS_ReportOutOfMemory(cx
);
742 if (!tarray
->init(cx
, len
)) {
746 } else if (JSVAL_IS_OBJECT(argv
[0])) {
747 int32_t byteOffset
= -1;
751 if (!ValueToInt32(cx
, argv
[1], &byteOffset
))
753 if (byteOffset
< 0) {
754 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
755 JSMSG_TYPED_ARRAY_NEGATIVE_ARG
, "1");
761 if (!ValueToInt32(cx
, argv
[2], &length
))
764 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
765 JSMSG_TYPED_ARRAY_NEGATIVE_ARG
, "2");
770 tarray
= new ThisTypeArray();
772 JS_ReportOutOfMemory(cx
);
776 if (!tarray
->init(cx
, JSVAL_TO_OBJECT(argv
[0]), byteOffset
, length
)) {
781 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
782 JSMSG_TYPED_ARRAY_BAD_ARGS
);
786 makeFastWithPrivate(cx
, obj
, tarray
);
791 class_finalize(JSContext
*cx
, JSObject
*obj
)
793 ThisTypeArray
*tarray
= ThisTypeArray::fromJSObject(obj
);
797 /* slice(start[, end]) */
799 fun_slice(JSContext
*cx
, uintN argc
, jsval
*vp
)
804 argv
= JS_ARGV(cx
, vp
);
805 obj
= JS_THIS_OBJECT(cx
, vp
);
807 ThisTypeArray
*tarray
= ThisTypeArray::fromJSObject(obj
);
811 // these are the default values
812 int32_t begin
= 0, end
= tarray
->length
;
813 int32_t length
= int32(tarray
->length
);
816 if (!ValueToInt32(cx
, argv
[0], &begin
))
822 } else if (begin
> length
) {
827 if (!ValueToInt32(cx
, argv
[1], &end
))
833 } else if (end
> length
) {
842 ThisTypeArray
*ntarray
= tarray
->slice(begin
, end
);
844 // this should rarely ever happen
845 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
846 JSMSG_TYPED_ARRAY_BAD_ARGS
);
850 // note the usage of JS_NewObject here -- we don't want the
851 // constructor to be called!
852 JSObject
*nobj
= JS_NewObject(cx
, slowClass(), NULL
, NULL
);
858 makeFastWithPrivate(cx
, nobj
, ntarray
);
860 *vp
= OBJECT_TO_JSVAL(nobj
);
864 static ThisTypeArray
*
865 fromJSObject(JSObject
*obj
)
867 JS_ASSERT(obj
->getClass() == fastClass());
868 return reinterpret_cast<ThisTypeArray
*>(obj
->getPrivate());
871 // helper used by both the constructor and Slice()
873 makeFastWithPrivate(JSContext
*cx
, JSObject
*obj
, ThisTypeArray
*tarray
)
875 JS_ASSERT(obj
->getClass() == slowClass());
877 obj
->setPrivate(tarray
);
879 // now munge the classword and make this into a fast typed
880 // array class, since it's an instance
881 obj
->classword
^= jsuword(slowClass());
882 obj
->classword
|= jsuword(fastClass());
884 obj
->map
= &fastObjectMap
;
888 TypedArrayTemplate() { }
891 init(JSContext
*cx
, uint32 len
)
893 type
= ArrayTypeID();
894 return createBufferWithSizeAndCount(cx
, sizeof(NativeType
), len
);
898 init(JSContext
*cx
, JSObject
*other
, int32 byteOffsetInt
= -1, int32 lengthInt
= -1)
900 type
= ArrayTypeID();
902 //printf ("Constructing with type %d other %p offset %d length %d\n", type, other, byteOffset, length);
904 if (JS_IsArrayObject(cx
, other
)) {
906 if (!JS_GetArrayLength(cx
, other
, &len
))
908 if (!createBufferWithSizeAndCount(cx
, sizeof(NativeType
), len
))
910 if (!copyFrom(cx
, other
, len
))
912 } else if (js_IsTypedArray(other
)) {
913 TypedArray
*tarray
= TypedArray::fromJSObject(other
);
915 //printf ("SizeAndCount: %d %d\n", sizeof(NativeType), tarray->length);
917 if (!createBufferWithSizeAndCount(cx
, sizeof(NativeType
), tarray
->length
))
919 if (!copyFrom(tarray
))
921 } else if (other
->getClass() == &ArrayBuffer::jsclass
) {
922 ArrayBuffer
*abuf
= ArrayBuffer::fromJSObject(other
);
924 //printf ("buffer: %d %d %d\n", abuf->byteLength, abuf->byteLength / sizeof(NativeType), len * sizeof(NativeType) == abuf->byteLength);
925 uint32 boffset
= (byteOffsetInt
< 0) ? 0 : uint32(byteOffsetInt
);
927 if (boffset
> abuf
->byteLength
|| boffset
% sizeof(NativeType
) != 0) {
928 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
929 JSMSG_TYPED_ARRAY_BAD_ARGS
);
930 return false; // invalid byteOffset
935 len
= (abuf
->byteLength
- boffset
) / sizeof(NativeType
);
936 if (len
* sizeof(NativeType
) != (abuf
->byteLength
- boffset
)) {
937 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
938 JSMSG_TYPED_ARRAY_BAD_ARGS
);
939 return false; // given byte array doesn't map exactly to sizeof(NativeType)*N
942 len
= (uint32
) lengthInt
;
945 // Go slowly and check for overflow.
946 uint32 arrayByteLength
= len
*sizeof(NativeType
);
947 if (uint32(len
) >= INT32_MAX
/ sizeof(NativeType
) ||
948 uint32(boffset
) >= INT32_MAX
- arrayByteLength
)
950 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
951 JSMSG_TYPED_ARRAY_BAD_ARGS
);
952 return false; // overflow occurred along the way when calculating boffset+len*sizeof(NativeType)
955 if (arrayByteLength
+ boffset
> abuf
->byteLength
) {
956 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
957 JSMSG_TYPED_ARRAY_BAD_ARGS
);
958 return false; // boffset+len is too big for the arraybuffer
963 byteOffset
= boffset
;
964 byteLength
= arrayByteLength
;
966 data
= abuf
->offsetData(boffset
);
968 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
969 JSMSG_TYPED_ARRAY_BAD_ARGS
);
977 getIndex(uint32 index
) const
979 return *(static_cast<const NativeType
*>(data
) + index
);
983 setIndex(uint32 index
, NativeType val
)
985 *(static_cast<NativeType
*>(data
) + index
) = val
;
988 inline void copyIndexToValue(JSContext
*cx
, uint32 index
, jsval
*vp
);
991 slice(uint32 begin
, uint32 end
)
993 if (begin
> length
|| end
> length
)
996 ThisTypeArray
*tarray
= new ThisTypeArray();
1000 tarray
->buffer
= buffer
;
1001 tarray
->bufferJS
= bufferJS
;
1002 tarray
->byteOffset
= byteOffset
+ begin
* sizeof(NativeType
);
1003 tarray
->byteLength
= (end
- begin
) * sizeof(NativeType
);
1004 tarray
->length
= end
- begin
;
1005 tarray
->type
= type
;
1006 tarray
->data
= buffer
->offsetData(tarray
->byteOffset
);
1013 nativeFromValue(JSContext
*cx
, jsval v
)
1015 if (JSVAL_IS_INT(v
))
1016 return NativeType(JSVAL_TO_INT(v
));
1018 if (JSVAL_IS_DOUBLE(v
))
1019 return NativeType(*JSVAL_TO_DOUBLE(v
));
1021 if (JSVAL_IS_PRIMITIVE(v
) && v
!= JSVAL_HOLE
) {
1023 ValueToNumber(cx
, v
, &dval
);
1024 return NativeType(dval
);
1027 if (ArrayTypeIsFloatingPoint())
1028 return NativeType(js_NaN
);
1030 return NativeType(int32(0));
1034 copyFrom(JSContext
*cx
, JSObject
*ar
, jsuint len
)
1036 NativeType
*dest
= static_cast<NativeType
*>(data
);
1038 if (ar
->isDenseArray() && ar
->getDenseArrayCapacity() >= len
) {
1039 JS_ASSERT(ar
->getArrayLength() == len
);
1041 jsval
*src
= ar
->getDenseArrayElements();
1043 for (uintN i
= 0; i
< len
; ++i
) {
1045 *dest
++ = nativeFromValue(cx
, v
);
1051 for (uintN i
= 0; i
< len
; ++i
) {
1052 if (!ar
->getProperty(cx
, INT_TO_JSID(i
), &v
))
1054 *dest
++ = nativeFromValue(cx
, v
);
1062 copyFrom(TypedArray
*tarray
)
1064 NativeType
*dest
= static_cast<NativeType
*>(data
);
1066 if (tarray
->type
== type
) {
1067 memcpy(dest
, tarray
->data
, tarray
->byteLength
);
1071 switch (tarray
->type
) {
1072 case TypedArray::TYPE_INT8
: {
1073 int8
*src
= static_cast<int8
*>(tarray
->data
);
1074 for (uintN i
= 0; i
< length
; ++i
)
1075 *dest
++ = NativeType(*src
++);
1078 case TypedArray::TYPE_UINT8
:
1079 case TypedArray::TYPE_UINT8_CLAMPED
: {
1080 uint8
*src
= static_cast<uint8
*>(tarray
->data
);
1081 for (uintN i
= 0; i
< length
; ++i
)
1082 *dest
++ = NativeType(*src
++);
1085 case TypedArray::TYPE_INT16
: {
1086 int16
*src
= static_cast<int16
*>(tarray
->data
);
1087 for (uintN i
= 0; i
< length
; ++i
)
1088 *dest
++ = NativeType(*src
++);
1091 case TypedArray::TYPE_UINT16
: {
1092 uint16
*src
= static_cast<uint16
*>(tarray
->data
);
1093 for (uintN i
= 0; i
< length
; ++i
)
1094 *dest
++ = NativeType(*src
++);
1097 case TypedArray::TYPE_INT32
: {
1098 int32
*src
= static_cast<int32
*>(tarray
->data
);
1099 for (uintN i
= 0; i
< length
; ++i
)
1100 *dest
++ = NativeType(*src
++);
1103 case TypedArray::TYPE_UINT32
: {
1104 uint32
*src
= static_cast<uint32
*>(tarray
->data
);
1105 for (uintN i
= 0; i
< length
; ++i
)
1106 *dest
++ = NativeType(*src
++);
1109 case TypedArray::TYPE_FLOAT32
: {
1110 float *src
= static_cast<float*>(tarray
->data
);
1111 for (uintN i
= 0; i
< length
; ++i
)
1112 *dest
++ = NativeType(*src
++);
1115 case TypedArray::TYPE_FLOAT64
: {
1116 double *src
= static_cast<double*>(tarray
->data
);
1117 for (uintN i
= 0; i
< length
; ++i
)
1118 *dest
++ = NativeType(*src
++);
1122 JS_NOT_REACHED("copyFrom with a TypedArray of unknown type");
1130 createBufferWithSizeAndCount(JSContext
*cx
, uint32 size
, uint32 count
)
1132 JS_ASSERT(size
!= 0);
1134 if (size
!= 0 && count
>= INT32_MAX
/ size
) {
1135 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1136 JSMSG_NEED_DIET
, "size and count");
1140 int32 bytelen
= size
* count
;
1141 if (!createBufferWithByteLength(cx
, bytelen
))
1149 createBufferWithByteLength(JSContext
*cx
, int32 bytes
)
1151 if (!INT_FITS_IN_JSVAL(bytes
)) {
1152 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1153 JSMSG_NEED_DIET
, "byte length");
1157 jsval argv
= INT_TO_JSVAL(bytes
);
1158 JSObject
*obj
= JS_ConstructObjectWithArguments(cx
, &ArrayBuffer::jsclass
, NULL
, NULL
,
1164 buffer
= ArrayBuffer::fromJSObject(obj
);
1168 data
= buffer
->data
;
1174 // this default implementation is only valid for integer types
1175 // less than 32-bits in size.
1176 template<typename NativeType
>
1178 TypedArrayTemplate
<NativeType
>::copyIndexToValue(JSContext
*cx
, uint32 index
, jsval
*vp
)
1180 JS_STATIC_ASSERT(sizeof(NativeType
) < 4);
1182 *vp
= INT_TO_JSVAL(getIndex(index
));
1185 // and we need to specialize for 32-bit integers and floats
1188 TypedArrayTemplate
<int32
>::copyIndexToValue(JSContext
*cx
, uint32 index
, jsval
*vp
)
1190 int32 val
= getIndex(index
);
1191 if (INT_FITS_IN_JSVAL(val
)) {
1192 *vp
= INT_TO_JSVAL(val
);
1194 jsdouble
*dp
= js_NewWeaklyRootedDouble(cx
, jsdouble(val
));
1195 *vp
= dp
? DOUBLE_TO_JSVAL(dp
) : JSVAL_VOID
;
1201 TypedArrayTemplate
<uint32
>::copyIndexToValue(JSContext
*cx
, uint32 index
, jsval
*vp
)
1203 uint32 val
= getIndex(index
);
1204 if (val
< uint32(JSVAL_INT_MAX
)) {
1205 *vp
= INT_TO_JSVAL(int32(val
));
1207 jsdouble
*dp
= js_NewWeaklyRootedDouble(cx
, jsdouble(val
));
1208 *vp
= dp
? DOUBLE_TO_JSVAL(dp
) : JSVAL_VOID
;
1214 TypedArrayTemplate
<float>::copyIndexToValue(JSContext
*cx
, uint32 index
, jsval
*vp
)
1216 float val
= getIndex(index
);
1217 if (!js_NewWeaklyRootedNumber(cx
, jsdouble(val
), vp
))
1223 TypedArrayTemplate
<double>::copyIndexToValue(JSContext
*cx
, uint32 index
, jsval
*vp
)
1225 double val
= getIndex(index
);
1226 if (!js_NewWeaklyRootedNumber(cx
, jsdouble(val
), vp
))
1235 * ArrayBuffer (base)
1238 JSClass
ArrayBuffer::jsclass
= {
1240 JSCLASS_HAS_PRIVATE
| JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer
),
1241 JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
,
1242 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, ArrayBuffer::class_finalize
,
1243 JSCLASS_NO_OPTIONAL_MEMBERS
1246 JSPropertySpec
ArrayBuffer::jsprops
[] = {
1248 -1, JSPROP_SHARED
| JSPROP_PERMANENT
| JSPROP_READONLY
,
1249 ArrayBuffer::prop_getByteLength
, ArrayBuffer::prop_getByteLength
},
1257 JSPropertySpec
TypedArray::jsprops
[] = {
1259 -1, JSPROP_SHARED
| JSPROP_PERMANENT
| JSPROP_READONLY
,
1260 TypedArray::prop_getLength
, TypedArray::prop_getLength
},
1262 -1, JSPROP_SHARED
| JSPROP_PERMANENT
| JSPROP_READONLY
,
1263 TypedArray::prop_getByteLength
, TypedArray::prop_getByteLength
},
1265 -1, JSPROP_SHARED
| JSPROP_PERMANENT
| JSPROP_READONLY
,
1266 TypedArray::prop_getByteOffset
, TypedArray::prop_getByteOffset
},
1268 -1, JSPROP_SHARED
| JSPROP_PERMANENT
| JSPROP_READONLY
,
1269 TypedArray::prop_getBuffer
, TypedArray::prop_getBuffer
},
1275 * TypedArray boilerplate
1278 #define IMPL_TYPED_ARRAY_STATICS(_typedArray) \
1279 template<> JSObjectMap _typedArray::fastObjectMap(&_typedArray::fastObjectOps, \
1280 JSObjectMap::SHAPELESS); \
1281 template<> JSObjectOps _typedArray::fastObjectOps = { \
1282 &_typedArray::fastObjectMap, \
1283 _typedArray::obj_lookupProperty, \
1284 _typedArray::obj_defineProperty, \
1285 _typedArray::obj_getProperty, \
1286 _typedArray::obj_setProperty, \
1287 _typedArray::obj_getAttributes, \
1288 _typedArray::obj_setAttributes, \
1289 _typedArray::obj_deleteProperty, \
1291 _typedArray::obj_enumerate, \
1293 _typedArray::obj_typeOf, \
1294 _typedArray::obj_trace, \
1296 _typedArray::obj_dropProperty, \
1300 template<> JSFunctionSpec _typedArray::jsfuncs[] = { \
1301 JS_FN("slice", _typedArray::fun_slice, 2, 0), \
1305 #define IMPL_TYPED_ARRAY_SLOW_CLASS(_typedArray) \
1308 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray), \
1309 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, \
1310 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, \
1311 JSCLASS_NO_OPTIONAL_MEMBERS \
1314 #define IMPL_TYPED_ARRAY_FAST_CLASS(_typedArray) \
1317 JSCLASS_HAS_PRIVATE, \
1318 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, \
1319 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, \
1320 _typedArray::class_finalize, \
1321 _typedArray::getObjectOps, NULL, NULL, NULL, \
1322 NULL, NULL, NULL, NULL \
1325 #define INIT_TYPED_ARRAY_CLASS(_typedArray,_type) \
1327 proto = js_InitClass(cx, obj, NULL, \
1328 &TypedArray::slowClasses[TypedArray::_type], \
1329 _typedArray::class_constructor, 3, \
1330 _typedArray::jsprops, \
1331 _typedArray::jsfuncs, \
1335 proto->setPrivate(0); \
1338 IMPL_TYPED_ARRAY_STATICS(Int8Array
);
1339 IMPL_TYPED_ARRAY_STATICS(Uint8Array
);
1340 IMPL_TYPED_ARRAY_STATICS(Int16Array
);
1341 IMPL_TYPED_ARRAY_STATICS(Uint16Array
);
1342 IMPL_TYPED_ARRAY_STATICS(Int32Array
);
1343 IMPL_TYPED_ARRAY_STATICS(Uint32Array
);
1344 IMPL_TYPED_ARRAY_STATICS(Float32Array
);
1345 IMPL_TYPED_ARRAY_STATICS(Float64Array
);
1346 IMPL_TYPED_ARRAY_STATICS(Uint8ClampedArray
);
1348 JSClass
TypedArray::fastClasses
[TYPE_MAX
] = {
1349 IMPL_TYPED_ARRAY_FAST_CLASS(Int8Array
),
1350 IMPL_TYPED_ARRAY_FAST_CLASS(Uint8Array
),
1351 IMPL_TYPED_ARRAY_FAST_CLASS(Int16Array
),
1352 IMPL_TYPED_ARRAY_FAST_CLASS(Uint16Array
),
1353 IMPL_TYPED_ARRAY_FAST_CLASS(Int32Array
),
1354 IMPL_TYPED_ARRAY_FAST_CLASS(Uint32Array
),
1355 IMPL_TYPED_ARRAY_FAST_CLASS(Float32Array
),
1356 IMPL_TYPED_ARRAY_FAST_CLASS(Float64Array
),
1357 IMPL_TYPED_ARRAY_FAST_CLASS(Uint8ClampedArray
)
1360 JSClass
TypedArray::slowClasses
[TYPE_MAX
] = {
1361 IMPL_TYPED_ARRAY_SLOW_CLASS(Int8Array
),
1362 IMPL_TYPED_ARRAY_SLOW_CLASS(Uint8Array
),
1363 IMPL_TYPED_ARRAY_SLOW_CLASS(Int16Array
),
1364 IMPL_TYPED_ARRAY_SLOW_CLASS(Uint16Array
),
1365 IMPL_TYPED_ARRAY_SLOW_CLASS(Int32Array
),
1366 IMPL_TYPED_ARRAY_SLOW_CLASS(Uint32Array
),
1367 IMPL_TYPED_ARRAY_SLOW_CLASS(Float32Array
),
1368 IMPL_TYPED_ARRAY_SLOW_CLASS(Float64Array
),
1369 IMPL_TYPED_ARRAY_SLOW_CLASS(Uint8ClampedArray
)
1372 JS_FRIEND_API(JSObject
*)
1373 js_InitTypedArrayClasses(JSContext
*cx
, JSObject
*obj
)
1375 /* Idempotency required: we initialize several things, possibly lazily. */
1377 if (!js_GetClassObject(cx
, obj
, JSProto_ArrayBuffer
, &stop
))
1384 INIT_TYPED_ARRAY_CLASS(Int8Array
,TYPE_INT8
);
1385 INIT_TYPED_ARRAY_CLASS(Uint8Array
,TYPE_UINT8
);
1386 INIT_TYPED_ARRAY_CLASS(Int16Array
,TYPE_INT16
);
1387 INIT_TYPED_ARRAY_CLASS(Uint16Array
,TYPE_UINT16
);
1388 INIT_TYPED_ARRAY_CLASS(Int32Array
,TYPE_INT32
);
1389 INIT_TYPED_ARRAY_CLASS(Uint32Array
,TYPE_UINT32
);
1390 INIT_TYPED_ARRAY_CLASS(Float32Array
,TYPE_FLOAT32
);
1391 INIT_TYPED_ARRAY_CLASS(Float64Array
,TYPE_FLOAT64
);
1392 INIT_TYPED_ARRAY_CLASS(Uint8ClampedArray
,TYPE_UINT8_CLAMPED
);
1394 proto
= js_InitClass(cx
, obj
, NULL
, &ArrayBuffer::jsclass
,
1395 ArrayBuffer::class_constructor
, 1,
1396 ArrayBuffer::jsprops
, NULL
, NULL
, NULL
);
1400 proto
->setPrivate(NULL
);
1404 JS_FRIEND_API(JSBool
)
1405 js_IsArrayBuffer(JSObject
*obj
)
1407 return obj
&& obj
->getClass() == &ArrayBuffer::jsclass
;
1410 JS_FRIEND_API(JSBool
)
1411 js_IsTypedArray(JSObject
*obj
)
1414 obj
->getClass() >= &TypedArray::fastClasses
[0] &&
1415 obj
->getClass() < &TypedArray::fastClasses
[TypedArray::TYPE_MAX
];
1418 JS_FRIEND_API(JSObject
*)
1419 js_CreateArrayBuffer(JSContext
*cx
, jsuint nbytes
)
1421 AutoValueRooter
tvr(cx
);
1422 if (!js_NewNumberInRootedValue(cx
, jsdouble(nbytes
), tvr
.addr()))
1425 AutoValueRooter
rval(cx
);
1426 if (!ArrayBuffer::create(cx
, NULL
, 1, tvr
.addr(), rval
.addr()))
1429 return JSVAL_TO_OBJECT(rval
.value());
1432 static inline JSBool
1433 TypedArrayConstruct(JSContext
*cx
, jsint atype
, uintN argc
, jsval
*argv
, jsval
*rv
)
1436 case TypedArray::TYPE_INT8
:
1437 return !!Int8Array::create(cx
, NULL
, argc
, argv
, rv
);
1439 case TypedArray::TYPE_UINT8
:
1440 return !!Uint8Array::create(cx
, NULL
, argc
, argv
, rv
);
1442 case TypedArray::TYPE_INT16
:
1443 return !!Int16Array::create(cx
, NULL
, argc
, argv
, rv
);
1445 case TypedArray::TYPE_UINT16
:
1446 return !!Uint16Array::create(cx
, NULL
, argc
, argv
, rv
);
1448 case TypedArray::TYPE_INT32
:
1449 return !!Int32Array::create(cx
, NULL
, argc
, argv
, rv
);
1451 case TypedArray::TYPE_UINT32
:
1452 return !!Uint32Array::create(cx
, NULL
, argc
, argv
, rv
);
1454 case TypedArray::TYPE_FLOAT32
:
1455 return !!Float32Array::create(cx
, NULL
, argc
, argv
, rv
);
1457 case TypedArray::TYPE_FLOAT64
:
1458 return !!Float64Array::create(cx
, NULL
, argc
, argv
, rv
);
1460 case TypedArray::TYPE_UINT8_CLAMPED
:
1461 return !!Uint8ClampedArray::create(cx
, NULL
, argc
, argv
, rv
);
1464 JS_NOT_REACHED("shouldn't have gotten here");
1469 JS_FRIEND_API(JSObject
*)
1470 js_CreateTypedArray(JSContext
*cx
, jsint atype
, jsuint nelements
)
1472 JS_ASSERT(atype
>= 0 && atype
< TypedArray::TYPE_MAX
);
1474 jsval vals
[2] = { JSVAL_NULL
, JSVAL_NULL
};
1475 AutoArrayRooter
tvr(cx
, JS_ARRAY_LENGTH(vals
), vals
);
1477 if (!js_NewNumberInRootedValue(cx
, jsdouble(nelements
), &vals
[0]))
1480 if (!TypedArrayConstruct(cx
, atype
, 1, &vals
[0], &vals
[1]))
1483 return JSVAL_TO_OBJECT(vals
[1]);
1486 JS_FRIEND_API(JSObject
*)
1487 js_CreateTypedArrayWithArray(JSContext
*cx
, jsint atype
, JSObject
*arrayArg
)
1489 JS_ASSERT(atype
>= 0 && atype
< TypedArray::TYPE_MAX
);
1491 jsval vals
[2] = { JSVAL_NULL
, JSVAL_NULL
};
1492 AutoArrayRooter
tvr(cx
, JS_ARRAY_LENGTH(vals
), vals
);
1494 vals
[0] = OBJECT_TO_JSVAL(arrayArg
);
1496 if (!TypedArrayConstruct(cx
, atype
, 1, &vals
[0], &vals
[1]))
1499 return JSVAL_TO_OBJECT(vals
[1]);
1502 JS_FRIEND_API(JSObject
*)
1503 js_CreateTypedArrayWithBuffer(JSContext
*cx
, jsint atype
, JSObject
*bufArg
,
1504 jsint byteoffset
, jsint length
)
1506 JS_ASSERT(atype
>= 0 && atype
< TypedArray::TYPE_MAX
);
1507 JS_ASSERT(bufArg
&& ArrayBuffer::fromJSObject(bufArg
));
1508 JS_ASSERT_IF(byteoffset
< 0, length
< 0);
1510 jsval vals
[4] = { JSVAL_NULL
, JSVAL_NULL
, JSVAL_NULL
, JSVAL_NULL
};
1511 AutoArrayRooter
tvr(cx
, JS_ARRAY_LENGTH(vals
), vals
);
1514 vals
[0] = OBJECT_TO_JSVAL(bufArg
);
1516 if (byteoffset
>= 0) {
1517 if (!js_NewNumberInRootedValue(cx
, jsdouble(byteoffset
), &vals
[argc
]))
1524 if (!js_NewNumberInRootedValue(cx
, jsdouble(length
), &vals
[argc
]))
1530 if (!TypedArrayConstruct(cx
, atype
, argc
, &vals
[0], &vals
[3]))
1533 return JSVAL_TO_OBJECT(vals
[3]);
1536 JS_FRIEND_API(JSBool
)
1537 js_ReparentTypedArrayToScope(JSContext
*cx
, JSObject
*obj
, JSObject
*scope
)
1539 scope
= JS_GetGlobalForObject(cx
, scope
);
1543 if (!js_IsTypedArray(obj
))
1546 TypedArray
*typedArray
= TypedArray::fromJSObject(obj
);
1548 JSObject
*buffer
= typedArray
->bufferJS
;
1549 JS_ASSERT(js_IsArrayBuffer(buffer
));
1553 JSCLASS_CACHED_PROTO_KEY(&TypedArray::slowClasses
[typedArray
->type
]);
1554 if (!js_GetClassPrototype(cx
, scope
, key
, &proto
))
1557 obj
->setProto(proto
);
1558 obj
->setParent(scope
);
1560 key
= JSCLASS_CACHED_PROTO_KEY(&ArrayBuffer::jsclass
);
1561 if (!js_GetClassPrototype(cx
, scope
, key
, &proto
))
1564 buffer
->setProto(proto
);
1565 buffer
->setParent(scope
);