mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1055472 - Part 14: Make the various TypedArray constructors properly subclassable. (r=Waldo)
This commit is contained in:
parent
e4d13c5d69
commit
6f08f54062
@ -1,15 +0,0 @@
|
||||
// Test that instantiating a typed array on top of a neutered buffer
|
||||
// doesn't trip any asserts.
|
||||
//
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
x = new ArrayBuffer();
|
||||
neuter(x, "same-data");
|
||||
new Uint32Array(x);
|
||||
gc();
|
||||
|
||||
x = new ArrayBuffer();
|
||||
neuter(x, "change-data");
|
||||
new Uint32Array(x);
|
||||
gc();
|
@ -14,6 +14,24 @@ function testBuiltin(builtin, ...args) {
|
||||
assertEq(instance.called, true);
|
||||
}
|
||||
|
||||
function testBuiltinTypedArrays() {
|
||||
let typedArrays = [Int8Array,
|
||||
Uint8Array,
|
||||
Uint8ClampedArray,
|
||||
Int16Array,
|
||||
Uint16Array,
|
||||
Int32Array,
|
||||
Uint32Array,
|
||||
Float32Array,
|
||||
Float64Array];
|
||||
|
||||
for (let array of typedArrays) {
|
||||
testBuiltin(array);
|
||||
testBuiltin(array, 5);
|
||||
testBuiltin(array, new array());
|
||||
testBuiltin(array, new ArrayBuffer());
|
||||
}
|
||||
}
|
||||
|
||||
testBuiltin(Function);
|
||||
testBuiltin(Object);
|
||||
@ -37,6 +55,7 @@ testBuiltin(Set);
|
||||
testBuiltin(WeakMap);
|
||||
testBuiltin(WeakSet);
|
||||
testBuiltin(ArrayBuffer);
|
||||
testBuiltinTypedArrays();
|
||||
|
||||
`;
|
||||
|
||||
|
27
js/src/tests/ecma_6/TypedArray/constructor-non-detached.js
Normal file
27
js/src/tests/ecma_6/TypedArray/constructor-non-detached.js
Normal file
@ -0,0 +1,27 @@
|
||||
const constructors = [
|
||||
Int8Array,
|
||||
Uint8Array,
|
||||
Uint8ClampedArray,
|
||||
Int16Array,
|
||||
Uint16Array,
|
||||
Int32Array,
|
||||
Uint32Array,
|
||||
Float32Array,
|
||||
Float64Array
|
||||
];
|
||||
|
||||
for (var constructor of constructors) {
|
||||
for (var neuterType of ["change-data", "same-data"]) {
|
||||
var buf = new constructor();
|
||||
neuter(buf.buffer, neuterType);
|
||||
assertThrowsInstanceOf(()=> new constructor(buf), TypeError);
|
||||
|
||||
var buffer = new ArrayBuffer();
|
||||
neuter(buffer, neuterType);
|
||||
assertThrowsInstanceOf(()=> new constructor(buffer), TypeError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
@ -141,6 +141,17 @@ IsAnyTypedArrayClass(const Class* clasp)
|
||||
return IsTypedArrayClass(clasp) || IsSharedTypedArrayClass(clasp);
|
||||
}
|
||||
|
||||
inline bool
|
||||
AnyTypedArrayIsDetached(const JSObject* obj)
|
||||
{
|
||||
if (obj->is<TypedArrayObject>()) {
|
||||
ArrayBufferObject* buffer = obj->as<TypedArrayObject>().buffer();
|
||||
return buffer && buffer->isNeutered();
|
||||
}
|
||||
// You cannoy detatch a shared array buffer
|
||||
return false;
|
||||
}
|
||||
|
||||
class SharedOps
|
||||
{
|
||||
public:
|
||||
|
@ -182,6 +182,20 @@ NewArray(JSContext* cx, uint32_t nelements);
|
||||
|
||||
namespace {
|
||||
|
||||
// We allow nullptr for newTarget for all the creation methods, to allow for
|
||||
// JSFriendAPI functions that don't care about subclassing
|
||||
static bool
|
||||
GetPrototypeForInstance(JSContext* cx, HandleObject newTarget, MutableHandleObject proto)
|
||||
{
|
||||
if (newTarget) {
|
||||
if (!GetPrototypeFromConstructor(cx, newTarget, proto))
|
||||
return false;
|
||||
} else {
|
||||
proto.set(nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Note, this template can probably be merged in part with the one in
|
||||
// SharedTypedArrayObject.cpp once our implementation of
|
||||
// TypedArrayObject is closer to ES6: at the moment, our
|
||||
@ -425,10 +439,13 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||
static JSObject*
|
||||
create(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
MOZ_ASSERT(args.isConstructing());
|
||||
RootedObject newTarget(cx, &args.newTarget().toObject());
|
||||
|
||||
/* () or (number) */
|
||||
uint32_t len = 0;
|
||||
if (args.length() == 0 || ValueIsLength(args[0], &len))
|
||||
return fromLength(cx, len);
|
||||
return fromLength(cx, len, newTarget);
|
||||
|
||||
/* (not an object) */
|
||||
if (!args[0].isObject()) {
|
||||
@ -449,9 +466,13 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||
* shared array's values are copied here.
|
||||
*/
|
||||
if (!UncheckedUnwrap(dataObj)->is<ArrayBufferObject>())
|
||||
return fromArray(cx, dataObj);
|
||||
return fromArray(cx, dataObj, newTarget);
|
||||
|
||||
/* (ArrayBuffer, [byteOffset, [length]]) */
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
|
||||
return nullptr;
|
||||
|
||||
int32_t byteOffset = 0;
|
||||
int32_t length = -1;
|
||||
|
||||
@ -475,7 +496,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||
}
|
||||
}
|
||||
|
||||
return fromBuffer(cx, dataObj, byteOffset, length);
|
||||
return fromBufferWithProto(cx, dataObj, byteOffset, length, proto);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -529,9 +550,11 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||
* don't have to do anything *uniquely* crazy here.
|
||||
*/
|
||||
|
||||
Rooted<JSObject*> proto(cx);
|
||||
if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &proto))
|
||||
return nullptr;
|
||||
RootedObject protoRoot(cx, proto);
|
||||
if (!protoRoot) {
|
||||
if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &protoRoot))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
InvokeArgs args(cx);
|
||||
if (!args.init(3))
|
||||
@ -541,7 +564,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||
args.setThis(ObjectValue(*bufobj));
|
||||
args[0].setNumber(byteOffset);
|
||||
args[1].setInt32(lengthInt);
|
||||
args[2].setObject(*proto);
|
||||
args[2].setObject(*protoRoot);
|
||||
|
||||
if (!Invoke(cx, args))
|
||||
return nullptr;
|
||||
@ -556,6 +579,11 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||
|
||||
Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
|
||||
|
||||
if (buffer->isNeutered()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (byteOffset > buffer->byteLength() || byteOffset % sizeof(NativeType) != 0) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||
return nullptr; // invalid byteOffset
|
||||
@ -614,16 +642,21 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
fromLength(JSContext* cx, uint32_t nelements)
|
||||
fromLength(JSContext* cx, uint32_t nelements, HandleObject newTarget = nullptr)
|
||||
{
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeForInstance(cx, newTarget, &proto))
|
||||
return nullptr;
|
||||
|
||||
Rooted<ArrayBufferObject*> buffer(cx);
|
||||
if (!maybeCreateArrayBuffer(cx, nelements, &buffer))
|
||||
return nullptr;
|
||||
return makeInstance(cx, buffer, 0, nelements);
|
||||
|
||||
return makeInstance(cx, buffer, 0, nelements, proto);
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
fromArray(JSContext* cx, HandleObject other);
|
||||
fromArray(JSContext* cx, HandleObject other, HandleObject newTarget = nullptr);
|
||||
|
||||
static const NativeType
|
||||
getIndex(JSObject* obj, uint32_t index)
|
||||
@ -663,20 +696,35 @@ struct TypedArrayObject::OfType
|
||||
|
||||
template<typename T>
|
||||
/* static */ JSObject*
|
||||
TypedArrayObjectTemplate<T>::fromArray(JSContext* cx, HandleObject other)
|
||||
TypedArrayObjectTemplate<T>::fromArray(JSContext* cx, HandleObject other,
|
||||
HandleObject newTarget /* = nullptr */)
|
||||
{
|
||||
// Allow nullptr newTarget for FriendAPI methods, which don't care about
|
||||
// subclassing.
|
||||
RootedObject proto(cx);
|
||||
|
||||
uint32_t len;
|
||||
if (IsAnyTypedArray(other)) {
|
||||
if (!GetPrototypeForInstance(cx, newTarget, &proto))
|
||||
return nullptr;
|
||||
|
||||
if (AnyTypedArrayIsDetached(other)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||
return nullptr;
|
||||
}
|
||||
len = AnyTypedArrayLength(other);
|
||||
} else if (!GetLengthProperty(cx, other, &len)) {
|
||||
return nullptr;
|
||||
} else {
|
||||
if (!GetLengthProperty(cx, other, &len))
|
||||
return nullptr;
|
||||
if (!GetPrototypeForInstance(cx, newTarget, &proto))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Rooted<ArrayBufferObject*> buffer(cx);
|
||||
if (!maybeCreateArrayBuffer(cx, len, &buffer))
|
||||
return nullptr;
|
||||
|
||||
Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len));
|
||||
Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len, proto));
|
||||
if (!obj || !TypedArrayMethods<TypedArrayObject>::setFromArrayLike(cx, obj, other, len))
|
||||
return nullptr;
|
||||
return obj;
|
||||
@ -1699,15 +1747,15 @@ TypedArrayObject::setElement(TypedArrayObject& obj, uint32_t index, double d)
|
||||
*/
|
||||
|
||||
#define IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Name,NativeType) \
|
||||
JS_FRIEND_API(JSObject*) JS_New ## Name ## Array(JSContext* cx, uint32_t nelements) \
|
||||
JS_FRIEND_API(JSObject*) JS_New ## Name ## Array(JSContext* cx, uint32_t nelements) \
|
||||
{ \
|
||||
return TypedArrayObjectTemplate<NativeType>::fromLength(cx, nelements); \
|
||||
} \
|
||||
JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayFromArray(JSContext* cx, HandleObject other) \
|
||||
JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayFromArray(JSContext* cx, HandleObject other) \
|
||||
{ \
|
||||
return TypedArrayObjectTemplate<NativeType>::fromArray(cx, other); \
|
||||
} \
|
||||
JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayWithBuffer(JSContext* cx, \
|
||||
JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayWithBuffer(JSContext* cx, \
|
||||
HandleObject arrayBuffer, uint32_t byteOffset, int32_t length) \
|
||||
{ \
|
||||
return TypedArrayObjectTemplate<NativeType>::fromBuffer(cx, arrayBuffer, byteOffset, \
|
||||
@ -1719,8 +1767,8 @@ TypedArrayObject::setElement(TypedArrayObject& obj, uint32_t index, double d)
|
||||
return false; \
|
||||
const Class* clasp = obj->getClass(); \
|
||||
return clasp == TypedArrayObjectTemplate<NativeType>::instanceClass(); \
|
||||
} \
|
||||
JS_FRIEND_API(JSObject*) js::Unwrap ## Name ## Array(JSObject* obj) \
|
||||
} \
|
||||
JS_FRIEND_API(JSObject*) js::Unwrap ## Name ## Array(JSObject* obj) \
|
||||
{ \
|
||||
obj = CheckedUnwrap(obj); \
|
||||
if (!obj) \
|
||||
@ -1729,7 +1777,7 @@ TypedArrayObject::setElement(TypedArrayObject& obj, uint32_t index, double d)
|
||||
if (clasp == TypedArrayObjectTemplate<NativeType>::instanceClass()) \
|
||||
return obj; \
|
||||
return nullptr; \
|
||||
} \
|
||||
} \
|
||||
const js::Class* const js::detail::Name ## ArrayClassPtr = \
|
||||
&js::TypedArrayObject::classes[TypedArrayObjectTemplate<NativeType>::ArrayTypeID()];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user