Bug 1119217 - Implement %TypedArray%.prototype.{keys, values, entries}. r=till

This commit is contained in:
Tom Schuster 2015-01-11 21:21:35 +01:00
parent b2bf53a267
commit bb29a349eb
7 changed files with 232 additions and 4 deletions

View File

@ -2,6 +2,22 @@
* 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 rev30 (2014/12/24) 22.2.3.6 %TypedArray%.prototype.entries()
function TypedArrayEntries() {
// Step 1.
var O = this;
// Step 2-3.
if (!IsObject(O) || !IsTypedArray(O)) {
return callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayEntries");
}
// Step 4-6. Bug 1101256: detachment checks
// Step 7.
return CreateArrayIterator(O, ITEM_KIND_KEY_AND_VALUE);
}
// ES6 draft rev30 (2014/12/24) 22.2.3.7 %TypedArray%.prototype.every(callbackfn[, thisArg]).
function TypedArrayEvery(callbackfn, thisArg = undefined) {
// This function is not generic.
@ -251,6 +267,22 @@ function TypedArrayJoin(separator) {
return R;
}
// ES6 draft rev30 (2014/12/24) 22.2.3.15 %TypedArray%.prototype.keys()
function TypedArrayKeys() {
// Step 1.
var O = this;
// Step 2-3.
if (!IsObject(O) || !IsTypedArray(O)) {
return callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayKeys");
}
// Step 4-6. Bug 1101256: detachment checks
// Step 7.
return CreateArrayIterator(O, ITEM_KIND_KEY);
}
// ES6 draft rev29 (2014/12/06) 22.2.3.16 %TypedArray%.prototype.lastIndexOf(searchElement [,fromIndex]).
function TypedArrayLastIndexOf(searchElement, fromIndex = undefined) {
// This function is not generic.
@ -443,6 +475,22 @@ function TypedArraySome(callbackfn, thisArg = undefined) {
return false;
}
// ES6 draft rev30 (2014/12/24) 22.2.3.30 %TypedArray%.prototype.values()
function TypedArrayValues() {
// Step 1.
var O = this;
// Step 2-3.
if (!IsObject(O) || !IsTypedArray(O)) {
return callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayValues");
}
// Step 4-6. Bug 1101256: detachment checks
// Step 7.
return CreateArrayIterator(O, ITEM_KIND_VALUE);
}
// Proposed for ES7:
// https://github.com/tc39/Array.prototype.includes/blob/7c023c19a0/spec.md
function TypedArrayIncludes(searchElement, fromIndex = 0) {

View File

@ -0,0 +1,49 @@
const constructors = [
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array
];
for (var constructor of constructors) {
assertEq(constructor.prototype.entries.length, 0);
assertEq(constructor.prototype.entries.name, "entries");
assertDeepEq([...new constructor(0).entries()], []);
assertDeepEq([...new constructor(1).entries()], [[0, 0]]);
assertDeepEq([...new constructor(2).entries()], [[0, 0], [1, 0]]);
assertDeepEq([...new constructor([15]).entries()], [[0, 15]]);
var arr = new constructor([1, 2, 3]);
var iterator = arr.entries();
assertDeepEq(iterator.next(), {value: [0, 1], done: false});
assertDeepEq(iterator.next(), {value: [1, 2], done: false});
assertDeepEq(iterator.next(), {value: [2, 3], done: false});
assertDeepEq(iterator.next(), {value: undefined, done: true});
// Called from other globals.
if (typeof newGlobal === "function") {
var entries = newGlobal()[constructor.name].prototype.entries;
assertDeepEq([...entries.call(new constructor(2))], [[0, 0], [1, 0]]);
arr = newGlobal()[constructor.name](2);
assertEq([...constructor.prototype.entries.call(arr)].toString(), "0,0,1,0");
}
// Throws if `this` isn't a TypedArray.
var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
invalidReceivers.forEach(invalidReceiver => {
assertThrowsInstanceOf(() => {
constructor.prototype.entries.call(invalidReceiver);
}, TypeError, "Assert that entries fails if this value is not a TypedArray");
});
// FIXME: Should throw exception if `this` is a proxy, see bug 1115361.
constructor.prototype.entries.call(new Proxy(new constructor(), {}));
}
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -0,0 +1,49 @@
const constructors = [
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array
];
for (var constructor of constructors) {
assertEq(constructor.prototype.keys.length, 0);
assertEq(constructor.prototype.keys.name, "keys");
assertDeepEq([...new constructor(0).keys()], []);
assertDeepEq([...new constructor(1).keys()], [0]);
assertDeepEq([...new constructor(2).keys()], [0, 1]);
assertDeepEq([...new constructor([15]).keys()], [0]);
var arr = new constructor([1, 2, 3]);
var iterator = arr.keys();
assertDeepEq(iterator.next(), {value: 0, done: false});
assertDeepEq(iterator.next(), {value: 1, done: false});
assertDeepEq(iterator.next(), {value: 2, done: false});
assertDeepEq(iterator.next(), {value: undefined, done: true});
// Called from other globals.
if (typeof newGlobal === "function") {
var keys = newGlobal()[constructor.name].prototype.keys;
assertDeepEq([...keys.call(new constructor(2))], [0, 1]);
arr = newGlobal()[constructor.name](2);
assertEq([...constructor.prototype.keys.call(arr)].toString(), "0,1");
}
// Throws if `this` isn't a TypedArray.
var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
invalidReceivers.forEach(invalidReceiver => {
assertThrowsInstanceOf(() => {
constructor.prototype.keys.call(invalidReceiver);
}, TypeError, "Assert that keys fails if this value is not a TypedArray");
});
// FIXME: Should throw exception if `this` is a proxy, see bug 1115361.
constructor.prototype.keys.call(new Proxy(new constructor(), {}));
}
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -0,0 +1,50 @@
const constructors = [
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array
];
for (var constructor of constructors) {
assertEq(constructor.prototype.values.length, 0);
assertEq(constructor.prototype.values.name, "values");
assertEq(constructor.prototype.values, constructor.prototype[Symbol.iterator]);
assertDeepEq([...new constructor(0).values()], []);
assertDeepEq([...new constructor(1).values()], [0]);
assertDeepEq([...new constructor(2).values()], [0, 0]);
assertDeepEq([...new constructor([15]).values()], [15]);
var arr = new constructor([1, 2, 3]);
var iterator = arr.values();
assertDeepEq(iterator.next(), {value: 1, done: false});
assertDeepEq(iterator.next(), {value: 2, done: false});
assertDeepEq(iterator.next(), {value: 3, done: false});
assertDeepEq(iterator.next(), {value: undefined, done: true});
// Called from other globals.
if (typeof newGlobal === "function") {
var values = newGlobal()[constructor.name].prototype.values;
assertDeepEq([...values.call(new constructor([42, 36]))], [42, 36]);
arr = newGlobal()[constructor.name]([42, 36]);
assertEq([...constructor.prototype.values.call(arr)].toString(), "42,36");
}
// Throws if `this` isn't a TypedArray.
var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
invalidReceivers.forEach(invalidReceiver => {
assertThrowsInstanceOf(() => {
constructor.prototype.values.call(invalidReceiver);
}, TypeError, "Assert that values fails if this value is not a TypedArray");
});
// FIXME: Should throw exception if `this` is a proxy, see bug 1115361.
constructor.prototype.values.call(new Proxy(new constructor(), {}));
}
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -211,6 +211,7 @@
macro(useAsm, useAsm, "use asm") \
macro(useStrict, useStrict, "use strict") \
macro(value, value, "value") \
macro(values, values, "values") \
macro(valueOf, valueOf, "valueOf") \
macro(var, var, "var") \
macro(variable, variable, "variable") \

View File

@ -259,7 +259,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject
return false;
cx->global()->setCreateArrayFromBuffer<NativeType>(fun);
return true;
}
@ -695,6 +694,34 @@ TypedArrayConstructor(JSContext *cx, unsigned argc, Value *vp)
return false;
}
static bool
FinishTypedArrayInit(JSContext *cx, HandleObject ctor, HandleObject proto)
{
// Define `values` and `@@iterator` manually, because they are supposed to be the same object.
RootedId name(cx, NameToId(cx->names().values));
RootedFunction fun(cx, GetSelfHostedFunction(cx, "TypedArrayValues", name, 0));
if (!fun)
return false;
RootedValue funValue(cx, ObjectValue(*fun));
if (!JSObject::defineProperty(cx, proto, cx->names().values, funValue, nullptr, nullptr, 0))
return false;
#ifdef JS_HAS_SYMBOLS
RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
if (!JSObject::defineGeneric(cx, proto, iteratorId, funValue, nullptr, nullptr, 0))
return false;
#else
if (!JSObject::defineProperty(cx, proto, cx->names().std_iterator, funValue, nullptr,
nullptr, 0))
{
return false;
}
#endif
return true;
}
/*
* These next 3 functions are brought to you by the buggy GCC we use to build
* B2G ICS. Older GCC versions have a bug in which they fail to compile
@ -779,7 +806,6 @@ TypedArrayObject::subarray(JSContext *cx, unsigned argc, Value *vp)
/* static */ const JSFunctionSpec
TypedArrayObject::protoFunctions[] = {
JS_SELF_HOSTED_SYM_FN(iterator, "ArrayValues", 0, 0), \
JS_FN("subarray", TypedArrayObject::subarray, 2, 0),
JS_FN("set", TypedArrayObject::set, 2, 0),
JS_FN("copyWithin", TypedArrayObject::copyWithin, 2, 0),
@ -794,6 +820,11 @@ TypedArrayObject::protoFunctions[] = {
JS_SELF_HOSTED_FN("reduceRight", "TypedArrayReduceRight", 1, 0),
JS_SELF_HOSTED_FN("reverse", "TypedArrayReverse", 0, 0),
JS_SELF_HOSTED_FN("some", "TypedArraySome", 2, 0),
JS_SELF_HOSTED_FN("entries", "TypedArrayEntries", 0, 0),
JS_SELF_HOSTED_FN("keys", "TypedArrayKeys", 0, 0),
// Both of these are actually defined to the same object in FinishTypedArrayInit.
JS_SELF_HOSTED_FN("values", "TypedArrayValues", 0, JSPROP_DEFINE_LATE),
JS_SELF_HOSTED_SYM_FN(iterator, "TypedArrayValues", 0, JSPROP_DEFINE_LATE),
#ifdef NIGHTLY_BUILD
JS_SELF_HOSTED_FN("includes", "TypedArrayIncludes", 2, 0),
#endif
@ -834,7 +865,7 @@ TypedArrayObject::sharedTypedArrayPrototypeClass = {
TypedArrayObject::staticFunctions,
TypedArrayObject::protoFunctions,
TypedArrayObject::protoAccessors,
nullptr,
FinishTypedArrayInit,
ClassSpec::DontDefineConstructor
}
};

View File

@ -179,7 +179,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
gPrototypeProperties['TypedArray'] =
["length", "buffer", "byteLength", "byteOffset", kIteratorSymbol, "subarray",
"set", "copyWithin", "find", "findIndex", "indexOf", "lastIndexOf", "reverse",
"join", "every", "some", "reduce", "reduceRight"];
"join", "every", "some", "reduce", "reduceRight", "entries", "keys", "values"];
if (isNightlyBuild) {
gPrototypeProperties['TypedArray'].push('includes');
}