From a06b6b66daa92f87342e67ca17c95c33ea27e745 Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Fri, 27 Aug 2010 12:06:34 -0400 Subject: [PATCH 1/3] b=590672; treat ArrayBuffer() and SomeArrayType() as (0); r=shaver --- js/src/jstypedarray.cpp | 28 ++++++++----------- js/src/tests/js1_8_5/extensions/typedarray.js | 15 ++++++++++ 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 2bba1b31d335..348af6514d0d 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -126,15 +126,12 @@ ArrayBuffer::create(JSContext *cx, JSObject *obj, rval->setObject(*obj); } - if (argc == 0) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_TYPED_ARRAY_BAD_ARGS); - return false; + int32_t nbytes = 0; + if (argc > 0) { + if (!ValueToECMAInt32(cx, argv[0], &nbytes)) + return false; } - int32_t nbytes; - if (!ValueToECMAInt32(cx, argv[0], &nbytes)) - return false; if (nbytes < 0) { /* * We're just not going to support arrays that are bigger than what will fit @@ -745,20 +742,17 @@ class TypedArrayTemplate ThisTypeArray *tarray = 0; - // must have at least one arg - if (argc == 0) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_TYPED_ARRAY_BAD_ARGS); - return false; - } + // figure out the type of the first argument; + // no args is treated like an int arg of 0. + if (argc == 0 || argv[0].isInt32()) { + int32 len = 0; + + if (argc != 0) + len = argv[0].toInt32(); - // figure out the type of the first argument - if (argv[0].isInt32()) { - int32 len = argv[0].toInt32(); if (len < 0) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); - return false; } diff --git a/js/src/tests/js1_8_5/extensions/typedarray.js b/js/src/tests/js1_8_5/extensions/typedarray.js index 9ac4773499c9..09de8dce295f 100644 --- a/js/src/tests/js1_8_5/extensions/typedarray.js +++ b/js/src/tests/js1_8_5/extensions/typedarray.js @@ -96,10 +96,25 @@ function test() check(function() (new Int32Array(zerobuf)).length == 0); checkThrows(function() new Int32Array(zerobuf, 1)); + var zerobuf2 = new ArrayBuffer(); + check(function() zerobuf2.byteLength == 0); + checkThrows(function() new ArrayBuffer(-100)); // this is using js_ValueToECMAUInt32, which is giving 0 for "abc" checkThrows(function() new ArrayBuffer("abc"), TODO); + var zeroarray = new Int32Array(0); + check(function() zeroarray.length == 0); + check(function() zeroarray.byteLength == 0); + check(function() zeroarray.buffer); + check(function() zeroarray.buffer.byteLength == 0); + + var zeroarray2 = new Int32Array(); + check(function() zeroarray2.length == 0); + check(function() zeroarray2.byteLength == 0); + check(function() zeroarray2.buffer); + check(function() zeroarray2.buffer.byteLength == 0); + var a = new Int32Array(20); check(function() a); check(function() a.length == 20); From 56b92565656ca62e29633579425167f419969067 Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Fri, 27 Aug 2010 12:07:24 -0400 Subject: [PATCH 2/3] b=575685; implement set() from TypedArray spec; r=jorendorff --- js/src/jstypedarray.cpp | 208 ++++++++++++++++-- js/src/tests/js1_8_5/extensions/typedarray.js | 67 ++++++ 2 files changed, 251 insertions(+), 24 deletions(-) diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 348af6514d0d..c675a8b650f1 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -821,11 +821,8 @@ class TypedArrayTemplate static JSBool fun_slice(JSContext *cx, uintN argc, Value *vp) { - Value *argv; - JSObject *obj; - - argv = JS_ARGV(cx, vp); - obj = ComputeThisFromVp(cx, vp); + Value *argv = JS_ARGV(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp+2)) return false; @@ -896,6 +893,86 @@ class TypedArrayTemplate return true; } + /* set(array[, offset]) */ + static JSBool + fun_set(JSContext *cx, uintN argc, Value *vp) + { + Value *argv = JS_ARGV(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); + + if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp+2)) + return false; + + if (obj->getClass() != fastClass()) { + // someone tried to apply this set() to the wrong class + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_METHOD, + fastClass()->name, "set", obj->getClass()->name); + return false; + } + + ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj); + if (!tarray) + return true; + + // these are the default values + int32_t offset = 0; + + if (argc > 1) { + if (!ValueToInt32(cx, argv[1], &offset)) + return false; + + if (offset < 0 || uint32_t(offset) > tarray->length) { + // the given offset is bogus + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return false; + } + } + + // first arg must be either a typed array or a JS array + if (!argv[0].isObject()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return false; + } + + JSObject *arg0 = argv[0].toObjectOrNull(); + if (js_IsTypedArray(arg0)) { + TypedArray *src = TypedArray::fromJSObject(arg0); + if (!src || + src->length > tarray->length - offset) + { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return false; + } + + tarray->copyFrom(src, offset); + } else if (arg0->wrappedObject(cx)->isArray()) { + jsuint len; + if (!js_GetLengthProperty(cx, arg0, &len)) + return false; + + // avoid overflow; we know that offset <= length + if (len > tarray->length - offset) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return false; + } + + if (!tarray->copyFrom(cx, arg0, len, offset)) + return false; + } else { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return false; + } + + vp->setUndefined(); + return true; + } + static ThisTypeArray * fromJSObject(JSObject *obj) { @@ -930,9 +1007,9 @@ class TypedArrayTemplate //printf ("Constructing with type %d other %p offset %d length %d\n", type, other, byteOffset, length); - if (JS_IsArrayObject(cx, other)) { + if (other->wrappedObject(cx)->isArray()) { jsuint len; - if (!JS_GetArrayLength(cx, other, &len)) + if (!js_GetLengthProperty(cx, other, &len)) return false; if (!createBufferWithSizeAndCount(cx, sizeof(NativeType), len)) return false; @@ -946,8 +1023,7 @@ class TypedArrayTemplate if (!createBufferWithSizeAndCount(cx, sizeof(NativeType), tarray->length)) return false; - if (!copyFrom(tarray)) - return false; + copyFrom(tarray); } else if (other->getClass() == &ArrayBuffer::jsclass) { ArrayBuffer *abuf = ArrayBuffer::fromJSObject(other); @@ -1067,9 +1143,11 @@ class TypedArrayTemplate } bool - copyFrom(JSContext *cx, JSObject *ar, jsuint len) + copyFrom(JSContext *cx, JSObject *ar, jsuint len, jsuint offset = 0) { - NativeType *dest = static_cast(data); + JS_ASSERT(offset <= length); + JS_ASSERT(len <= length - offset); + NativeType *dest = static_cast(data) + offset; if (ar->isDenseArray() && ar->getDenseArrayCapacity() >= len) { JS_ASSERT(ar->getArrayLength() == len); @@ -1092,63 +1170,71 @@ class TypedArrayTemplate return true; } - bool - copyFrom(TypedArray *tarray) + void + copyFrom(TypedArray *tarray, jsuint offset = 0) { - NativeType *dest = static_cast(data); + JS_ASSERT(offset <= length); + JS_ASSERT(tarray->length <= length - offset); + if (tarray->buffer == buffer) { + copyFromWithOverlap(tarray, offset); + return; + } + + NativeType *dest = static_cast(data) + offset; if (tarray->type == type) { memcpy(dest, tarray->data, tarray->byteLength); - return true; + return; } + uintN srclen = tarray->length; switch (tarray->type) { case TypedArray::TYPE_INT8: { int8 *src = static_cast(tarray->data); - for (uintN i = 0; i < length; ++i) + for (uintN i = 0; i < srclen; ++i) *dest++ = NativeType(*src++); break; } case TypedArray::TYPE_UINT8: case TypedArray::TYPE_UINT8_CLAMPED: { uint8 *src = static_cast(tarray->data); - for (uintN i = 0; i < length; ++i) + for (uintN i = 0; i < srclen; ++i) *dest++ = NativeType(*src++); break; } case TypedArray::TYPE_INT16: { int16 *src = static_cast(tarray->data); - for (uintN i = 0; i < length; ++i) + for (uintN i = 0; i < srclen; ++i) *dest++ = NativeType(*src++); break; } case TypedArray::TYPE_UINT16: { uint16 *src = static_cast(tarray->data); - for (uintN i = 0; i < length; ++i) + for (uintN i = 0; i < srclen; ++i) *dest++ = NativeType(*src++); break; } case TypedArray::TYPE_INT32: { int32 *src = static_cast(tarray->data); - for (uintN i = 0; i < length; ++i) + for (uintN i = 0; i < srclen; ++i) *dest++ = NativeType(*src++); break; } case TypedArray::TYPE_UINT32: { uint32 *src = static_cast(tarray->data); - for (uintN i = 0; i < length; ++i) + for (uintN i = 0; i < srclen; ++i) *dest++ = NativeType(*src++); break; } case TypedArray::TYPE_FLOAT32: { float *src = static_cast(tarray->data); - for (uintN i = 0; i < length; ++i) + for (uintN i = 0; i < srclen; ++i) *dest++ = NativeType(*src++); break; } case TypedArray::TYPE_FLOAT64: { double *src = static_cast(tarray->data); - for (uintN i = 0; i < length; ++i) + for (uintN i = 0; i < srclen; ++i) *dest++ = NativeType(*src++); break; } @@ -1156,8 +1242,81 @@ class TypedArrayTemplate JS_NOT_REACHED("copyFrom with a TypedArray of unknown type"); break; } + } - return true; + void + copyFromWithOverlap(TypedArray *tarray, jsuint offset = 0) + { + JS_ASSERT(offset < length); + + NativeType *dest = static_cast(data) + offset; + + if (tarray->type == type) { + memmove(dest, tarray->data, tarray->byteLength); + return; + } + + // We have to make a copy of the source array here, since + // there's overlap, and we have to convert types. + void *srcbuf = js_malloc(tarray->byteLength); + memcpy(srcbuf, tarray->data, tarray->byteLength); + + switch (tarray->type) { + case TypedArray::TYPE_INT8: { + int8 *src = (int8*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_UINT8: + case TypedArray::TYPE_UINT8_CLAMPED: { + uint8 *src = (uint8*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_INT16: { + int16 *src = (int16*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_UINT16: { + uint16 *src = (uint16*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_INT32: { + int32 *src = (int32*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_UINT32: { + uint32 *src = (uint32*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_FLOAT32: { + float *src = (float*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_FLOAT64: { + double *src = (double*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + default: + JS_NOT_REACHED("copyFromWithOverlap with a TypedArray of unknown type"); + break; + } + + js_free(srcbuf); } bool @@ -1325,6 +1484,7 @@ JSPropertySpec TypedArray::jsprops[] = { #define IMPL_TYPED_ARRAY_STATICS(_typedArray) \ template<> JSFunctionSpec _typedArray::jsfuncs[] = { \ JS_FN("slice", _typedArray::fun_slice, 2, 0), \ + JS_FN("set", _typedArray::fun_set, 2, 0), \ JS_FS_END \ } diff --git a/js/src/tests/js1_8_5/extensions/typedarray.js b/js/src/tests/js1_8_5/extensions/typedarray.js index 09de8dce295f..d8eb2dfbd3fb 100644 --- a/js/src/tests/js1_8_5/extensions/typedarray.js +++ b/js/src/tests/js1_8_5/extensions/typedarray.js @@ -230,6 +230,73 @@ function test() check(function() !(a[3] == a[3])); check(function() a[4] == 1); + // test set() + var empty = new Int32Array(0); + a = new Int32Array(9); + + empty.set([]); + empty.set([], 0); + + checkThrows(function() empty.set([1])); + checkThrows(function() empty.set([1], 0)); + checkThrows(function() empty.set([1], 1)); + + a.set([]); + a.set([], 3); + a.set([], 9); + + a.set(empty); + a.set(empty, 3); + a.set(empty, 9); + a.set(Array.prototype); + checkThrows(function() a.set(empty, 100)); + + checkThrows(function() a.set([1,2,3,4,5,6,7,8,9,10])); + checkThrows(function() a.set([1,2,3,4,5,6,7,8,9,10], 0)); + checkThrows(function() a.set([1,2,3,4,5,6,7,8,9,10], 0x7fffffff)); + checkThrows(function() a.set([1,2,3,4,5,6,7,8,9,10], 0xffffffff)); + checkThrows(function() a.set([1,2,3,4,5,6], 6)); + + checkThrows(function() a.set(new Array(0x7fffffff))); + checkThrows(function() a.set([1,2,3], 2147483647)); + + checkThrows(function() a.set(ArrayBuffer.prototype)); + checkThrows(function() a.set(UInt16Array.prototype)); + checkThrows(function() a.set(Int32Array.prototype)); + + a.set([1,2,3]); + a.set([4,5,6], 3); + check(function() + a[0] == 1 && a[1] == 2 && a[2] == 3 && + a[3] == 4 && a[4] == 5 && a[5] == 6 && + a[6] == 0 && a[7] == 0 && a[8] == 0); + + b = new Float32Array([7,8,9]); + a.set(b, 0); + a.set(b, 3); + check(function() + a[0] == 7 && a[1] == 8 && a[2] == 9 && + a[3] == 7 && a[4] == 8 && a[5] == 9 && + a[6] == 0 && a[7] == 0 && a[8] == 0); + a.set(a.slice(0,3), 6); + check(function() + a[0] == 7 && a[1] == 8 && a[2] == 9 && + a[3] == 7 && a[4] == 8 && a[5] == 9 && + a[6] == 7 && a[7] == 8 && a[8] == 9); + + a.set([1,2,3,4,5,6,7,8,9]); + a.set(a.slice(0,6), 3); + check(function() + a[0] == 1 && a[1] == 2 && a[2] == 3 && + a[3] == 1 && a[4] == 2 && a[5] == 3 && + a[6] == 4 && a[7] == 5 && a[8] == 6); + + a.set(a.slice(3,9), 0); + check(function() + a[0] == 1 && a[1] == 2 && a[2] == 3 && + a[3] == 4 && a[4] == 5 && a[5] == 6 && + a[6] == 4 && a[7] == 5 && a[8] == 6); + a = new ArrayBuffer(0x10); checkThrows(function() new Uint32Array(buffer, 4, 0x3FFFFFFF)); From 597f3eefdb2ce70c7507168a7e6496e7777b542d Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Fri, 27 Aug 2010 11:07:18 -0700 Subject: [PATCH 3/3] Fix crash on nested Iterator iteration, bug 590813. r=gal --- js/src/jsiter.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 079de7c2a435..607253a9805a 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -123,16 +123,11 @@ NativeIterator::mark(JSTracer *trc) MarkObject(trc, obj, "obj"); } -/* - * Shared code to close iterator's state either through an explicit call or - * when GC detects that the iterator is no longer reachable. - */ static void iterator_finalize(JSContext *cx, JSObject *obj) { JS_ASSERT(obj->getClass() == &js_IteratorClass); - /* Avoid double work if the iterator was closed by JSOP_ENDITER. */ NativeIterator *ni = obj->getNativeIterator(); if (ni) { cx->free(ni); @@ -811,8 +806,6 @@ js_CloseIterator(JSContext *cx, JSObject *obj) ni->props_cursor = ni->props_array; ni->next = *hp; *hp = obj; - } else { - iterator_finalize(cx, obj); } } #if JS_HAS_GENERATORS