mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
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:
parent
90406e4550
commit
7c9f81a176
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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); }
|
||||
|
@ -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();
|
||||
return obj;
|
||||
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;
|
||||
// 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);
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t offset = 0;
|
||||
if (args.length() > 1) {
|
||||
if (!ToInt32(cx, args[1], &off))
|
||||
if (!ToInt32(cx, args[1], &offset))
|
||||
return false;
|
||||
|
||||
if (off < 0 || uint32_t(off) > getLength(tarray)) {
|
||||
if (offset < 0 || uint32_t(offset) > getLength(tarray)) {
|
||||
// the given offset is bogus
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_INDEX, "2");
|
||||
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);
|
||||
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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 object’s
|
||||
// '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);
|
||||
|
Loading…
Reference in New Issue
Block a user