mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1139759 - Self-host %TypedArray%.prototype.copyWithin. r=till
This commit is contained in:
parent
8a79499588
commit
e40dae4a4c
@ -2,6 +2,77 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// ES6 draft 20150304 %TypedArray%.prototype.copyWithin
|
||||
function TypedArrayCopyWithin(target, start, end = undefined) {
|
||||
// This function is not generic.
|
||||
if (!IsObject(this) || !IsTypedArray(this)) {
|
||||
return callFunction(CallTypedArrayMethodIfWrapped, this, target, start, end,
|
||||
"TypedArrayCopyWithin");
|
||||
}
|
||||
|
||||
// Bug 1101256: detachment checks mandated by ValidateTypedArray
|
||||
|
||||
// Steps 1-2.
|
||||
var obj = this;
|
||||
|
||||
// Steps 3-4, modified for the typed array case.
|
||||
var len = TypedArrayLength(obj);
|
||||
|
||||
assert(0 <= len && len <= 0x7FFFFFFF,
|
||||
"assumed by some of the math below, see also the other assertions");
|
||||
|
||||
// Steps 5-7.
|
||||
var relativeTarget = ToInteger(target);
|
||||
|
||||
var to = relativeTarget < 0 ? std_Math_max(len + relativeTarget, 0)
|
||||
: std_Math_min(relativeTarget, len);
|
||||
|
||||
// Steps 8-10.
|
||||
var relativeStart = ToInteger(start);
|
||||
|
||||
var from = relativeStart < 0 ? std_Math_max(len + relativeStart, 0)
|
||||
: std_Math_min(relativeStart, len);
|
||||
|
||||
// Steps 11-13.
|
||||
var relativeEnd = end === undefined ? len
|
||||
: ToInteger(end);
|
||||
|
||||
var final = relativeEnd < 0 ? std_Math_max(len + relativeEnd, 0)
|
||||
: std_Math_min(relativeEnd, len);
|
||||
|
||||
// Step 14.
|
||||
var count = std_Math_min(final - from, len - to);
|
||||
|
||||
assert(0 <= to && to <= 0x7FFFFFFF,
|
||||
"typed array |to| index assumed int32_t");
|
||||
assert(0 <= from && from <= 0x7FFFFFFF,
|
||||
"typed array |from| index assumed int32_t");
|
||||
|
||||
// Negative counts are possible for cases like tarray.copyWithin(0, 3, 0)
|
||||
// where |count === final - from|. As |to| is within the [0, len] range,
|
||||
// only |final - from| may underflow; with |final| in the range [0, len]
|
||||
// and |from| in the range [0, len] the overall subtraction range is
|
||||
// [-len, len] for |count| -- and with |len| bounded by implementation
|
||||
// limits to 2**31 - 1, there can be no exceeding int32_t.
|
||||
assert(-0x7FFFFFFF - 1 <= count && count <= 0x7FFFFFFF,
|
||||
"typed array element count assumed int32_t");
|
||||
|
||||
// Steps 15-17.
|
||||
//
|
||||
// Note that getting or setting a typed array element must throw if the
|
||||
// typed array is neutered, so the intrinsic below checks for neutering.
|
||||
// This happens *only* if a get/set occurs, i.e. when |count > 0|.
|
||||
//
|
||||
// Also note that this copies elements effectively by memmove, *not* in
|
||||
// step 17's specified order. This is unobservable, but it would be if we
|
||||
// used this method to implement shared typed arrays' copyWithin.
|
||||
if (count > 0)
|
||||
MoveTypedArrayElements(obj, to | 0, from | 0, count | 0);
|
||||
|
||||
// Step 18.
|
||||
return obj;
|
||||
}
|
||||
|
||||
// ES6 draft rev30 (2014/12/24) 22.2.3.6 %TypedArray%.prototype.entries()
|
||||
function TypedArrayEntries() {
|
||||
// Step 1.
|
||||
|
@ -172,6 +172,28 @@ for (var constructor of constructors) {
|
||||
assertEq(e, 42, "should have failed converting target to index");
|
||||
}
|
||||
|
||||
function neuterAndConvertTo(x) {
|
||||
return { valueOf() { neuter(tarray.buffer, "change-data"); return x; } };
|
||||
}
|
||||
|
||||
// Neutering during argument processing triggers a TypeError.
|
||||
tarray = new constructor([1, 2, 3, 4, 5]);
|
||||
try
|
||||
{
|
||||
tarray.copyWithin(0, 3, neuterAndConvertTo(4));
|
||||
throw new Error("expected to throw");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"expected throw with neutered array during set");
|
||||
}
|
||||
|
||||
// ...unless no elements are to be copied.
|
||||
tarray = new constructor([1, 2, 3, 4, 5]);
|
||||
assertDeepEq(tarray.copyWithin(0, 3, neuterAndConvertTo(3)),
|
||||
new constructor([]));
|
||||
|
||||
/* // fails, unclear whether it should, disabling for now
|
||||
// test with a proxy object
|
||||
var handler = {
|
||||
|
@ -2239,7 +2239,6 @@ IonBuilder::inlineTypedArrayLength(CallInfo &callInfo)
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineObjectIsTypeDescr(CallInfo &callInfo)
|
||||
{
|
||||
|
@ -842,6 +842,8 @@ bool intrinsic_IsStringIterator(JSContext *cx, unsigned argc, Value *vp);
|
||||
bool intrinsic_IsTypedArray(JSContext *cx, unsigned argc, Value *vp);
|
||||
bool intrinsic_TypedArrayLength(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
bool intrinsic_MoveTypedArrayElements(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
class AutoLockForExclusiveAccess
|
||||
{
|
||||
JSRuntime *runtime;
|
||||
|
@ -671,6 +671,57 @@ js::intrinsic_TypedArrayLength(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intrinsic_MoveTypedArrayElements(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 4);
|
||||
|
||||
Rooted<TypedArrayObject*> tarray(cx, &args[0].toObject().as<TypedArrayObject>());
|
||||
uint32_t to = uint32_t(args[1].toInt32());
|
||||
uint32_t from = uint32_t(args[2].toInt32());
|
||||
uint32_t count = uint32_t(args[3].toInt32());
|
||||
|
||||
MOZ_ASSERT(count > 0,
|
||||
"don't call this method if copying no elements, because then "
|
||||
"the not-neutered requirement is wrong");
|
||||
|
||||
if (tarray->hasBuffer() && tarray->buffer()->isNeutered()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't multiply by |tarray->bytesPerElement()| in case the compiler can't
|
||||
// strength-reduce multiplication by 1/2/4/8 into the equivalent shift.
|
||||
const size_t ElementShift = TypedArrayShift(tarray->type());
|
||||
|
||||
MOZ_ASSERT((UINT32_MAX >> ElementShift) > to);
|
||||
uint32_t byteDest = to << ElementShift;
|
||||
|
||||
MOZ_ASSERT((UINT32_MAX >> ElementShift) > from);
|
||||
uint32_t byteSrc = from << ElementShift;
|
||||
|
||||
MOZ_ASSERT((UINT32_MAX >> ElementShift) >= count);
|
||||
uint32_t byteSize = count << ElementShift;
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
uint32_t viewByteLength = tarray->byteLength();
|
||||
MOZ_ASSERT(byteSize <= viewByteLength);
|
||||
MOZ_ASSERT(byteDest < viewByteLength);
|
||||
MOZ_ASSERT(byteSrc < viewByteLength);
|
||||
MOZ_ASSERT(byteDest <= viewByteLength - byteSize);
|
||||
MOZ_ASSERT(byteSrc <= viewByteLength - byteSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t *data = static_cast<uint8_t*>(tarray->viewData());
|
||||
mozilla::PodMove(&data[byteDest], &data[byteSrc], byteSize);
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CallSelfHostedNonGenericMethod(JSContext *cx, CallArgs args)
|
||||
{
|
||||
@ -909,6 +960,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
JS_FN("IsTypedArray", intrinsic_IsTypedArray, 1,0),
|
||||
JS_FN("TypedArrayLength", intrinsic_TypedArrayLength, 1,0),
|
||||
|
||||
JS_FN("MoveTypedArrayElements", intrinsic_MoveTypedArrayElements, 4,0),
|
||||
|
||||
JS_FN("CallTypedArrayMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<TypedArrayObject>>, 2, 0),
|
||||
|
||||
|
@ -569,6 +569,11 @@ class TypedArrayMethods
|
||||
|
||||
/* copyWithin(target, start[, end]) */
|
||||
// ES6 draft rev 26, 22.2.3.5
|
||||
// %TypedArray%.prototype.copyWithin is a self-hosted method, so this code
|
||||
// is only used for shared typed arrays. We should self-host both methods
|
||||
// eventually (but note TypedArrayCopyWithin will require changes to be
|
||||
// usable for shared typed arrays), but we need to rejigger the shared
|
||||
// typed array prototype chain before we can do that.
|
||||
static bool
|
||||
copyWithin(JSContext *cx, CallArgs args)
|
||||
{
|
||||
|
@ -771,14 +771,6 @@ TypedArrayObject::protoAccessors[] = {
|
||||
JS_PS_END
|
||||
};
|
||||
|
||||
/* static */ bool
|
||||
TypedArrayObject::copyWithin(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<TypedArrayObject::is,
|
||||
TypedArrayMethods<TypedArrayObject>::copyWithin>(cx, args);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
TypedArrayObject::set(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
@ -799,7 +791,7 @@ TypedArrayObject::subarray(JSContext *cx, unsigned argc, Value *vp)
|
||||
TypedArrayObject::protoFunctions[] = {
|
||||
JS_FN("subarray", TypedArrayObject::subarray, 2, 0),
|
||||
JS_FN("set", TypedArrayObject::set, 2, 0),
|
||||
JS_FN("copyWithin", TypedArrayObject::copyWithin, 2, 0),
|
||||
JS_SELF_HOSTED_FN("copyWithin", "TypedArrayCopyWithin", 3, 0),
|
||||
JS_SELF_HOSTED_FN("every", "TypedArrayEvery", 2, 0),
|
||||
JS_SELF_HOSTED_FN("fill", "TypedArrayFill", 3, 0),
|
||||
JS_SELF_HOSTED_FN("filter", "TypedArrayFilter", 2, 0),
|
||||
|
@ -214,7 +214,6 @@ class TypedArrayObject : public NativeObject
|
||||
|
||||
static bool is(HandleValue v);
|
||||
|
||||
static bool copyWithin(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool set(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool subarray(JSContext *cx, unsigned argc, Value *vp);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user