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 ***** */
51 #include "jsbuiltins.h"
53 #include "jsversion.h"
59 #include "jsstaticcheck.h"
62 #include "jstypedarray.h"
64 #include "jsobjinlines.h"
67 using namespace js::gc;
70 ValueIsLength(JSContext *cx, const Value &v, jsuint *len)
73 int32_t i = v.toInt32();
81 jsdouble d = v.toDouble();
82 if (JSDOUBLE_IS_NaN(d))
85 jsuint length = jsuint(d);
86 if (d != jsdouble(length))
99 * This class holds the underlying raw buffer that the TypedArray classes
100 * access. It can be created explicitly and passed to a TypedArray, or
101 * can be created implicitly by constructing a TypedArray with a size.
104 ArrayBuffer::fromJSObject(JSObject *obj)
106 while (!js_IsArrayBuffer(obj))
107 obj = obj->getProto();
108 return reinterpret_cast<ArrayBuffer*>(obj->getPrivate());
112 ArrayBuffer::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
114 ArrayBuffer *abuf = ArrayBuffer::fromJSObject(obj);
116 vp->setInt32(jsint(abuf->byteLength));
121 ArrayBuffer::class_finalize(JSContext *cx, JSObject *obj)
123 ArrayBuffer *abuf = ArrayBuffer::fromJSObject(obj);
125 abuf->freeStorage(cx);
126 cx->destroy<ArrayBuffer>(abuf);
131 * new ArrayBuffer(byteLength)
134 ArrayBuffer::class_constructor(JSContext *cx, uintN argc, Value *vp)
137 if (argc > 0 && !ValueToECMAInt32(cx, vp[2], &nbytes))
140 JSObject *bufobj = create(cx, nbytes);
143 vp->setObject(*bufobj);
148 ArrayBuffer::create(JSContext *cx, int32 nbytes)
150 JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass);
156 * We're just not going to support arrays that are bigger than what will fit
157 * as an integer value; if someone actually ever complains (validly), then we
160 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
164 ArrayBuffer *abuf = cx->create<ArrayBuffer>();
168 if (!abuf->allocateStorage(cx, nbytes)) {
169 cx->destroy<ArrayBuffer>(abuf);
173 obj->setPrivate(abuf);
178 ArrayBuffer::allocateStorage(JSContext *cx, uint32 nbytes)
180 JS_ASSERT(data == 0);
183 data = cx->calloc(nbytes);
193 ArrayBuffer::freeStorage(JSContext *cx)
198 // the destructor asserts that data is 0 in debug builds
204 ArrayBuffer::~ArrayBuffer()
206 JS_ASSERT(data == NULL);
212 * The non-templated base class for the specific typed implementations.
213 * This class holds all the member variables that are used by
218 TypedArray::fromJSObject(JSObject *obj)
220 while (!js_IsTypedArray(obj))
221 obj = obj->getProto();
222 return reinterpret_cast<TypedArray*>(obj->getPrivate());
226 TypedArray::isArrayIndex(JSContext *cx, jsid id, jsuint *ip)
229 if (js_IdIsIndex(id, &index) && index < length) {
238 typedef Value (* TypedArrayPropertyGetter)(TypedArray *tarray);
240 template <TypedArrayPropertyGetter Get>
241 class TypedArrayGetter {
243 static inline bool get(JSContext *cx, JSObject *obj, jsid id, Value *vp) {
245 if (js_IsTypedArray(obj)) {
246 TypedArray *tarray = TypedArray::fromJSObject(obj);
251 } while ((obj = obj->getProto()) != NULL);
257 getBuffer(TypedArray *tarray)
259 return ObjectValue(*tarray->bufferJS);
263 TypedArray::prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp)
265 return TypedArrayGetter<getBuffer>::get(cx, obj, id, vp);
269 getByteOffset(TypedArray *tarray)
271 return Int32Value(tarray->byteOffset);
275 TypedArray::prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp)
277 return TypedArrayGetter<getByteOffset>::get(cx, obj, id, vp);
281 getByteLength(TypedArray *tarray)
283 return Int32Value(tarray->byteLength);
287 TypedArray::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
289 return TypedArrayGetter<getByteLength>::get(cx, obj, id, vp);
293 getLength(TypedArray *tarray)
295 return Int32Value(tarray->length);
299 TypedArray::prop_getLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
301 return TypedArrayGetter<getLength>::get(cx, obj, id, vp);
305 TypedArray::obj_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
306 JSObject **objp, JSProperty **propp)
308 TypedArray *tarray = fromJSObject(obj);
311 if (tarray->isArrayIndex(cx, id)) {
312 *propp = (JSProperty *) 1; /* non-null to indicate found */
317 JSObject *proto = obj->getProto();
324 return proto->lookupProperty(cx, id, objp, propp);
328 TypedArray::obj_trace(JSTracer *trc, JSObject *obj)
330 TypedArray *tarray = fromJSObject(obj);
332 MarkObject(trc, *tarray->bufferJS, "typedarray.buffer");
336 TypedArray::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
338 *attrsp = (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
339 ? JSPROP_PERMANENT | JSPROP_READONLY
340 : JSPROP_PERMANENT | JSPROP_ENUMERATE;
345 TypedArray::obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
347 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
348 JSMSG_CANT_SET_ARRAY_ATTRS);
352 /* Helper clamped uint8 type */
355 js_TypedArray_uint8_clamp_double(const double x)
357 // Not < so that NaN coerces to 0
364 jsdouble toTruncate = x + 0.5;
365 JSUint8 y = JSUint8(toTruncate);
368 * now val is rounded to nearest, ties rounded up. We want
369 * rounded to nearest ties to even, so check whether we had a
372 if (y == toTruncate) {
374 * It was a tie (since adding 0.5 gave us the exact integer
375 * we want). Since we rounded up, we either already have an
376 * even number or we have an odd number but the number we
377 * want is one less. So just unconditionally masking out the
378 * ones bit should do the trick to get us the value we
387 JS_DEFINE_CALLINFO_1(extern, INT32, js_TypedArray_uint8_clamp_double, DOUBLE,
388 1, nanojit::ACCSET_NONE)
391 struct uint8_clamped {
395 uint8_clamped(const uint8_clamped& other) : val(other.val) { }
397 // invoke our assignment helpers for constructor conversion
398 uint8_clamped(uint8 x) { *this = x; }
399 uint8_clamped(uint16 x) { *this = x; }
400 uint8_clamped(uint32 x) { *this = x; }
401 uint8_clamped(int8 x) { *this = x; }
402 uint8_clamped(int16 x) { *this = x; }
403 uint8_clamped(int32 x) { *this = x; }
404 uint8_clamped(jsdouble x) { *this = x; }
406 inline uint8_clamped& operator= (const uint8_clamped& x) {
411 inline uint8_clamped& operator= (uint8 x) {
416 inline uint8_clamped& operator= (uint16 x) {
417 val = (x > 255) ? 255 : uint8(x);
421 inline uint8_clamped& operator= (uint32 x) {
422 val = (x > 255) ? 255 : uint8(x);
426 inline uint8_clamped& operator= (int8 x) {
427 val = (x >= 0) ? uint8(x) : 0;
431 inline uint8_clamped& operator= (int16 x) {
440 inline uint8_clamped& operator= (int32 x) {
449 inline uint8_clamped& operator= (const jsdouble x) {
450 val = uint8(js_TypedArray_uint8_clamp_double(x));
454 inline operator uint8() const {
459 /* Make sure the compiler isn't doing some funky stuff */
460 JS_STATIC_ASSERT(sizeof(uint8_clamped) == 1);
462 template<typename NativeType> static inline const int TypeIDOfType();
463 template<> inline const int TypeIDOfType<int8>() { return TypedArray::TYPE_INT8; }
464 template<> inline const int TypeIDOfType<uint8>() { return TypedArray::TYPE_UINT8; }
465 template<> inline const int TypeIDOfType<int16>() { return TypedArray::TYPE_INT16; }
466 template<> inline const int TypeIDOfType<uint16>() { return TypedArray::TYPE_UINT16; }
467 template<> inline const int TypeIDOfType<int32>() { return TypedArray::TYPE_INT32; }
468 template<> inline const int TypeIDOfType<uint32>() { return TypedArray::TYPE_UINT32; }
469 template<> inline const int TypeIDOfType<float>() { return TypedArray::TYPE_FLOAT32; }
470 template<> inline const int TypeIDOfType<double>() { return TypedArray::TYPE_FLOAT64; }
471 template<> inline const int TypeIDOfType<uint8_clamped>() { return TypedArray::TYPE_UINT8_CLAMPED; }
473 template<typename NativeType> static inline const bool TypeIsUnsigned() { return false; }
474 template<> inline const bool TypeIsUnsigned<uint8>() { return true; }
475 template<> inline const bool TypeIsUnsigned<uint16>() { return true; }
476 template<> inline const bool TypeIsUnsigned<uint32>() { return true; }
478 template<typename NativeType> static inline const bool TypeIsFloatingPoint() { return false; }
479 template<> inline const bool TypeIsFloatingPoint<float>() { return true; }
480 template<> inline const bool TypeIsFloatingPoint<double>() { return true; }
482 template<typename NativeType> class TypedArrayTemplate;
484 typedef TypedArrayTemplate<int8> Int8Array;
485 typedef TypedArrayTemplate<uint8> Uint8Array;
486 typedef TypedArrayTemplate<int16> Int16Array;
487 typedef TypedArrayTemplate<uint16> Uint16Array;
488 typedef TypedArrayTemplate<int32> Int32Array;
489 typedef TypedArrayTemplate<uint32> Uint32Array;
490 typedef TypedArrayTemplate<float> Float32Array;
491 typedef TypedArrayTemplate<double> Float64Array;
492 typedef TypedArrayTemplate<uint8_clamped> Uint8ClampedArray;
494 template<typename NativeType>
495 class TypedArrayTemplate
499 typedef NativeType ThisType;
500 typedef TypedArrayTemplate<NativeType> ThisTypeArray;
501 static const int ArrayTypeID() { return TypeIDOfType<NativeType>(); }
502 static const bool ArrayTypeIsUnsigned() { return TypeIsUnsigned<NativeType>(); }
503 static const bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint<NativeType>(); }
505 static JSFunctionSpec jsfuncs[];
507 static inline Class *slowClass()
509 return &TypedArray::slowClasses[ArrayTypeID()];
512 static inline Class *fastClass()
514 return &TypedArray::fastClasses[ArrayTypeID()];
518 obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
520 ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
523 if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
524 vp->setNumber(tarray->length);
529 if (tarray->isArrayIndex(cx, id, &index)) {
530 // this inline function is specialized for each type
531 tarray->copyIndexToValue(cx, index, vp);
537 JSObject *proto = obj->getProto();
544 if (js_LookupPropertyWithFlags(cx, proto, id, cx->resolveFlags, &obj2, &prop) < 0)
548 if (obj2->isNative()) {
549 shape = (Shape *) prop;
550 if (!js_NativeGet(cx, obj, obj2, shape, JSGET_METHOD_BARRIER, vp))
560 obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
562 ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
565 if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
566 vp->setNumber(tarray->length);
571 // We can't just chain to js_SetProperty, because we're not a normal object.
572 if (!tarray->isArrayIndex(cx, id, &index)) {
574 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
575 JSMSG_TYPED_ARRAY_BAD_INDEX);
578 // Silent ignore is better than an exception here, because
579 // at some point we may want to support other properties on
580 // these objects. This is especially true when these arrays
581 // are used to implement HTML Canvas 2D's PixelArray objects,
582 // which used to be plain old arrays.
588 tarray->setIndex(index, NativeType(vp->toInt32()));
594 if (vp->isDouble()) {
596 } else if (vp->isNull()) {
598 } else if (vp->isPrimitive()) {
599 JS_ASSERT(vp->isString() || vp->isUndefined() || vp->isBoolean());
600 if (vp->isString()) {
601 // note that ValueToNumber will always succeed with a string arg
602 ValueToNumber(cx, *vp, &d);
603 } else if (vp->isUndefined()) {
606 d = (double) vp->toBoolean();
609 // non-primitive assignments become NaN or 0 (for float/int arrays)
613 // If the array is an integer array, we only handle up to
614 // 32-bit ints from this point on. if we want to handle
615 // 64-bit ints, we'll need some changes.
617 // Assign based on characteristics of the destination type
618 if (ArrayTypeIsFloatingPoint()) {
619 tarray->setIndex(index, NativeType(d));
620 } else if (ArrayTypeIsUnsigned()) {
621 JS_ASSERT(sizeof(NativeType) <= 4);
622 uint32 n = js_DoubleToECMAUint32(d);
623 tarray->setIndex(index, NativeType(n));
624 } else if (ArrayTypeID() == TypedArray::TYPE_UINT8_CLAMPED) {
625 // The uint8_clamped type has a special rounding converter
627 tarray->setIndex(index, NativeType(d));
629 JS_ASSERT(sizeof(NativeType) <= 4);
630 int32 n = js_DoubleToECMAInt32(d);
631 tarray->setIndex(index, NativeType(n));
638 obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
639 PropertyOp getter, StrictPropertyOp setter, uintN attrs)
641 if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
645 return obj_setProperty(cx, obj, id, &tmp, false);
649 obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
651 if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
652 rval->setBoolean(false);
656 TypedArray *tarray = TypedArray::fromJSObject(obj);
659 if (tarray->isArrayIndex(cx, id)) {
660 rval->setBoolean(false);
664 rval->setBoolean(true);
669 obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
670 Value *statep, jsid *idp)
672 ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
676 * Iteration is "length" (if JSENUMERATE_INIT_ALL), then [0, length).
677 * *statep is JSVAL_TRUE if enumerating "length" and
678 * JSVAL_TO_INT(index) when enumerating index.
681 case JSENUMERATE_INIT_ALL:
682 statep->setBoolean(true);
684 *idp = INT_TO_JSID(tarray->length + 1);
687 case JSENUMERATE_INIT:
690 *idp = INT_TO_JSID(tarray->length);
693 case JSENUMERATE_NEXT:
694 if (statep->isTrue()) {
695 *idp = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
698 uint32 index = statep->toInt32();
699 if (index < uint32(tarray->length)) {
700 *idp = INT_TO_JSID(index);
701 statep->setInt32(index + 1);
703 JS_ASSERT(index == tarray->length);
709 case JSENUMERATE_DESTROY:
718 obj_typeOf(JSContext *cx, JSObject *obj)
720 return JSTYPE_OBJECT;
724 createTypedArray(JSContext *cx, JSObject *bufobj, uint32 byteOffset, uint32 len)
726 JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
730 ThisTypeArray *tarray = cx->create<ThisTypeArray>(bufobj, byteOffset, len);
734 JS_ASSERT(obj->getClass() == slowClass());
735 obj->setSharedNonNativeMap();
736 obj->clasp = fastClass();
737 obj->setPrivate(tarray);
739 // FIXME Bug 599008: make it ok to call preventExtensions here.
740 obj->flags |= JSObject::NOT_EXTENSIBLE;
746 * new [Type]Array(length)
747 * new [Type]Array(otherTypedArray)
748 * new [Type]Array(JSArray)
749 * new [Type]Array(ArrayBuffer, [optional] byteOffset, [optional] length)
752 class_constructor(JSContext *cx, uintN argc, Value *vp)
754 /* N.B. this is a constructor for slowClass, not fastClass! */
755 JSObject *obj = create(cx, argc, JS_ARGV(cx, vp));
763 create(JSContext *cx, uintN argc, Value *argv)
765 /* N.B. there may not be an argv[-2]/argv[-1]. */
769 if (argc == 0 || ValueIsLength(cx, argv[0], &len)) {
770 JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
774 return createTypedArray(cx, bufobj, 0, len);
777 /* (not an object) */
778 if (!argv[0].isObject()) {
779 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
780 JSMSG_TYPED_ARRAY_BAD_ARGS);
784 JSObject *dataObj = &argv[0].toObject();
787 if (js_IsTypedArray(dataObj)) {
788 TypedArray *otherTypedArray = TypedArray::fromJSObject(dataObj);
789 JS_ASSERT(otherTypedArray);
791 uint32 len = otherTypedArray->length;
792 JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
796 JSObject *obj = createTypedArray(cx, bufobj, 0, len);
797 if (!obj || !copyFrom(cx, obj, otherTypedArray, 0))
802 /* (obj, byteOffset, length). */
803 int32_t byteOffset = -1;
807 if (!ValueToInt32(cx, argv[1], &byteOffset))
809 if (byteOffset < 0) {
810 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
811 JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "1");
816 if (!ValueToInt32(cx, argv[2], &length))
819 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
820 JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "2");
826 /* (obj, byteOffset, length) */
827 return createTypedArrayWithOffsetLength(cx, dataObj, byteOffset, length);
831 class_finalize(JSContext *cx, JSObject *obj)
833 ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
835 cx->destroy<ThisTypeArray>(tarray);
838 /* subarray(start[, end]) */
840 fun_subarray(JSContext *cx, uintN argc, Value *vp)
842 JSObject *obj = ToObject(cx, &vp[1]);
846 if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp + 2))
849 if (obj->getClass() != fastClass()) {
850 // someone tried to apply this subarray() to the wrong class
851 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
852 JSMSG_INCOMPATIBLE_METHOD,
853 fastClass()->name, "subarray", obj->getClass()->name);
857 ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
861 // these are the default values
862 int32_t begin = 0, end = tarray->length;
863 int32_t length = int32(tarray->length);
866 Value *argv = JS_ARGV(cx, vp);
867 if (!ValueToInt32(cx, argv[0], &begin))
873 } else if (begin > length) {
878 if (!ValueToInt32(cx, argv[1], &end))
884 } else if (end > length) {
893 JSObject *nobj = createSubarray(cx, tarray, begin, end);
896 vp->setObject(*nobj);
900 /* set(array[, offset]) */
902 fun_set(JSContext *cx, uintN argc, Value *vp)
904 JSObject *obj = ToObject(cx, &vp[1]);
908 if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp + 2))
911 if (obj->getClass() != fastClass()) {
912 // someone tried to apply this set() to the wrong class
913 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
914 JSMSG_INCOMPATIBLE_METHOD,
915 fastClass()->name, "set", obj->getClass()->name);
919 ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
923 // these are the default values
926 Value *argv = JS_ARGV(cx, vp);
928 if (!ValueToInt32(cx, argv[1], &off))
931 if (off < 0 || uint32_t(off) > tarray->length) {
932 // the given offset is bogus
933 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
934 JSMSG_TYPED_ARRAY_BAD_ARGS);
941 // first arg must be either a typed array or a JS array
942 if (argc == 0 || !argv[0].isObject()) {
943 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
944 JSMSG_TYPED_ARRAY_BAD_ARGS);
948 JSObject *arg0 = argv[0].toObjectOrNull();
949 if (js_IsTypedArray(arg0)) {
950 TypedArray *src = TypedArray::fromJSObject(arg0);
952 src->length > tarray->length - offset)
954 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
955 JSMSG_TYPED_ARRAY_BAD_ARGS);
959 if (!copyFrom(cx, obj, src, offset))
963 if (!js_GetLengthProperty(cx, arg0, &len))
966 // avoid overflow; we know that offset <= length
967 if (len > tarray->length - offset) {
968 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
969 JSMSG_TYPED_ARRAY_BAD_ARGS);
973 if (!copyFrom(cx, obj, arg0, len, offset))
981 static ThisTypeArray *
982 fromJSObject(JSObject *obj)
984 JS_ASSERT(obj->getClass() == fastClass());
985 return reinterpret_cast<ThisTypeArray*>(obj->getPrivate());
989 TypedArrayTemplate(JSObject *bufobj, uint32 byteOffset, uint32 len)
991 JS_ASSERT(bufobj->getClass() == &ArrayBuffer::jsclass);
993 type = ArrayTypeID();
995 buffer = ArrayBuffer::fromJSObject(bufobj);
997 this->byteOffset = byteOffset;
999 JS_ASSERT(byteOffset <= buffer->byteLength);
1000 this->data = buffer->offsetData(byteOffset);
1001 JS_ASSERT(buffer->data <= this->data);
1002 JS_ASSERT(this->data <= buffer->offsetData(buffer->byteLength));
1004 this->byteLength = len * sizeof(NativeType);
1005 JS_ASSERT(buffer->byteLength - byteOffset >= this->byteLength);
1011 createTypedArrayWithOffsetLength(JSContext *cx, JSObject *other,
1012 int32 byteOffsetInt, int32 lengthInt)
1014 JS_ASSERT(!js_IsTypedArray(other));
1016 /* Handle creation from an ArrayBuffer not ArrayBuffer.prototype. */
1018 if (other->getClass() == &ArrayBuffer::jsclass &&
1019 ((abuf = ArrayBuffer::fromJSObject(other)) != NULL)) {
1020 uint32 boffset = (byteOffsetInt < 0) ? 0 : uint32(byteOffsetInt);
1022 if (boffset > abuf->byteLength || boffset % sizeof(NativeType) != 0) {
1023 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1024 JSMSG_TYPED_ARRAY_BAD_ARGS);
1025 return NULL; // invalid byteOffset
1029 if (lengthInt < 0) {
1030 len = (abuf->byteLength - boffset) / sizeof(NativeType);
1031 if (len * sizeof(NativeType) != (abuf->byteLength - boffset)) {
1032 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1033 JSMSG_TYPED_ARRAY_BAD_ARGS);
1034 return NULL; // given byte array doesn't map exactly to sizeof(NativeType)*N
1037 len = (uint32) lengthInt;
1040 // Go slowly and check for overflow.
1041 uint32 arrayByteLength = len*sizeof(NativeType);
1042 if (uint32(len) >= INT32_MAX / sizeof(NativeType) ||
1043 uint32(boffset) >= INT32_MAX - arrayByteLength)
1045 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1046 JSMSG_TYPED_ARRAY_BAD_ARGS);
1047 return NULL; // overflow occurred along the way when calculating boffset+len*sizeof(NativeType)
1050 if (arrayByteLength + boffset > abuf->byteLength) {
1051 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1052 JSMSG_TYPED_ARRAY_BAD_ARGS);
1053 return NULL; // boffset+len is too big for the arraybuffer
1056 return createTypedArray(cx, other, boffset, len);
1060 * Otherwise create a new typed array and copy len properties from the
1064 if (!js_GetLengthProperty(cx, other, &len))
1067 JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
1071 JSObject *obj = createTypedArray(cx, bufobj, 0, len);
1072 if (!obj || !copyFrom(cx, obj, other, len))
1078 getIndex(uint32 index) const
1080 return *(static_cast<const NativeType*>(data) + index);
1084 setIndex(uint32 index, NativeType val)
1086 *(static_cast<NativeType*>(data) + index) = val;
1089 inline void copyIndexToValue(JSContext *cx, uint32 index, Value *vp);
1092 createSubarray(JSContext *cx, ThisTypeArray *tarray, uint32 begin, uint32 end)
1096 JS_ASSERT(0 <= begin);
1097 JS_ASSERT(begin <= tarray->length);
1098 JS_ASSERT(0 <= end);
1099 JS_ASSERT(end <= tarray->length);
1101 JSObject *bufobj = tarray->bufferJS;
1104 JS_ASSERT(begin <= end);
1105 uint32 length = end - begin;
1107 JS_ASSERT(begin < UINT32_MAX / sizeof(NativeType));
1108 uint32 byteOffset = begin * sizeof(NativeType);
1110 return createTypedArray(cx, bufobj, byteOffset, length);
1115 nativeFromValue(JSContext *cx, const Value &v)
1118 return NativeType(v.toInt32());
1121 double d = v.toDouble();
1122 if (!ArrayTypeIsFloatingPoint() && JS_UNLIKELY(JSDOUBLE_IS_NaN(d)))
1123 return NativeType(int32(0));
1124 if (TypeIsFloatingPoint<NativeType>())
1125 return NativeType(d);
1126 if (TypeIsUnsigned<NativeType>())
1127 return NativeType(js_DoubleToECMAUint32(d));
1128 return NativeType(js_DoubleToECMAInt32(d));
1131 if (v.isPrimitive() && !v.isMagic()) {
1133 ValueToNumber(cx, v, &dval);
1134 return NativeType(dval);
1137 if (ArrayTypeIsFloatingPoint())
1138 return NativeType(js_NaN);
1140 return NativeType(int32(0));
1144 copyFrom(JSContext *cx, JSObject *thisTypedArrayObj,
1145 JSObject *ar, jsuint len, jsuint offset = 0)
1147 ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj);
1148 JS_ASSERT(thisTypedArray);
1150 JS_ASSERT(offset <= thisTypedArray->length);
1151 JS_ASSERT(len <= thisTypedArray->length - offset);
1152 NativeType *dest = static_cast<NativeType*>(thisTypedArray->data) + offset;
1154 if (ar->isDenseArray() && ar->getDenseArrayCapacity() >= len) {
1155 JS_ASSERT(ar->getArrayLength() == len);
1157 Value *src = ar->getDenseArrayElements();
1159 for (uintN i = 0; i < len; ++i)
1160 *dest++ = nativeFromValue(cx, *src++);
1165 for (uintN i = 0; i < len; ++i) {
1166 if (!ar->getProperty(cx, INT_TO_JSID(i), &v))
1168 *dest++ = nativeFromValue(cx, v);
1176 copyFrom(JSContext *cx, JSObject *thisTypedArrayObj, TypedArray *tarray, jsuint offset)
1178 ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj);
1179 JS_ASSERT(thisTypedArray);
1181 JS_ASSERT(offset <= thisTypedArray->length);
1182 JS_ASSERT(tarray->length <= thisTypedArray->length - offset);
1183 if (tarray->buffer == thisTypedArray->buffer)
1184 return thisTypedArray->copyFromWithOverlap(cx, tarray, offset);
1186 NativeType *dest = static_cast<NativeType*>(thisTypedArray->data) + offset;
1188 if (tarray->type == thisTypedArray->type) {
1189 memcpy(dest, tarray->data, tarray->byteLength);
1193 uintN srclen = tarray->length;
1194 switch (tarray->type) {
1195 case TypedArray::TYPE_INT8: {
1196 int8 *src = static_cast<int8*>(tarray->data);
1197 for (uintN i = 0; i < srclen; ++i)
1198 *dest++ = NativeType(*src++);
1201 case TypedArray::TYPE_UINT8:
1202 case TypedArray::TYPE_UINT8_CLAMPED: {
1203 uint8 *src = static_cast<uint8*>(tarray->data);
1204 for (uintN i = 0; i < srclen; ++i)
1205 *dest++ = NativeType(*src++);
1208 case TypedArray::TYPE_INT16: {
1209 int16 *src = static_cast<int16*>(tarray->data);
1210 for (uintN i = 0; i < srclen; ++i)
1211 *dest++ = NativeType(*src++);
1214 case TypedArray::TYPE_UINT16: {
1215 uint16 *src = static_cast<uint16*>(tarray->data);
1216 for (uintN i = 0; i < srclen; ++i)
1217 *dest++ = NativeType(*src++);
1220 case TypedArray::TYPE_INT32: {
1221 int32 *src = static_cast<int32*>(tarray->data);
1222 for (uintN i = 0; i < srclen; ++i)
1223 *dest++ = NativeType(*src++);
1226 case TypedArray::TYPE_UINT32: {
1227 uint32 *src = static_cast<uint32*>(tarray->data);
1228 for (uintN i = 0; i < srclen; ++i)
1229 *dest++ = NativeType(*src++);
1232 case TypedArray::TYPE_FLOAT32: {
1233 float *src = static_cast<float*>(tarray->data);
1234 for (uintN i = 0; i < srclen; ++i)
1235 *dest++ = NativeType(*src++);
1238 case TypedArray::TYPE_FLOAT64: {
1239 double *src = static_cast<double*>(tarray->data);
1240 for (uintN i = 0; i < srclen; ++i)
1241 *dest++ = NativeType(*src++);
1245 JS_NOT_REACHED("copyFrom with a TypedArray of unknown type");
1253 copyFromWithOverlap(JSContext *cx, TypedArray *tarray, jsuint offset)
1255 JS_ASSERT(offset <= length);
1257 NativeType *dest = static_cast<NativeType*>(data) + offset;
1259 if (tarray->type == type) {
1260 memmove(dest, tarray->data, tarray->byteLength);
1264 // We have to make a copy of the source array here, since
1265 // there's overlap, and we have to convert types.
1266 void *srcbuf = cx->malloc(tarray->byteLength);
1269 memcpy(srcbuf, tarray->data, tarray->byteLength);
1271 switch (tarray->type) {
1272 case TypedArray::TYPE_INT8: {
1273 int8 *src = (int8*) srcbuf;
1274 for (uintN i = 0; i < tarray->length; ++i)
1275 *dest++ = NativeType(*src++);
1278 case TypedArray::TYPE_UINT8:
1279 case TypedArray::TYPE_UINT8_CLAMPED: {
1280 uint8 *src = (uint8*) srcbuf;
1281 for (uintN i = 0; i < tarray->length; ++i)
1282 *dest++ = NativeType(*src++);
1285 case TypedArray::TYPE_INT16: {
1286 int16 *src = (int16*) srcbuf;
1287 for (uintN i = 0; i < tarray->length; ++i)
1288 *dest++ = NativeType(*src++);
1291 case TypedArray::TYPE_UINT16: {
1292 uint16 *src = (uint16*) srcbuf;
1293 for (uintN i = 0; i < tarray->length; ++i)
1294 *dest++ = NativeType(*src++);
1297 case TypedArray::TYPE_INT32: {
1298 int32 *src = (int32*) srcbuf;
1299 for (uintN i = 0; i < tarray->length; ++i)
1300 *dest++ = NativeType(*src++);
1303 case TypedArray::TYPE_UINT32: {
1304 uint32 *src = (uint32*) srcbuf;
1305 for (uintN i = 0; i < tarray->length; ++i)
1306 *dest++ = NativeType(*src++);
1309 case TypedArray::TYPE_FLOAT32: {
1310 float *src = (float*) srcbuf;
1311 for (uintN i = 0; i < tarray->length; ++i)
1312 *dest++ = NativeType(*src++);
1315 case TypedArray::TYPE_FLOAT64: {
1316 double *src = (double*) srcbuf;
1317 for (uintN i = 0; i < tarray->length; ++i)
1318 *dest++ = NativeType(*src++);
1322 JS_NOT_REACHED("copyFromWithOverlap with a TypedArray of unknown type");
1331 createBufferWithSizeAndCount(JSContext *cx, uint32 count)
1333 size_t size = sizeof(NativeType);
1334 if (size != 0 && count >= INT32_MAX / size) {
1335 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1336 JSMSG_NEED_DIET, "size and count");
1340 int32 bytelen = size * count;
1341 return ArrayBuffer::create(cx, bytelen);
1345 // this default implementation is only valid for integer types
1346 // less than 32-bits in size.
1347 template<typename NativeType>
1349 TypedArrayTemplate<NativeType>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
1351 JS_STATIC_ASSERT(sizeof(NativeType) < 4);
1353 vp->setInt32(getIndex(index));
1356 // and we need to specialize for 32-bit integers and floats
1359 TypedArrayTemplate<int32>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
1361 int32 val = getIndex(index);
1367 TypedArrayTemplate<uint32>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
1369 uint32 val = getIndex(index);
1375 TypedArrayTemplate<float>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
1377 float val = getIndex(index);
1381 * Doubles in typed arrays could be typed-punned arrays of integers. This
1382 * could allow user code to break the engine-wide invariant that only
1383 * canonical nans are stored into jsvals, which means user code could
1384 * confuse the engine into interpreting a double-typed jsval as an
1385 * object-typed jsval.
1387 * This could be removed for platforms/compilers known to convert a 32-bit
1388 * non-canonical nan to a 64-bit canonical nan.
1390 if (JS_UNLIKELY(JSDOUBLE_IS_NaN(dval)))
1393 vp->setDouble(dval);
1398 TypedArrayTemplate<double>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
1400 double val = getIndex(index);
1403 * Doubles in typed arrays could be typed-punned arrays of integers. This
1404 * could allow user code to break the engine-wide invariant that only
1405 * canonical nans are stored into jsvals, which means user code could
1406 * confuse the engine into interpreting a double-typed jsval as an
1407 * object-typed jsval.
1409 if (JS_UNLIKELY(JSDOUBLE_IS_NaN(val)))
1420 * ArrayBuffer (base)
1423 Class ArrayBuffer::jsclass = {
1425 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
1426 PropertyStub, /* addProperty */
1427 PropertyStub, /* delProperty */
1428 PropertyStub, /* getProperty */
1429 StrictPropertyStub, /* setProperty */
1433 ArrayBuffer::class_finalize,
1436 JSPropertySpec ArrayBuffer::jsprops[] = {
1438 -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
1439 Jsvalify(ArrayBuffer::prop_getByteLength), JS_StrictPropertyStub },
1447 JSPropertySpec TypedArray::jsprops[] = {
1449 -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
1450 Jsvalify(TypedArray::prop_getLength), JS_StrictPropertyStub },
1452 -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
1453 Jsvalify(TypedArray::prop_getByteLength), JS_StrictPropertyStub },
1455 -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
1456 Jsvalify(TypedArray::prop_getByteOffset), JS_StrictPropertyStub },
1458 -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
1459 Jsvalify(TypedArray::prop_getBuffer), JS_StrictPropertyStub },
1464 * TypedArray boilerplate
1467 #define IMPL_TYPED_ARRAY_STATICS(_typedArray) \
1468 template<> JSFunctionSpec _typedArray::jsfuncs[] = { \
1469 JS_FN("subarray", _typedArray::fun_subarray, 2, 0), \
1470 JS_FN("set", _typedArray::fun_set, 2, 0), \
1474 #define IMPL_TYPED_ARRAY_SLOW_CLASS(_typedArray) \
1477 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray), \
1478 PropertyStub, /* addProperty */ \
1479 PropertyStub, /* delProperty */ \
1480 PropertyStub, /* getProperty */ \
1481 StrictPropertyStub, /* setProperty */ \
1488 #define IMPL_TYPED_ARRAY_FAST_CLASS(_typedArray) \
1491 Class::NON_NATIVE | JSCLASS_HAS_PRIVATE, \
1492 PropertyStub, /* addProperty */ \
1493 PropertyStub, /* delProperty */ \
1494 PropertyStub, /* getProperty */ \
1495 StrictPropertyStub, /* setProperty */ \
1499 _typedArray::class_finalize, \
1500 NULL, /* reserved0 */ \
1501 NULL, /* checkAccess */ \
1503 NULL, /* construct */ \
1504 NULL, /* xdrObject */ \
1505 NULL, /* hasInstance */ \
1507 JS_NULL_CLASS_EXT, \
1509 _typedArray::obj_lookupProperty, \
1510 _typedArray::obj_defineProperty, \
1511 _typedArray::obj_getProperty, \
1512 _typedArray::obj_setProperty, \
1513 _typedArray::obj_getAttributes, \
1514 _typedArray::obj_setAttributes, \
1515 _typedArray::obj_deleteProperty, \
1516 _typedArray::obj_enumerate, \
1517 _typedArray::obj_typeOf, \
1518 _typedArray::obj_trace, \
1519 NULL, /* thisObject */ \
1524 #define INIT_TYPED_ARRAY_CLASS(_typedArray,_type) \
1526 proto = js_InitClass(cx, obj, NULL, \
1527 &TypedArray::slowClasses[TypedArray::_type], \
1528 _typedArray::class_constructor, 3, \
1529 _typedArray::jsprops, \
1530 _typedArray::jsfuncs, \
1534 JSObject *ctor = JS_GetConstructor(cx, proto); \
1536 !JS_DefineProperty(cx, ctor, "BYTES_PER_ELEMENT", \
1537 INT_TO_JSVAL(sizeof(_typedArray::ThisType)), \
1538 JS_PropertyStub, JS_StrictPropertyStub, \
1539 JSPROP_PERMANENT | JSPROP_READONLY) || \
1540 !JS_DefineProperty(cx, proto, "BYTES_PER_ELEMENT", \
1541 INT_TO_JSVAL(sizeof(_typedArray::ThisType)), \
1542 JS_PropertyStub, JS_StrictPropertyStub, \
1543 JSPROP_PERMANENT | JSPROP_READONLY)) \
1547 proto->setPrivate(0); \
1550 IMPL_TYPED_ARRAY_STATICS(Int8Array);
1551 IMPL_TYPED_ARRAY_STATICS(Uint8Array);
1552 IMPL_TYPED_ARRAY_STATICS(Int16Array);
1553 IMPL_TYPED_ARRAY_STATICS(Uint16Array);
1554 IMPL_TYPED_ARRAY_STATICS(Int32Array);
1555 IMPL_TYPED_ARRAY_STATICS(Uint32Array);
1556 IMPL_TYPED_ARRAY_STATICS(Float32Array);
1557 IMPL_TYPED_ARRAY_STATICS(Float64Array);
1558 IMPL_TYPED_ARRAY_STATICS(Uint8ClampedArray);
1560 Class TypedArray::fastClasses[TYPE_MAX] = {
1561 IMPL_TYPED_ARRAY_FAST_CLASS(Int8Array),
1562 IMPL_TYPED_ARRAY_FAST_CLASS(Uint8Array),
1563 IMPL_TYPED_ARRAY_FAST_CLASS(Int16Array),
1564 IMPL_TYPED_ARRAY_FAST_CLASS(Uint16Array),
1565 IMPL_TYPED_ARRAY_FAST_CLASS(Int32Array),
1566 IMPL_TYPED_ARRAY_FAST_CLASS(Uint32Array),
1567 IMPL_TYPED_ARRAY_FAST_CLASS(Float32Array),
1568 IMPL_TYPED_ARRAY_FAST_CLASS(Float64Array),
1569 IMPL_TYPED_ARRAY_FAST_CLASS(Uint8ClampedArray)
1572 Class TypedArray::slowClasses[TYPE_MAX] = {
1573 IMPL_TYPED_ARRAY_SLOW_CLASS(Int8Array),
1574 IMPL_TYPED_ARRAY_SLOW_CLASS(Uint8Array),
1575 IMPL_TYPED_ARRAY_SLOW_CLASS(Int16Array),
1576 IMPL_TYPED_ARRAY_SLOW_CLASS(Uint16Array),
1577 IMPL_TYPED_ARRAY_SLOW_CLASS(Int32Array),
1578 IMPL_TYPED_ARRAY_SLOW_CLASS(Uint32Array),
1579 IMPL_TYPED_ARRAY_SLOW_CLASS(Float32Array),
1580 IMPL_TYPED_ARRAY_SLOW_CLASS(Float64Array),
1581 IMPL_TYPED_ARRAY_SLOW_CLASS(Uint8ClampedArray)
1584 JS_FRIEND_API(JSObject *)
1585 js_InitTypedArrayClasses(JSContext *cx, JSObject *obj)
1587 /* Idempotency required: we initialize several things, possibly lazily. */
1589 if (!js_GetClassObject(cx, obj, JSProto_ArrayBuffer, &stop))
1596 INIT_TYPED_ARRAY_CLASS(Int8Array,TYPE_INT8);
1597 INIT_TYPED_ARRAY_CLASS(Uint8Array,TYPE_UINT8);
1598 INIT_TYPED_ARRAY_CLASS(Int16Array,TYPE_INT16);
1599 INIT_TYPED_ARRAY_CLASS(Uint16Array,TYPE_UINT16);
1600 INIT_TYPED_ARRAY_CLASS(Int32Array,TYPE_INT32);
1601 INIT_TYPED_ARRAY_CLASS(Uint32Array,TYPE_UINT32);
1602 INIT_TYPED_ARRAY_CLASS(Float32Array,TYPE_FLOAT32);
1603 INIT_TYPED_ARRAY_CLASS(Float64Array,TYPE_FLOAT64);
1604 INIT_TYPED_ARRAY_CLASS(Uint8ClampedArray,TYPE_UINT8_CLAMPED);
1606 proto = js_InitClass(cx, obj, NULL, &ArrayBuffer::jsclass,
1607 ArrayBuffer::class_constructor, 1,
1608 ArrayBuffer::jsprops, NULL, NULL, NULL);
1612 proto->setPrivate(NULL);
1616 JS_FRIEND_API(JSBool)
1617 js_IsArrayBuffer(JSObject *obj)
1620 return obj->getClass() == &ArrayBuffer::jsclass;
1623 JS_FRIEND_API(JSBool)
1624 js_IsTypedArray(JSObject *obj)
1627 Class *clasp = obj->getClass();
1628 return clasp >= &TypedArray::fastClasses[0] &&
1629 clasp < &TypedArray::fastClasses[TypedArray::TYPE_MAX];
1632 JS_FRIEND_API(JSObject *)
1633 js_CreateArrayBuffer(JSContext *cx, jsuint nbytes)
1635 return ArrayBuffer::create(cx, nbytes);
1638 static inline JSObject *
1639 TypedArrayConstruct(JSContext *cx, jsint atype, uintN argc, Value *argv)
1642 case TypedArray::TYPE_INT8:
1643 return Int8Array::create(cx, argc, argv);
1645 case TypedArray::TYPE_UINT8:
1646 return Uint8Array::create(cx, argc, argv);
1648 case TypedArray::TYPE_INT16:
1649 return Int16Array::create(cx, argc, argv);
1651 case TypedArray::TYPE_UINT16:
1652 return Uint16Array::create(cx, argc, argv);
1654 case TypedArray::TYPE_INT32:
1655 return Int32Array::create(cx, argc, argv);
1657 case TypedArray::TYPE_UINT32:
1658 return Uint32Array::create(cx, argc, argv);
1660 case TypedArray::TYPE_FLOAT32:
1661 return Float32Array::create(cx, argc, argv);
1663 case TypedArray::TYPE_FLOAT64:
1664 return Float64Array::create(cx, argc, argv);
1666 case TypedArray::TYPE_UINT8_CLAMPED:
1667 return Uint8ClampedArray::create(cx, argc, argv);
1670 JS_NOT_REACHED("shouldn't have gotten here");
1675 JS_FRIEND_API(JSObject *)
1676 js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements)
1678 JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
1680 Value nelems = Int32Value(nelements);
1681 return TypedArrayConstruct(cx, atype, 1, &nelems);
1684 JS_FRIEND_API(JSObject *)
1685 js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg)
1687 JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
1689 Value arrval = ObjectValue(*arrayArg);
1690 return TypedArrayConstruct(cx, atype, 1, &arrval);
1693 JS_FRIEND_API(JSObject *)
1694 js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg,
1695 jsint byteoffset, jsint length)
1697 JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
1698 JS_ASSERT(bufArg && ArrayBuffer::fromJSObject(bufArg));
1699 JS_ASSERT_IF(byteoffset < 0, length < 0);
1704 vals[0].setObject(*bufArg);
1706 if (byteoffset >= 0) {
1707 vals[argc].setInt32(byteoffset);
1712 vals[argc].setInt32(length);
1716 AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
1717 return TypedArrayConstruct(cx, atype, argc, &vals[0]);
1720 JS_FRIEND_API(JSBool)
1721 js_ReparentTypedArrayToScope(JSContext *cx, JSObject *obj, JSObject *scope)
1725 scope = JS_GetGlobalForObject(cx, scope);
1729 if (!js_IsTypedArray(obj))
1732 TypedArray *typedArray = TypedArray::fromJSObject(obj);
1734 JSObject *buffer = typedArray->bufferJS;
1735 JS_ASSERT(js_IsArrayBuffer(buffer));
1739 JSCLASS_CACHED_PROTO_KEY(&TypedArray::slowClasses[typedArray->type]);
1740 if (!js_GetClassPrototype(cx, scope, key, &proto))
1743 obj->setProto(proto);
1744 obj->setParent(scope);
1746 key = JSCLASS_CACHED_PROTO_KEY(&ArrayBuffer::jsclass);
1747 if (!js_GetClassPrototype(cx, scope, key, &proto))
1750 buffer->setProto(proto);
1751 buffer->setParent(scope);