This commit is contained in:
Robert Sayre 2010-08-27 22:25:03 -04:00
commit a3b6c5a908
3 changed files with 277 additions and 48 deletions

View File

@ -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

View File

@ -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;
}
@ -827,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;
@ -902,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)
{
@ -936,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;
@ -952,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);
@ -1073,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<NativeType*>(data);
JS_ASSERT(offset <= length);
JS_ASSERT(len <= length - offset);
NativeType *dest = static_cast<NativeType*>(data) + offset;
if (ar->isDenseArray() && ar->getDenseArrayCapacity() >= len) {
JS_ASSERT(ar->getArrayLength() == len);
@ -1098,63 +1170,71 @@ class TypedArrayTemplate
return true;
}
bool
copyFrom(TypedArray *tarray)
void
copyFrom(TypedArray *tarray, jsuint offset = 0)
{
NativeType *dest = static_cast<NativeType*>(data);
JS_ASSERT(offset <= length);
JS_ASSERT(tarray->length <= length - offset);
if (tarray->buffer == buffer) {
copyFromWithOverlap(tarray, offset);
return;
}
NativeType *dest = static_cast<NativeType*>(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<int8*>(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<uint8*>(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<int16*>(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<uint16*>(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<int32*>(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<uint32*>(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<float*>(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<double*>(tarray->data);
for (uintN i = 0; i < length; ++i)
for (uintN i = 0; i < srclen; ++i)
*dest++ = NativeType(*src++);
break;
}
@ -1162,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<NativeType*>(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
@ -1331,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 \
}

View File

@ -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);
@ -215,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));