--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -1,12 +1,28 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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.
if (!IsObject(this) || !IsTypedArray(this)) {
return callFunction(CallTypedArrayMethodIfWrapped, this, callbackfn, thisArg,
"TypedArrayEvery");
}
@@ -246,16 +262,32 @@ function TypedArrayJoin(separator) {
// Step 13.e.
R = S + next;
}
// Step 14.
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.
if (!IsObject(this) || !IsTypedArray(this)) {
return callFunction(CallTypedArrayMethodIfWrapped, this, searchElement, fromIndex,
"TypedArrayLastIndexOf");
}
@@ -438,16 +470,32 @@ function TypedArraySome(callbackfn, this
if (testResult)
return true;
}
// Step 10.
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) {
// This function is not generic.
if (!IsObject(this) || !IsTypedArray(this)) {
return callFunction(CallTypedArrayMethodIfWrapped, this, searchElement,
fromIndex, "TypedArrayIncludes");
}
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/TypedArray/entries.js
@@ -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);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/TypedArray/keys.js
@@ -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);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/TypedArray/values.js
@@ -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);
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -206,16 +206,17 @@
macro(unsized, unsized, "unsized") \
macro(unwatch, unwatch, "unwatch") \
macro(url, url, "url") \
macro(usage, usage, "usage") \
macro(useGrouping, useGrouping, "useGrouping") \
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") \
macro(void0, void0, "(void 0)") \
macro(watch, watch, "watch") \
macro(WeakSet_add, WeakSet_add, "WeakSet_add") \
macro(writable, writable, "writable") \
macro(w, w, "w") \
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -254,17 +254,16 @@ class TypedArrayObjectTemplate : public
RootedFunction fun(cx);
fun = NewFunction(cx, NullPtr(), ArrayBufferObject::createTypedArrayFromBuffer<NativeType>,
0, JSFunction::NATIVE_FUN, cx->global(), NullPtr());
if (!fun)
return false;
cx->global()->setCreateArrayFromBuffer<NativeType>(fun);
-
return true;
}
static inline const Class *instanceClass()
{
return TypedArrayObject::classForType(ArrayTypeID());
}
@@ -690,16 +689,44 @@ TypedArrayObjectTemplate<T>::fromArray(J
bool
TypedArrayConstructor(JSContext *cx, unsigned argc, Value *vp)
{
JS_ReportError(cx, "%%TypedArray%% calling/constructing not implemented yet");
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
* reinterpret_casts of templated functions with the message: "insufficient
* contextual information to determine type". JS_PSG needs to
* reinterpret_cast<JSPropertyOp>, so this causes problems for us here.
*
* We could restructure all this code to make this nicer, but since ICS isn't
@@ -774,31 +801,35 @@ TypedArrayObject::subarray(JSContext *cx
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<TypedArrayObject::is,
TypedArrayMethods<TypedArrayObject>::subarray>(cx, args);
}
/* 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),
JS_SELF_HOSTED_FN("every", "TypedArrayEvery", 2, 0),
JS_SELF_HOSTED_FN("fill", "TypedArrayFill", 3, 0),
JS_SELF_HOSTED_FN("find", "TypedArrayFind", 2, 0),
JS_SELF_HOSTED_FN("findIndex", "TypedArrayFindIndex", 2, 0),
JS_SELF_HOSTED_FN("indexOf", "TypedArrayIndexOf", 2, 0),
JS_SELF_HOSTED_FN("join", "TypedArrayJoin", 1, 0),
JS_SELF_HOSTED_FN("lastIndexOf", "TypedArrayLastIndexOf", 2, 0),
JS_SELF_HOSTED_FN("reduce", "TypedArrayReduce", 1, 0),
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
JS_FS_END
};
/* static */ const JSFunctionSpec
TypedArrayObject::staticFunctions[] = {
@@ -829,17 +860,17 @@ TypedArrayObject::sharedTypedArrayProtot
nullptr, /* construct */
nullptr, /* trace */
{
GenericCreateConstructor<TypedArrayConstructor, 3, JSFunction::FinalizeKind>,
GenericCreatePrototype,
TypedArrayObject::staticFunctions,
TypedArrayObject::protoFunctions,
TypedArrayObject::protoAccessors,
- nullptr,
+ FinishTypedArrayInit,
ClassSpec::DontDefineConstructor
}
};
template<typename T>
bool
ArrayBufferObject::createTypedArrayFromBufferImpl(JSContext *cx, CallArgs args)
{
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -174,17 +174,17 @@ https://bugzilla.mozilla.org/show_bug.cg
gPrototypeProperties['Array'].push('includes');
}
for (var c of typedArrayClasses) {
gPrototypeProperties[c] = ["constructor", "BYTES_PER_ELEMENT"];
}
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');
}
for (var c of errorObjectClasses) {
gPrototypeProperties[c] = ["constructor", "name",
// We don't actually resolve these empty data properties
// onto the Xray prototypes, but we list them here to make
// the test happy.