зеркало из https://github.com/mozilla/gecko-dev.git
Bug 636078 - Fix some typed array bugs. r=vlad, r=jorendorff
This commit is contained in:
Родитель
ab404c48d1
Коммит
eb38099001
|
@ -133,23 +133,23 @@ ArrayBuffer::class_finalize(JSContext *cx, JSObject *obj)
|
||||||
JSBool
|
JSBool
|
||||||
ArrayBuffer::class_constructor(JSContext *cx, uintN argc, Value *vp)
|
ArrayBuffer::class_constructor(JSContext *cx, uintN argc, Value *vp)
|
||||||
{
|
{
|
||||||
return create(cx, argc, JS_ARGV(cx, vp), vp);
|
int32 nbytes = 0;
|
||||||
}
|
if (argc > 0 && !ValueToECMAInt32(cx, vp[2], &nbytes))
|
||||||
|
|
||||||
bool
|
|
||||||
ArrayBuffer::create(JSContext *cx, uintN argc, Value *argv, Value *rval)
|
|
||||||
{
|
|
||||||
/* N.B. there may not be an argv[-2]/argv[-1]. */
|
|
||||||
|
|
||||||
JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass);
|
|
||||||
if (!obj)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int32_t nbytes = 0;
|
JSObject *bufobj = create(cx, nbytes);
|
||||||
if (argc > 0) {
|
if (!bufobj)
|
||||||
if (!ValueToECMAInt32(cx, argv[0], &nbytes))
|
return false;
|
||||||
return false;
|
vp->setObject(*bufobj);
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject *
|
||||||
|
ArrayBuffer::create(JSContext *cx, int32 nbytes)
|
||||||
|
{
|
||||||
|
JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass);
|
||||||
|
if (!obj)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (nbytes < 0) {
|
if (nbytes < 0) {
|
||||||
/*
|
/*
|
||||||
|
@ -157,25 +157,21 @@ ArrayBuffer::create(JSContext *cx, uintN argc, Value *argv, Value *rval)
|
||||||
* as an integer value; if someone actually ever complains (validly), then we
|
* as an integer value; if someone actually ever complains (validly), then we
|
||||||
* can fix.
|
* can fix.
|
||||||
*/
|
*/
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
|
||||||
JSMSG_BAD_ARRAY_LENGTH);
|
return NULL;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayBuffer *abuf = cx->create<ArrayBuffer>();
|
ArrayBuffer *abuf = cx->create<ArrayBuffer>();
|
||||||
if (!abuf) {
|
if (!abuf)
|
||||||
JS_ReportOutOfMemory(cx);
|
return NULL;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!abuf->allocateStorage(cx, nbytes)) {
|
if (!abuf->allocateStorage(cx, nbytes)) {
|
||||||
cx->destroy<ArrayBuffer>(abuf);
|
cx->destroy<ArrayBuffer>(abuf);
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj->setPrivate(abuf);
|
obj->setPrivate(abuf);
|
||||||
rval->setObject(*obj);
|
return obj;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -185,10 +181,8 @@ ArrayBuffer::allocateStorage(JSContext *cx, uint32 nbytes)
|
||||||
|
|
||||||
if (nbytes) {
|
if (nbytes) {
|
||||||
data = cx->calloc(nbytes);
|
data = cx->calloc(nbytes);
|
||||||
if (!data) {
|
if (!data)
|
||||||
JS_ReportOutOfMemory(cx);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byteLength = nbytes;
|
byteLength = nbytes;
|
||||||
|
@ -726,6 +720,28 @@ class TypedArrayTemplate
|
||||||
return JSTYPE_OBJECT;
|
return JSTYPE_OBJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSObject *
|
||||||
|
createTypedArray(JSContext *cx, JSObject *bufobj, uint32 byteOffset, uint32 len)
|
||||||
|
{
|
||||||
|
JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
|
||||||
|
if (!obj)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ThisTypeArray *tarray = cx->create<ThisTypeArray>(bufobj, byteOffset, len);
|
||||||
|
if (!tarray)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
JS_ASSERT(obj->getClass() == slowClass());
|
||||||
|
obj->setSharedNonNativeMap();
|
||||||
|
obj->clasp = fastClass();
|
||||||
|
obj->setPrivate(tarray);
|
||||||
|
|
||||||
|
// FIXME Bug 599008: make it ok to call preventExtensions here.
|
||||||
|
obj->flags |= JSObject::NOT_EXTENSIBLE;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* new [Type]Array(length)
|
* new [Type]Array(length)
|
||||||
* new [Type]Array(otherTypedArray)
|
* new [Type]Array(otherTypedArray)
|
||||||
|
@ -736,80 +752,79 @@ class TypedArrayTemplate
|
||||||
class_constructor(JSContext *cx, uintN argc, Value *vp)
|
class_constructor(JSContext *cx, uintN argc, Value *vp)
|
||||||
{
|
{
|
||||||
/* N.B. this is a constructor for slowClass, not fastClass! */
|
/* N.B. this is a constructor for slowClass, not fastClass! */
|
||||||
return create(cx, argc, JS_ARGV(cx, vp), vp);
|
JSObject *obj = create(cx, argc, JS_ARGV(cx, vp));
|
||||||
|
if (!obj)
|
||||||
|
return false;
|
||||||
|
vp->setObject(*obj);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSBool
|
static JSObject *
|
||||||
create(JSContext *cx, uintN argc, Value *argv, Value *rval)
|
create(JSContext *cx, uintN argc, Value *argv)
|
||||||
{
|
{
|
||||||
/* N.B. there may not be an argv[-2]/argv[-1]. */
|
/* N.B. there may not be an argv[-2]/argv[-1]. */
|
||||||
|
|
||||||
JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
|
/* () or (number) */
|
||||||
if (!obj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ThisTypeArray *tarray = 0;
|
|
||||||
|
|
||||||
// figure out the type of the first argument;
|
|
||||||
// no args is treated like an int arg of 0.
|
|
||||||
jsuint len = 0;
|
jsuint len = 0;
|
||||||
bool hasLen = true;
|
if (argc == 0 || ValueIsLength(cx, argv[0], &len)) {
|
||||||
if (argc > 0)
|
JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
|
||||||
hasLen = ValueIsLength(cx, argv[0], &len);
|
if (!bufobj)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (hasLen) {
|
return createTypedArray(cx, bufobj, 0, len);
|
||||||
tarray = cx->create<ThisTypeArray>();
|
}
|
||||||
if (!tarray) {
|
|
||||||
JS_ReportOutOfMemory(cx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tarray->init(cx, len)) {
|
/* (not an object) */
|
||||||
cx->destroy<ThisTypeArray>(tarray);
|
if (!argv[0].isObject()) {
|
||||||
return false;
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
}
|
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||||
} else if (argc > 0 && argv[0].isObject()) {
|
return NULL;
|
||||||
int32_t byteOffset = -1;
|
}
|
||||||
int32_t length = -1;
|
|
||||||
|
|
||||||
if (argc > 1) {
|
JSObject *dataObj = &argv[0].toObject();
|
||||||
if (!ValueToInt32(cx, argv[1], &byteOffset))
|
|
||||||
return false;
|
/* (typedArray) */
|
||||||
if (byteOffset < 0) {
|
if (js_IsTypedArray(dataObj)) {
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
TypedArray *otherTypedArray = TypedArray::fromJSObject(dataObj);
|
||||||
JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "1");
|
JS_ASSERT(otherTypedArray);
|
||||||
return false;
|
|
||||||
}
|
uint32 len = otherTypedArray->length;
|
||||||
|
JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
|
||||||
|
if (!bufobj)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
JSObject *obj = createTypedArray(cx, bufobj, 0, len);
|
||||||
|
if (!obj || !copyFrom(cx, obj, otherTypedArray, 0))
|
||||||
|
return NULL;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (obj, byteOffset, length). */
|
||||||
|
int32_t byteOffset = -1;
|
||||||
|
int32_t length = -1;
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
if (!ValueToInt32(cx, argv[1], &byteOffset))
|
||||||
|
return NULL;
|
||||||
|
if (byteOffset < 0) {
|
||||||
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
|
JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "1");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
if (!ValueToInt32(cx, argv[2], &length))
|
if (!ValueToInt32(cx, argv[2], &length))
|
||||||
return false;
|
return NULL;
|
||||||
if (length < 0) {
|
if (length < 0) {
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "2");
|
JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "2");
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tarray = cx->create<ThisTypeArray>();
|
|
||||||
if (!tarray) {
|
|
||||||
JS_ReportOutOfMemory(cx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tarray->init(cx, &argv[0].toObject(), byteOffset, length)) {
|
|
||||||
cx->destroy<ThisTypeArray>(tarray);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
||||||
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rval->setObject(*obj);
|
/* (obj, byteOffset, length) */
|
||||||
return makeFastWithPrivate(cx, obj, tarray);
|
return createTypedArrayWithOffsetLength(cx, dataObj, byteOffset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -875,25 +890,11 @@ class TypedArrayTemplate
|
||||||
if (begin > end)
|
if (begin > end)
|
||||||
begin = end;
|
begin = end;
|
||||||
|
|
||||||
ThisTypeArray *ntarray = tarray->subarray(cx, begin, end);
|
JSObject *nobj = createSubarray(cx, tarray, begin, end);
|
||||||
if (!ntarray) {
|
if (!nobj)
|
||||||
// this should rarely ever happen
|
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
||||||
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// note the usage of NewObject here -- we don't want the
|
|
||||||
// constructor to be called!
|
|
||||||
JS_ASSERT(slowClass() != &js_FunctionClass);
|
|
||||||
JSObject *nobj = NewNonFunction<WithProto::Class>(cx, slowClass(), NULL, NULL);
|
|
||||||
if (!nobj) {
|
|
||||||
cx->destroy<ThisTypeArray>(ntarray);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
vp->setObject(*nobj);
|
vp->setObject(*nobj);
|
||||||
return makeFastWithPrivate(cx, nobj, ntarray);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set(array[, offset]) */
|
/* set(array[, offset]) */
|
||||||
|
@ -920,14 +921,14 @@ class TypedArrayTemplate
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// these are the default values
|
// these are the default values
|
||||||
int32_t offset = 0;
|
int32_t off = 0;
|
||||||
|
|
||||||
Value *argv = JS_ARGV(cx, vp);
|
Value *argv = JS_ARGV(cx, vp);
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
if (!ValueToInt32(cx, argv[1], &offset))
|
if (!ValueToInt32(cx, argv[1], &off))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (offset < 0 || uint32_t(offset) > tarray->length) {
|
if (off < 0 || uint32_t(off) > tarray->length) {
|
||||||
// the given offset is bogus
|
// the given offset is bogus
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||||
|
@ -935,6 +936,8 @@ class TypedArrayTemplate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 offset(off);
|
||||||
|
|
||||||
// first arg must be either a typed array or a JS array
|
// first arg must be either a typed array or a JS array
|
||||||
if (argc == 0 || !argv[0].isObject()) {
|
if (argc == 0 || !argv[0].isObject()) {
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
|
@ -953,7 +956,7 @@ class TypedArrayTemplate
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tarray->copyFrom(cx, src, offset))
|
if (!copyFrom(cx, obj, src, offset))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
jsuint len;
|
jsuint len;
|
||||||
|
@ -967,7 +970,7 @@ class TypedArrayTemplate
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tarray->copyFrom(cx, arg0, len, offset))
|
if (!copyFrom(cx, obj, arg0, len, offset))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -982,53 +985,44 @@ class TypedArrayTemplate
|
||||||
return reinterpret_cast<ThisTypeArray*>(obj->getPrivate());
|
return reinterpret_cast<ThisTypeArray*>(obj->getPrivate());
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper used by both the constructor and Subarray()
|
|
||||||
static bool
|
|
||||||
makeFastWithPrivate(JSContext *cx, JSObject *obj, ThisTypeArray *tarray)
|
|
||||||
{
|
|
||||||
JS_ASSERT(obj->getClass() == slowClass());
|
|
||||||
obj->setSharedNonNativeMap();
|
|
||||||
obj->clasp = fastClass();
|
|
||||||
obj->setPrivate(tarray);
|
|
||||||
|
|
||||||
// FIXME bug 599008. make it ok to call preventExtensions here.
|
|
||||||
// Keeping the boolean signature of this method for now.
|
|
||||||
obj->flags |= JSObject::NOT_EXTENSIBLE;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TypedArrayTemplate() { }
|
TypedArrayTemplate(JSObject *bufobj, uint32 byteOffset, uint32 len)
|
||||||
|
|
||||||
bool
|
|
||||||
init(JSContext *cx, uint32 len)
|
|
||||||
{
|
{
|
||||||
|
JS_ASSERT(bufobj->getClass() == &ArrayBuffer::jsclass);
|
||||||
|
|
||||||
type = ArrayTypeID();
|
type = ArrayTypeID();
|
||||||
return createBufferWithSizeAndCount(cx, sizeof(NativeType), len);
|
bufferJS = bufobj;
|
||||||
|
buffer = ArrayBuffer::fromJSObject(bufobj);
|
||||||
|
|
||||||
|
this->byteOffset = byteOffset;
|
||||||
|
|
||||||
|
JS_ASSERT(byteOffset <= buffer->byteLength);
|
||||||
|
this->data = buffer->offsetData(byteOffset);
|
||||||
|
JS_ASSERT(buffer->data <= this->data);
|
||||||
|
JS_ASSERT(this->data <= buffer->offsetData(buffer->byteLength));
|
||||||
|
|
||||||
|
this->byteLength = len * sizeof(NativeType);
|
||||||
|
JS_ASSERT(buffer->byteLength - byteOffset >= this->byteLength);
|
||||||
|
|
||||||
|
this->length = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static JSObject *
|
||||||
init(JSContext *cx, JSObject *other, int32 byteOffsetInt = -1, int32 lengthInt = -1)
|
createTypedArrayWithOffsetLength(JSContext *cx, JSObject *other,
|
||||||
|
int32 byteOffsetInt, int32 lengthInt)
|
||||||
{
|
{
|
||||||
type = ArrayTypeID();
|
JS_ASSERT(!js_IsTypedArray(other));
|
||||||
|
|
||||||
|
/* Handle creation from an ArrayBuffer not ArrayBuffer.prototype. */
|
||||||
ArrayBuffer *abuf;
|
ArrayBuffer *abuf;
|
||||||
|
if (other->getClass() == &ArrayBuffer::jsclass &&
|
||||||
if (js_IsTypedArray(other)) {
|
|
||||||
TypedArray *tarray = TypedArray::fromJSObject(other);
|
|
||||||
JS_ASSERT(tarray);
|
|
||||||
|
|
||||||
if (!createBufferWithSizeAndCount(cx, sizeof(NativeType), tarray->length))
|
|
||||||
return false;
|
|
||||||
if (!copyFrom(cx, tarray))
|
|
||||||
return false;
|
|
||||||
} else if (other->getClass() == &ArrayBuffer::jsclass &&
|
|
||||||
((abuf = ArrayBuffer::fromJSObject(other)) != NULL)) {
|
((abuf = ArrayBuffer::fromJSObject(other)) != NULL)) {
|
||||||
uint32 boffset = (byteOffsetInt < 0) ? 0 : uint32(byteOffsetInt);
|
uint32 boffset = (byteOffsetInt < 0) ? 0 : uint32(byteOffsetInt);
|
||||||
|
|
||||||
if (boffset > abuf->byteLength || boffset % sizeof(NativeType) != 0) {
|
if (boffset > abuf->byteLength || boffset % sizeof(NativeType) != 0) {
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||||
return false; // invalid byteOffset
|
return NULL; // invalid byteOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 len;
|
uint32 len;
|
||||||
|
@ -1037,7 +1031,7 @@ class TypedArrayTemplate
|
||||||
if (len * sizeof(NativeType) != (abuf->byteLength - boffset)) {
|
if (len * sizeof(NativeType) != (abuf->byteLength - boffset)) {
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||||
return false; // given byte array doesn't map exactly to sizeof(NativeType)*N
|
return NULL; // given byte array doesn't map exactly to sizeof(NativeType)*N
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
len = (uint32) lengthInt;
|
len = (uint32) lengthInt;
|
||||||
|
@ -1050,32 +1044,34 @@ class TypedArrayTemplate
|
||||||
{
|
{
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||||
return false; // overflow occurred along the way when calculating boffset+len*sizeof(NativeType)
|
return NULL; // overflow occurred along the way when calculating boffset+len*sizeof(NativeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arrayByteLength + boffset > abuf->byteLength) {
|
if (arrayByteLength + boffset > abuf->byteLength) {
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||||
return false; // boffset+len is too big for the arraybuffer
|
return NULL; // boffset+len is too big for the arraybuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = abuf;
|
return createTypedArray(cx, other, boffset, len);
|
||||||
bufferJS = other;
|
|
||||||
byteOffset = boffset;
|
|
||||||
byteLength = arrayByteLength;
|
|
||||||
length = len;
|
|
||||||
data = abuf->offsetData(boffset);
|
|
||||||
} else {
|
|
||||||
jsuint len;
|
|
||||||
if (!js_GetLengthProperty(cx, other, &len))
|
|
||||||
return false;
|
|
||||||
if (!createBufferWithSizeAndCount(cx, sizeof(NativeType), len))
|
|
||||||
return false;
|
|
||||||
if (!copyFrom(cx, other, len))
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
/*
|
||||||
|
* Otherwise create a new typed array and copy len properties from the
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
jsuint len;
|
||||||
|
if (!js_GetLengthProperty(cx, other, &len))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
|
||||||
|
if (!bufobj)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
JSObject *obj = createTypedArray(cx, bufobj, 0, len);
|
||||||
|
if (!obj || !copyFrom(cx, obj, other, len))
|
||||||
|
return NULL;
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NativeType
|
const NativeType
|
||||||
|
@ -1092,25 +1088,26 @@ class TypedArrayTemplate
|
||||||
|
|
||||||
inline void copyIndexToValue(JSContext *cx, uint32 index, Value *vp);
|
inline void copyIndexToValue(JSContext *cx, uint32 index, Value *vp);
|
||||||
|
|
||||||
ThisTypeArray *
|
static JSObject *
|
||||||
subarray(JSContext *cx, uint32 begin, uint32 end)
|
createSubarray(JSContext *cx, ThisTypeArray *tarray, uint32 begin, uint32 end)
|
||||||
{
|
{
|
||||||
if (begin > length || end > length)
|
JS_ASSERT(tarray);
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ThisTypeArray *tarray = cx->create<ThisTypeArray>();
|
JS_ASSERT(0 <= begin);
|
||||||
if (!tarray)
|
JS_ASSERT(begin <= tarray->length);
|
||||||
return NULL;
|
JS_ASSERT(0 <= end);
|
||||||
|
JS_ASSERT(end <= tarray->length);
|
||||||
|
|
||||||
tarray->buffer = buffer;
|
JSObject *bufobj = tarray->bufferJS;
|
||||||
tarray->bufferJS = bufferJS;
|
JS_ASSERT(bufobj);
|
||||||
tarray->byteOffset = byteOffset + begin * sizeof(NativeType);
|
|
||||||
tarray->byteLength = (end - begin) * sizeof(NativeType);
|
|
||||||
tarray->length = end - begin;
|
|
||||||
tarray->type = type;
|
|
||||||
tarray->data = buffer->offsetData(tarray->byteOffset);
|
|
||||||
|
|
||||||
return tarray;
|
JS_ASSERT(begin <= end);
|
||||||
|
uint32 length = end - begin;
|
||||||
|
|
||||||
|
JS_ASSERT(begin < UINT32_MAX / sizeof(NativeType));
|
||||||
|
uint32 byteOffset = begin * sizeof(NativeType);
|
||||||
|
|
||||||
|
return createTypedArray(cx, bufobj, byteOffset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -1139,12 +1136,16 @@ class TypedArrayTemplate
|
||||||
return NativeType(int32(0));
|
return NativeType(int32(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static bool
|
||||||
copyFrom(JSContext *cx, JSObject *ar, jsuint len, jsuint offset = 0)
|
copyFrom(JSContext *cx, JSObject *thisTypedArrayObj,
|
||||||
|
JSObject *ar, jsuint len, jsuint offset = 0)
|
||||||
{
|
{
|
||||||
JS_ASSERT(offset <= length);
|
ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj);
|
||||||
JS_ASSERT(len <= length - offset);
|
JS_ASSERT(thisTypedArray);
|
||||||
NativeType *dest = static_cast<NativeType*>(data) + offset;
|
|
||||||
|
JS_ASSERT(offset <= thisTypedArray->length);
|
||||||
|
JS_ASSERT(len <= thisTypedArray->length - offset);
|
||||||
|
NativeType *dest = static_cast<NativeType*>(thisTypedArray->data) + offset;
|
||||||
|
|
||||||
if (ar->isDenseArray() && ar->getDenseArrayCapacity() >= len) {
|
if (ar->isDenseArray() && ar->getDenseArrayCapacity() >= len) {
|
||||||
JS_ASSERT(ar->getArrayLength() == len);
|
JS_ASSERT(ar->getArrayLength() == len);
|
||||||
|
@ -1167,17 +1168,20 @@ class TypedArrayTemplate
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static bool
|
||||||
copyFrom(JSContext *cx, TypedArray *tarray, jsuint offset = 0)
|
copyFrom(JSContext *cx, JSObject *thisTypedArrayObj, TypedArray *tarray, jsuint offset)
|
||||||
{
|
{
|
||||||
JS_ASSERT(offset <= length);
|
ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj);
|
||||||
JS_ASSERT(tarray->length <= length - offset);
|
JS_ASSERT(thisTypedArray);
|
||||||
if (tarray->buffer == buffer)
|
|
||||||
return copyFromWithOverlap(cx, tarray, offset);
|
|
||||||
|
|
||||||
NativeType *dest = static_cast<NativeType*>(data) + offset;
|
JS_ASSERT(offset <= thisTypedArray->length);
|
||||||
|
JS_ASSERT(tarray->length <= thisTypedArray->length - offset);
|
||||||
|
if (tarray->buffer == thisTypedArray->buffer)
|
||||||
|
return thisTypedArray->copyFromWithOverlap(cx, tarray, offset);
|
||||||
|
|
||||||
if (tarray->type == type) {
|
NativeType *dest = static_cast<NativeType*>(thisTypedArray->data) + offset;
|
||||||
|
|
||||||
|
if (tarray->type == thisTypedArray->type) {
|
||||||
memcpy(dest, tarray->data, tarray->byteLength);
|
memcpy(dest, tarray->data, tarray->byteLength);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1242,7 +1246,7 @@ class TypedArrayTemplate
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
copyFromWithOverlap(JSContext *cx, TypedArray *tarray, jsuint offset = 0)
|
copyFromWithOverlap(JSContext *cx, TypedArray *tarray, jsuint offset)
|
||||||
{
|
{
|
||||||
JS_ASSERT(offset <= length);
|
JS_ASSERT(offset <= length);
|
||||||
|
|
||||||
|
@ -1255,11 +1259,9 @@ class TypedArrayTemplate
|
||||||
|
|
||||||
// We have to make a copy of the source array here, since
|
// We have to make a copy of the source array here, since
|
||||||
// there's overlap, and we have to convert types.
|
// there's overlap, and we have to convert types.
|
||||||
void *srcbuf = js_malloc(tarray->byteLength);
|
void *srcbuf = cx->malloc(tarray->byteLength);
|
||||||
if (!srcbuf) {
|
if (!srcbuf)
|
||||||
js_ReportOutOfMemory(cx);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
memcpy(srcbuf, tarray->data, tarray->byteLength);
|
memcpy(srcbuf, tarray->data, tarray->byteLength);
|
||||||
|
|
||||||
switch (tarray->type) {
|
switch (tarray->type) {
|
||||||
|
@ -1321,11 +1323,10 @@ class TypedArrayTemplate
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static JSObject *
|
||||||
createBufferWithSizeAndCount(JSContext *cx, uint32 size, uint32 count)
|
createBufferWithSizeAndCount(JSContext *cx, uint32 count)
|
||||||
{
|
{
|
||||||
JS_ASSERT(size != 0);
|
size_t size = sizeof(NativeType);
|
||||||
|
|
||||||
if (size != 0 && count >= INT32_MAX / size) {
|
if (size != 0 && count >= INT32_MAX / size) {
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
JSMSG_NEED_DIET, "size and count");
|
JSMSG_NEED_DIET, "size and count");
|
||||||
|
@ -1333,30 +1334,7 @@ class TypedArrayTemplate
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 bytelen = size * count;
|
int32 bytelen = size * count;
|
||||||
if (!createBufferWithByteLength(cx, bytelen))
|
return ArrayBuffer::create(cx, bytelen);
|
||||||
return false;
|
|
||||||
|
|
||||||
length = count;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
createBufferWithByteLength(JSContext *cx, int32 bytes)
|
|
||||||
{
|
|
||||||
Value arg = Int32Value(bytes), rval;
|
|
||||||
if (!ArrayBuffer::create(cx, 1, &arg, &rval))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
JSObject *obj = &rval.toObject();
|
|
||||||
|
|
||||||
bufferJS = obj;
|
|
||||||
buffer = ArrayBuffer::fromJSObject(obj);
|
|
||||||
|
|
||||||
byteOffset = 0;
|
|
||||||
byteLength = bytes;
|
|
||||||
data = buffer->data;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1650,42 +1628,39 @@ js_IsTypedArray(JSObject *obj)
|
||||||
JS_FRIEND_API(JSObject *)
|
JS_FRIEND_API(JSObject *)
|
||||||
js_CreateArrayBuffer(JSContext *cx, jsuint nbytes)
|
js_CreateArrayBuffer(JSContext *cx, jsuint nbytes)
|
||||||
{
|
{
|
||||||
Value arg = NumberValue(nbytes), rval;
|
return ArrayBuffer::create(cx, nbytes);
|
||||||
if (!ArrayBuffer::create(cx, 1, &arg, &rval))
|
|
||||||
return NULL;
|
|
||||||
return &rval.toObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline JSBool
|
static inline JSObject *
|
||||||
TypedArrayConstruct(JSContext *cx, jsint atype, uintN argc, Value *argv, Value *rv)
|
TypedArrayConstruct(JSContext *cx, jsint atype, uintN argc, Value *argv)
|
||||||
{
|
{
|
||||||
switch (atype) {
|
switch (atype) {
|
||||||
case TypedArray::TYPE_INT8:
|
case TypedArray::TYPE_INT8:
|
||||||
return Int8Array::create(cx, argc, argv, rv);
|
return Int8Array::create(cx, argc, argv);
|
||||||
|
|
||||||
case TypedArray::TYPE_UINT8:
|
case TypedArray::TYPE_UINT8:
|
||||||
return Uint8Array::create(cx, argc, argv, rv);
|
return Uint8Array::create(cx, argc, argv);
|
||||||
|
|
||||||
case TypedArray::TYPE_INT16:
|
case TypedArray::TYPE_INT16:
|
||||||
return Int16Array::create(cx, argc, argv, rv);
|
return Int16Array::create(cx, argc, argv);
|
||||||
|
|
||||||
case TypedArray::TYPE_UINT16:
|
case TypedArray::TYPE_UINT16:
|
||||||
return Uint16Array::create(cx, argc, argv, rv);
|
return Uint16Array::create(cx, argc, argv);
|
||||||
|
|
||||||
case TypedArray::TYPE_INT32:
|
case TypedArray::TYPE_INT32:
|
||||||
return Int32Array::create(cx, argc, argv, rv);
|
return Int32Array::create(cx, argc, argv);
|
||||||
|
|
||||||
case TypedArray::TYPE_UINT32:
|
case TypedArray::TYPE_UINT32:
|
||||||
return Uint32Array::create(cx, argc, argv, rv);
|
return Uint32Array::create(cx, argc, argv);
|
||||||
|
|
||||||
case TypedArray::TYPE_FLOAT32:
|
case TypedArray::TYPE_FLOAT32:
|
||||||
return Float32Array::create(cx, argc, argv, rv);
|
return Float32Array::create(cx, argc, argv);
|
||||||
|
|
||||||
case TypedArray::TYPE_FLOAT64:
|
case TypedArray::TYPE_FLOAT64:
|
||||||
return Float64Array::create(cx, argc, argv, rv);
|
return Float64Array::create(cx, argc, argv);
|
||||||
|
|
||||||
case TypedArray::TYPE_UINT8_CLAMPED:
|
case TypedArray::TYPE_UINT8_CLAMPED:
|
||||||
return Uint8ClampedArray::create(cx, argc, argv, rv);
|
return Uint8ClampedArray::create(cx, argc, argv);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
JS_NOT_REACHED("shouldn't have gotten here");
|
JS_NOT_REACHED("shouldn't have gotten here");
|
||||||
|
@ -1698,15 +1673,8 @@ js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements)
|
||||||
{
|
{
|
||||||
JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
|
JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
|
||||||
|
|
||||||
Value vals[2];
|
Value nelems = Int32Value(nelements);
|
||||||
vals[0].setInt32(nelements);
|
return TypedArrayConstruct(cx, atype, 1, &nelems);
|
||||||
vals[1].setUndefined();
|
|
||||||
|
|
||||||
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
|
|
||||||
if (!TypedArrayConstruct(cx, atype, 1, &vals[0], &vals[1]))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return &vals[1].toObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(JSObject *)
|
JS_FRIEND_API(JSObject *)
|
||||||
|
@ -1714,15 +1682,8 @@ js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg)
|
||||||
{
|
{
|
||||||
JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
|
JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
|
||||||
|
|
||||||
Value vals[2];
|
Value arrval = ObjectValue(*arrayArg);
|
||||||
vals[0].setObject(*arrayArg);
|
return TypedArrayConstruct(cx, atype, 1, &arrval);
|
||||||
vals[1].setUndefined();
|
|
||||||
|
|
||||||
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
|
|
||||||
if (!TypedArrayConstruct(cx, atype, 1, &vals[0], &vals[1]))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return &vals[1].toObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(JSObject *)
|
JS_FRIEND_API(JSObject *)
|
||||||
|
@ -1737,7 +1698,6 @@ js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg,
|
||||||
|
|
||||||
int argc = 1;
|
int argc = 1;
|
||||||
vals[0].setObject(*bufArg);
|
vals[0].setObject(*bufArg);
|
||||||
vals[3].setUndefined();
|
|
||||||
|
|
||||||
if (byteoffset >= 0) {
|
if (byteoffset >= 0) {
|
||||||
vals[argc].setInt32(byteoffset);
|
vals[argc].setInt32(byteoffset);
|
||||||
|
@ -1750,10 +1710,7 @@ js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg,
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
|
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
|
||||||
if (!TypedArrayConstruct(cx, atype, argc, &vals[0], &vals[3]))
|
return TypedArrayConstruct(cx, atype, argc, &vals[0]);
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return &vals[3].toObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(JSBool)
|
JS_FRIEND_API(JSBool)
|
||||||
|
|
|
@ -64,7 +64,7 @@ struct JS_FRIEND_API(ArrayBuffer) {
|
||||||
|
|
||||||
static JSBool class_constructor(JSContext *cx, uintN argc, Value *vp);
|
static JSBool class_constructor(JSContext *cx, uintN argc, Value *vp);
|
||||||
|
|
||||||
static bool create(JSContext *cx, uintN argc, Value *argv, Value *rval);
|
static JSObject *create(JSContext *cx, int32 nbytes);
|
||||||
|
|
||||||
static ArrayBuffer *fromJSObject(JSObject *obj);
|
static ArrayBuffer *fromJSObject(JSObject *obj);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче