Bug 741039 - Modify TypedArrays and ArrayBuffers to comply with the WebIDL spec. r=Waldo

WebIDL 4.4.6 says Float32Array.prototype is not a platform object and should throw TypeErrors when any of the Float32Array attributes is accessed. This patch makes obj->isTypedArray only succeed for actual TypedArray instances, and adds TypeErrors when special properties are retrieved from the prototypes.

This patch also eliminates some lingering uses of TypedArray::getTypedArray and makes it and getArrayBuffer static within jstypedarray.cpp. (Both are used for objects whose prototypes are typed arrays or array buffers.)

--HG--
extra : rebase_source : 93032b5c8dc98c4e18eec4fa438f6a9a4173487d
This commit is contained in:
Steve Fink 2012-04-23 15:13:02 -07:00
parent 3250e70d87
commit 7aee790f0d
10 changed files with 200 additions and 188 deletions

View File

@ -1741,7 +1741,7 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj)
}
#define CLASP(name) (&name##Class)
#define TYPED_ARRAY_CLASP(type) (&TypedArray::fastClasses[TypedArray::type])
#define TYPED_ARRAY_CLASP(type) (&TypedArray::classes[TypedArray::type])
#define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
#define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
#define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)

View File

@ -434,9 +434,8 @@ JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v)
}
bool
JSStructuredCloneWriter::writeTypedArray(JSObject *obj)
JSStructuredCloneWriter::writeTypedArray(JSObject *arr)
{
JSObject *arr = TypedArray::getTypedArray(obj);
if (!out.writePair(ArrayTypeToTag(TypedArray::getType(arr)), TypedArray::getLength(arr)))
return false;
@ -750,27 +749,26 @@ JSStructuredCloneReader::readTypedArray(uint32_t tag, uint32_t nelems, Value *vp
return false;
vp->setObject(*obj);
JSObject *arr = TypedArray::getTypedArray(obj);
JS_ASSERT(TypedArray::getLength(arr) == nelems);
JS_ASSERT(TypedArray::getLength(obj) == nelems);
switch (tag) {
case SCTAG_TYPED_ARRAY_INT8:
return in.readArray((uint8_t *) JS_GetInt8ArrayData(arr, context()), nelems);
return in.readArray((uint8_t*) JS_GetInt8ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_UINT8:
return in.readArray((uint8_t *) JS_GetUint8ArrayData(arr, context()), nelems);
return in.readArray(JS_GetUint8ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_INT16:
return in.readArray((uint16_t *) JS_GetInt16ArrayData(arr, context()), nelems);
return in.readArray((uint16_t*) JS_GetInt16ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_UINT16:
return in.readArray((uint16_t *) JS_GetUint16ArrayData(arr, context()), nelems);
return in.readArray(JS_GetUint16ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_INT32:
return in.readArray((uint32_t *) JS_GetInt32ArrayData(arr, context()), nelems);
return in.readArray((uint32_t*) JS_GetInt32ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_UINT32:
return in.readArray((uint32_t *) JS_GetUint32ArrayData(arr, context()), nelems);
return in.readArray(JS_GetUint32ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_FLOAT32:
return in.readArray((uint32_t *) JS_GetFloat32ArrayData(arr, context()), nelems);
return in.readArray((uint32_t*) JS_GetFloat32ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_FLOAT64:
return in.readArray((uint64_t *) JS_GetFloat64ArrayData(arr, context()), nelems);
return in.readArray((uint64_t*) JS_GetFloat64ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_UINT8_CLAMPED:
return in.readArray((uint8_t *) JS_GetUint8ClampedArrayData(arr, context()), nelems);
return in.readArray(JS_GetUint8ClampedArrayData(obj, context()), nelems);
default:
JS_NOT_REACHED("unknown TypedArray type");
return false;

View File

@ -233,8 +233,7 @@ GetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, Value *vp
}
if (obj->isTypedArray()) {
JSObject *tarray = TypedArray::getTypedArray(obj);
*vp = Int32Value(TypedArray::getLength(tarray));
*vp = Int32Value(TypedArray::getLength(obj));
return true;
}
}

View File

@ -811,7 +811,7 @@ inline bool JSObject::isStaticBlock() const { return isBlock() && !getProto(); }
inline bool JSObject::isStopIteration() const { return hasClass(&js::StopIterationClass); }
inline bool JSObject::isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); }
inline bool JSObject::isString() const { return hasClass(&js::StringClass); }
inline bool JSObject::isTypedArray() const { return IsFastTypedArrayClass(getClass()); }
inline bool JSObject::isTypedArray() const { return IsTypedArrayClass(getClass()); }
inline bool JSObject::isWeakMap() const { return hasClass(&js::WeakMapClass); }
inline bool JSObject::isWith() const { return hasClass(&js::WithClass); }
inline bool JSObject::isXML() const { return hasClass(&js::XMLClass); }

View File

@ -138,29 +138,27 @@ ToClampedIndex(JSContext *cx, const Value &v, int32_t length, int32_t *out)
*/
/**
* Walks up the prototype chain to find the actual ArrayBuffer data.
* This MAY return NULL. Callers should always use isArrayBuffer()
* first.
* Walks up the prototype chain to find the actual ArrayBuffer data, if any.
*/
JSObject *
ArrayBufferObject::getArrayBuffer(JSObject *obj)
static ArrayBufferObject *
getArrayBuffer(JSObject *obj)
{
while (obj && !obj->isArrayBuffer())
obj = obj->getProto();
return obj;
return obj ? &obj->asArrayBuffer() : NULL;
}
JSBool
ArrayBufferObject::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
JSObject *bufobj = getArrayBuffer(obj);
if (!bufobj) {
vp->setInt32(0);
return true;
ArrayBufferObject *buffer = getArrayBuffer(obj);
if (!buffer) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, "ArrayBuffer", "byteLength", "object");
return false;
}
ArrayBufferObject &arrayBuffer = bufobj->asArrayBuffer();
vp->setInt32(int32_t(arrayBuffer.byteLength()));
vp->setInt32(int32_t(buffer->byteLength()));
return true;
}
@ -505,7 +503,15 @@ ArrayBufferObject::obj_getProperty(JSContext *cx, JSObject *obj_,
RootedVarObject obj(cx, obj_), receiver(cx, receiver_);
RootedVarPropertyName name(cx, name_);
obj = getArrayBuffer(obj);
if (!(obj = getArrayBuffer(obj))) {
JSAutoByteString bs(cx, name);
if (!bs)
return false;
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, "ArrayBuffer", bs.ptr(), "object");
return false;
}
if (name == cx->runtime->atomState.byteLengthAtom) {
vp->setInt32(obj->asArrayBuffer().byteLength());
return true;
@ -787,12 +793,15 @@ ArrayBufferObject::obj_typeOf(JSContext *cx, JSObject *obj)
* the subclasses.
*/
JSObject *
TypedArray::getTypedArray(JSObject *obj)
static JSObject *
getTypedArray(JSObject *obj)
{
while (!obj->isTypedArray())
obj = obj->getProto();
MOZ_ASSERT(obj);
do {
if (obj->isTypedArray())
return obj;
} while ((obj = obj->getProto()));
return NULL;
}
inline bool
@ -808,75 +817,60 @@ TypedArray::isArrayIndex(JSContext *cx, JSObject *obj, jsid id, uint32_t *ip)
return false;
}
typedef Value (* TypedArrayPropertyGetter)(JSObject *tarray);
template <TypedArrayPropertyGetter Get>
class TypedArrayGetter {
public:
static inline bool get(JSContext *cx, JSObject *obj, jsid id, Value *vp) {
do {
if (obj->isTypedArray()) {
JSObject *tarray = TypedArray::getTypedArray(obj);
if (tarray)
*vp = Get(tarray);
return true;
}
} while ((obj = obj->getProto()) != NULL);
return true;
}
};
/*
* For now (until slots directly hold data)
* slots data element points to the JSObject representing the ArrayBuffer.
*/
inline Value
getBufferValue(JSObject *tarray)
{
JSObject *buffer = TypedArray::getBuffer(tarray);
return ObjectValue(*buffer);
}
JSBool
TypedArray::prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return TypedArrayGetter<getBufferValue>::get(cx, obj, id, vp);
}
if (!(obj = getTypedArray(obj))) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, "TypedArray", "buffer", "object");
return false;
}
inline Value
getByteOffsetValue(JSObject *tarray)
{
return Int32Value(TypedArray::getByteOffset(tarray));
JS_SET_RVAL(cx, vp, ObjectValue(*TypedArray::getBuffer(obj)));
return true;
}
JSBool
TypedArray::prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return TypedArrayGetter<getByteOffsetValue>::get(cx, obj, id, vp);
}
if (!(obj = getTypedArray(obj))) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, "TypedArray", "byteOffset", "object");
return false;
}
inline Value
getByteLengthValue(JSObject *tarray)
{
return Int32Value(TypedArray::getByteLength(tarray));
JS_SET_RVAL(cx, vp, Int32Value(TypedArray::getByteOffset(obj)));
return true;
}
JSBool
TypedArray::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return TypedArrayGetter<getByteLengthValue>::get(cx, obj, id, vp);
}
if (!(obj = getTypedArray(obj))) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, "TypedArray", "byteLength", "object");
return false;
}
inline Value
getLengthValue(JSObject *tarray)
{
return Int32Value(TypedArray::getLength(tarray));
JS_SET_RVAL(cx, vp, Int32Value(TypedArray::getByteLength(obj)));
return true;
}
JSBool
TypedArray::prop_getLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return TypedArrayGetter<getLengthValue>::get(cx, obj, id, vp);
if (!(obj = getTypedArray(obj))) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, "TypedArray", "length", "object");
return false;
}
JS_SET_RVAL(cx, vp, Int32Value(TypedArray::getLength(obj)));
return true;
}
JSBool
@ -1090,7 +1084,7 @@ class TypedArrayTemplate
static inline Class *fastClass()
{
return &TypedArray::fastClasses[ArrayTypeID()];
return &TypedArray::classes[ArrayTypeID()];
}
static void
@ -1354,7 +1348,7 @@ class TypedArrayTemplate
static JSBool
obj_deleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict)
{
JSObject *tarray = TypedArray::getTypedArray(obj);
JSObject *tarray = getTypedArray(obj);
JS_ASSERT(tarray);
if (index < getLength(tarray)) {
@ -1627,56 +1621,52 @@ class TypedArrayTemplate
if (!tarray)
return true;
// these are the default values
int32_t off = 0;
if (args.length() > 1) {
if (!ToInt32(cx, args[1], &off))
return false;
if (off < 0 || uint32_t(off) > getLength(tarray)) {
// the given offset is bogus
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
}
uint32_t offset(off);
// first arg must be either a typed array or a JS array
if (args.length() == 0 || !args[0].isObject()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_TYPED_ARRAY_BAD_ARGS);
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
int32_t offset = 0;
if (args.length() > 1) {
if (!ToInt32(cx, args[1], &offset))
return false;
if (offset < 0 || uint32_t(offset) > getLength(tarray)) {
// the given offset is bogus
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_INDEX, "2");
return false;
}
}
if (!args[0].isObject()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
RootedVarObject arg0(cx, args[0].toObjectOrNull());
if (arg0->isTypedArray()) {
JSObject *src = TypedArray::getTypedArray(arg0);
if (!src ||
getLength(src) > getLength(tarray) - offset)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_TYPED_ARRAY_BAD_ARGS);
RootedVarObject src(getTypedArray(arg0));
if (src) {
if (getLength(src) > getLength(tarray) - offset) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
return false;
}
if (!copyFromTypedArray(cx, obj, src, offset))
return false;
} else {
src = arg0;
uint32_t len;
if (!js_GetLengthProperty(cx, arg0, &len))
if (!js_GetLengthProperty(cx, src, &len))
return false;
// avoid overflow; we know that offset <= length
if (len > getLength(tarray) - offset) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_TYPED_ARRAY_BAD_ARGS);
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
return false;
}
if (!copyFromArray(cx, obj, arg0, len, offset))
if (!copyFromArray(cx, obj, src, len, offset))
return false;
}
@ -2145,10 +2135,7 @@ TypedArrayTemplate<float>::copyIndexToValue(JSContext *cx, JSObject *tarray, uin
* This could be removed for platforms/compilers known to convert a 32-bit
* non-canonical nan to a 64-bit canonical nan.
*/
if (JS_UNLIKELY(MOZ_DOUBLE_IS_NaN(dval)))
dval = js_NaN;
vp->setDouble(dval);
vp->setDouble(JS_CANONICALIZE_NAN(dval));
}
template<>
@ -2335,7 +2322,7 @@ NewArrayWithBuffer(JSContext *cx, HandleObject arrayBuffer, int32_t byteoffset,
{ \
obj = UnwrapObject(obj); \
Class *clasp = obj->getClass(); \
return (clasp == &TypedArray::fastClasses[TypedArrayTemplate<NativeType>::ArrayTypeID()]); \
return (clasp == &TypedArray::classes[TypedArrayTemplate<NativeType>::ArrayTypeID()]); \
}
IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int8, int8_t)
@ -2350,7 +2337,7 @@ IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float64, double)
#define IMPL_TYPED_ARRAY_PROTO_CLASS(_typedArray) \
{ \
#_typedArray, \
#_typedArray "Prototype", \
JSCLASS_HAS_RESERVED_SLOTS(TypedArray::FIELD_MAX) | \
JSCLASS_HAS_PRIVATE | \
JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray), \
@ -2475,7 +2462,7 @@ IMPL_TYPED_ARRAY_STATICS(Float32Array);
IMPL_TYPED_ARRAY_STATICS(Float64Array);
IMPL_TYPED_ARRAY_STATICS(Uint8ClampedArray);
Class TypedArray::fastClasses[TYPE_MAX] = {
Class TypedArray::classes[TYPE_MAX] = {
IMPL_TYPED_ARRAY_FAST_CLASS(Int8Array),
IMPL_TYPED_ARRAY_FAST_CLASS(Uint8Array),
IMPL_TYPED_ARRAY_FAST_CLASS(Int16Array),
@ -2554,27 +2541,6 @@ js_InitTypedArrayClasses(JSContext *cx, JSObject *obj)
return InitArrayBufferClass(cx, global);
}
bool
js::IsFastTypedArrayClass(const Class *clasp)
{
return &TypedArray::fastClasses[0] <= clasp &&
clasp < &TypedArray::fastClasses[TypedArray::TYPE_MAX];
}
static inline bool
IsSlowTypedArrayClass(const Class *clasp)
{
return &TypedArray::protoClasses[0] <= clasp &&
clasp < &TypedArray::protoClasses[TypedArray::TYPE_MAX];
}
bool
js::IsFastOrSlowTypedArray(JSObject *obj)
{
Class *clasp = obj->getClass();
return IsFastTypedArrayClass(clasp) || IsSlowTypedArrayClass(clasp);
}
/* JS Friend API */
JS_FRIEND_API(JSBool)

View File

@ -161,9 +161,6 @@ class ArrayBufferObject : public JSObject
static JSType
obj_typeOf(JSContext *cx, JSObject *obj);
static JSObject *
getArrayBuffer(JSObject *obj);
bool
allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents = NULL);
@ -218,7 +215,7 @@ struct TypedArray {
};
// and MUST NOT be used to construct new objects.
static Class fastClasses[TYPE_MAX];
static Class classes[TYPE_MAX];
// These are the proto/original classes, used
// fo constructing new objects
@ -226,8 +223,6 @@ struct TypedArray {
static JSPropertySpec jsprops[];
static JSObject *getTypedArray(JSObject *obj);
static JSBool prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp);
static JSBool prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp);
static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp);
@ -292,14 +287,31 @@ struct TypedArray {
static int dataOffset();
};
bool
IsFastOrSlowTypedArray(JSObject *obj);
inline bool
IsTypedArrayClass(const Class *clasp)
{
return &TypedArray::classes[0] <= clasp &&
clasp < &TypedArray::classes[TypedArray::TYPE_MAX];
}
bool
IsFastOrSlowTypedArrayClass(const Class *clasp);
inline bool
IsTypedArrayProtoClass(const Class *clasp)
{
return &TypedArray::protoClasses[0] <= clasp &&
clasp < &TypedArray::protoClasses[TypedArray::TYPE_MAX];
}
bool
IsFastTypedArrayClass(const Class *clasp);
inline bool
IsTypedArray(JSObject *obj)
{
return IsTypedArrayClass(obj->getClass());
}
inline bool
IsTypedArrayProto(JSObject *obj)
{
return IsTypedArrayProtoClass(obj->getClass());
}
} // namespace js

View File

@ -83,37 +83,37 @@ ClampIntForUint8Array(int32_t x)
inline uint32_t
TypedArray::getLength(JSObject *obj) {
JS_ASSERT(IsFastOrSlowTypedArray(obj));
JS_ASSERT(obj->isTypedArray());
return obj->getFixedSlot(FIELD_LENGTH).toInt32();
}
inline uint32_t
TypedArray::getByteOffset(JSObject *obj) {
JS_ASSERT(IsFastOrSlowTypedArray(obj));
JS_ASSERT(obj->isTypedArray());
return obj->getFixedSlot(FIELD_BYTEOFFSET).toInt32();
}
inline uint32_t
TypedArray::getByteLength(JSObject *obj) {
JS_ASSERT(IsFastOrSlowTypedArray(obj));
JS_ASSERT(obj->isTypedArray());
return obj->getFixedSlot(FIELD_BYTELENGTH).toInt32();
}
inline uint32_t
TypedArray::getType(JSObject *obj) {
JS_ASSERT(IsFastOrSlowTypedArray(obj));
JS_ASSERT(obj->isTypedArray());
return obj->getFixedSlot(FIELD_TYPE).toInt32();
}
inline ArrayBufferObject *
TypedArray::getBuffer(JSObject *obj) {
JS_ASSERT(IsFastOrSlowTypedArray(obj));
JS_ASSERT(obj->isTypedArray());
return &obj->getFixedSlot(FIELD_BUFFER).toObject().asArrayBuffer();
}
inline void *
TypedArray::getDataOffset(JSObject *obj) {
JS_ASSERT(IsFastOrSlowTypedArray(obj));
JS_ASSERT(obj->isTypedArray());
return (void *)obj->getPrivate(NUM_FIXED_SLOTS);
}

View File

@ -2319,17 +2319,16 @@ GetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, const Value &v, jsid i
? Int32Key::FromConstant(v.toInt32())
: Int32Key::FromRegister(idRemat.dataReg());
JSObject *tarray = js::TypedArray::getTypedArray(obj);
if (!masm.supportsFloatingPoint() &&
(TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32 ||
TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT64 ||
TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT32))
(TypedArray::getType(obj) == TypedArray::TYPE_FLOAT32 ||
TypedArray::getType(obj) == TypedArray::TYPE_FLOAT64 ||
TypedArray::getType(obj) == TypedArray::TYPE_UINT32))
{
return disable(f, "fpu not supported");
}
MaybeRegisterID tempReg;
masm.loadFromTypedArray(TypedArray::getType(tarray), objReg, key, typeReg, objReg, tempReg);
masm.loadFromTypedArray(TypedArray::getType(obj), objReg, key, typeReg, objReg, tempReg);
Jump done = masm.jump();
@ -2633,18 +2632,17 @@ SetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, int32_t key)
// Load the array's packed data vector.
masm.loadPtr(Address(objReg, TypedArray::dataOffset()), objReg);
JSObject *tarray = js::TypedArray::getTypedArray(obj);
if (!masm.supportsFloatingPoint() &&
(TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32 ||
TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT64))
(TypedArray::getType(obj) == TypedArray::TYPE_FLOAT32 ||
TypedArray::getType(obj) == TypedArray::TYPE_FLOAT64))
{
return disable(f, "fpu not supported");
}
int shift = js::TypedArray::slotWidth(obj);
int shift = TypedArray::slotWidth(obj);
if (hasConstantKey) {
Address addr(objReg, keyValue * shift);
if (!StoreToTypedArray(cx, masm, tarray, addr, vr, volatileMask))
if (!StoreToTypedArray(cx, masm, obj, addr, vr, volatileMask))
return error(cx);
} else {
Assembler::Scale scale = Assembler::TimesOne;
@ -2660,7 +2658,7 @@ SetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, int32_t key)
break;
}
BaseIndex addr(objReg, keyReg, scale);
if (!StoreToTypedArray(cx, masm, tarray, addr, vr, volatileMask))
if (!StoreToTypedArray(cx, masm, obj, addr, vr, volatileMask))
return error(cx);
}

View File

@ -3409,17 +3409,16 @@ Deserialize(JSContext *cx, unsigned argc, jsval *vp)
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS, "deserialize");
return false;
}
JSObject *array = TypedArray::getTypedArray(obj);
if ((TypedArray::getByteLength(array) & 7) != 0) {
if ((TypedArray::getByteLength(obj) & 7) != 0) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS, "deserialize");
return false;
}
if ((uintptr_t(TypedArray::getDataOffset(array)) & 7) != 0) {
if ((uintptr_t(TypedArray::getDataOffset(obj)) & 7) != 0) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_BAD_ALIGNMENT);
return false;
}
if (!JS_ReadStructuredClone(cx, (uint64_t *) TypedArray::getDataOffset(array), TypedArray::getByteLength(array),
if (!JS_ReadStructuredClone(cx, (uint64_t *) TypedArray::getDataOffset(obj), TypedArray::getByteLength(obj),
JS_STRUCTURED_CLONE_VERSION, v.address(), NULL, NULL)) {
return false;
}

View File

@ -28,7 +28,7 @@ function test()
var TODO = 1;
function check(fun, todo) {
function check(fun, msg, todo) {
var thrown = null;
var success = false;
try {
@ -60,6 +60,8 @@ function test()
var ex = new Error;
print ("=== FAILED ===");
if (msg)
print (msg);
print (ex.stack);
if (thrown) {
print (" threw exception:");
@ -69,18 +71,29 @@ function test()
}
}
function checkThrows(fun, todo) {
let thrown = false;
function checkThrows(fun, type, todo) {
var thrown = false;
try {
fun();
} catch (x) {
thrown = true;
thrown = x;
}
check(function() thrown, todo);
if (typeof(type) !== 'undefined')
if (thrown) {
check(function () thrown instanceof type,
"expected " + type.name + " but saw " + thrown,
todo);
} else {
check(function () thrown, "expected " + type.name + " but no exception thrown", todo);
}
else
check(function () thrown, undefined, todo);
}
check(function() ArrayBuffer.prototype.byteLength == 0);
function checkThrowsTODO(fun, type) {
checkThrows(fun, type, true);
}
var buf, buf2;
@ -101,9 +114,9 @@ function test()
var zerobuf2 = new ArrayBuffer();
check(function() zerobuf2.byteLength == 0);
checkThrows(function() new ArrayBuffer(-100));
checkThrows(function() new ArrayBuffer(-100), RangeError);
// this is using js_ValueToECMAUInt32, which is giving 0 for "abc"
checkThrows(function() new ArrayBuffer("abc"), TODO);
checkThrowsTODO(function() new ArrayBuffer("abc"), TypeError);
var zeroarray = new Int32Array(0);
check(function() zeroarray.length == 0);
@ -187,15 +200,15 @@ function test()
check(function() a[1] == 0xbb);
// not sure if this is supposed to throw or to treat "foo"" as 0.
checkThrows(function() new Int32Array([0xaa, "foo", 0xbb]), TODO);
checkThrowsTODO(function() new Int32Array([0xaa, "foo", 0xbb]), Error);
checkThrows(function() new Int32Array(-100));
a = new Uint8Array(3);
// XXX these are ignored now and return undefined
//checkThrows(function() a[5000] = 0);
//checkThrows(function() a["hello"] = 0);
//checkThrows(function() a[-10] = 0);
//checkThrows(function() a[5000] = 0, RangeError);
//checkThrows(function() a["hello"] = 0, TypeError);
//checkThrows(function() a[-10] = 0, RangeError);
check(function() (a[0] = "10") && (a[0] == 10));
// check Uint8ClampedArray, which is an extension to this extension
@ -265,8 +278,8 @@ function test()
checkThrows(function() a.set([1,2,3], 2147483647));
a.set(ArrayBuffer.prototype);
a.set(Int16Array.prototype);
a.set(Int32Array.prototype);
checkThrows(function () a.set(Int16Array.prototype), TypeError);
checkThrows(function () a.set(Int32Array.prototype), TypeError);
a.set([1,2,3]);
a.set([4,5,6], 3);
@ -317,16 +330,43 @@ function test()
a = new Uint8Array(0x100);
checkThrows(function() Uint32Array.prototype.subarray.apply(a, [0, 0x100]));
// The prototypes are objects that don't have a length property, so they act
// like empty arrays.
check(function() new Int32Array(ArrayBuffer.prototype).length == 0);
check(function() new Int32Array(Int32Array.prototype).length == 0);
check(function() new Int32Array(Float64Array.prototype).length == 0);
// webidl section 4.4.6, getter bullet point 2.2: prototypes are not
// platform objects, and calling the getter of any attribute defined on the
// interface should throw a TypeError according to
checkThrows(function() ArrayBuffer.prototype.byteLength, TypeError);
checkThrows(function() Int32Array.prototype.length, TypeError);
checkThrows(function() Int32Array.prototype.byteLength, TypeError);
checkThrows(function() Int32Array.prototype.byteOffset, TypeError);
checkThrows(function() Float64Array.prototype.length, TypeError);
checkThrows(function() Float64Array.prototype.byteLength, TypeError);
checkThrows(function() Float64Array.prototype.byteOffset, TypeError);
// ArrayBuffer, Int32Array and Float64Array are native functions and have a .length
// checkThrows(function() new Int32Array(ArrayBuffer));
// checkThrows(function() new Int32Array(Int32Array));
// checkThrows(function() new Int32Array(Float64Array));
// webidl 4.4.6: a readonly attribute's setter is undefined. From
// observation, that seems to mean it silently does nothing, and returns
// the value that you tried to set it to.
check(function() Int32Array.prototype.length = true);
check(function() Float64Array.prototype.length = true);
check(function() Int32Array.prototype.byteLength = true);
check(function() Float64Array.prototype.byteLength = true);
check(function() Int32Array.prototype.byteOffset = true);
check(function() Float64Array.prototype.byteOffset = true);
// ArrayBuffer, Int32Array and Float64Array are native functions and have a
// .length, so none of these should throw:
check(function() (new Int32Array(ArrayBuffer)).length >= 0);
check(function() (new Int32Array(Int32Array)).length >= 0);
check(function() (new Int32Array(Float64Array)).length >= 0);
// webidl 4.4.6, under getters: "The value of the Function objects
// 'length' property is the Number value 0"
//
// Except this fails in getOwnPropertyDescriptor, I think because
// Int32Array.prototype does not provide a lookup hook, and the fallback
// case ends up calling the getter. Which seems odd to me, but much of this
// stuff baffles me. It does seem strange that there's no way to do
// getOwnPropertyDescriptor on any of these attributes.
//
//check(Object.getOwnPropertyDescriptor(Int32Array.prototype, 'byteOffset')['get'].length == 0);
check(function() Int32Array.BYTES_PER_ELEMENT == 4);
check(function() (new Int32Array(4)).BYTES_PER_ELEMENT == 4);