Bug 894658 - Implement ES6 Array.prototype.{keys,entries}. r=jorendorff
authorSankha Narayan Guria <sankha93@gmail.com>
Sat, 02 Nov 2013 07:52:50 +0530
changeset 153377 31e1a183f9c1
parent 153376 e77d96c4bfee
child 153378 4f259397bfb9
push id35793
push userryanvm@gmail.com
push dateMon, 04 Nov 2013 21:06:02 +0000
treeherdermozilla-inbound@4f259397bfb9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs894658
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 894658 - Implement ES6 Array.prototype.{keys,entries}. r=jorendorff
js/src/jit-test/tests/for-of/array-iterator-changing.js
js/src/jit-test/tests/for-of/array-iterator-empty.js
js/src/jit-test/tests/for-of/array-iterator-generic.js
js/src/jit-test/tests/for-of/array-iterator-growing-1.js
js/src/jit-test/tests/for-of/array-iterator-keys-entries.js
js/src/jit-test/tests/for-of/array-iterator-null.js
js/src/jit-test/tests/for-of/array-iterator-proxy.js
js/src/jit-test/tests/for-of/array-iterator-shrinking.js
js/src/jit-test/tests/for-of/array-iterator-surfaces-2.js
js/src/jsarray.cpp
--- a/js/src/jit-test/tests/for-of/array-iterator-changing.js
+++ b/js/src/jit-test/tests/for-of/array-iterator-changing.js
@@ -6,8 +6,24 @@ load(libdir + "iteration.js");
 var arr = [0, 1, 2];
 var it = arr[std_iterator]();
 arr[0] = 1000;
 arr[2] = 2000;
 assertIteratorNext(it, 1000);
 assertIteratorNext(it, 1);
 assertIteratorNext(it, 2000);
 assertIteratorDone(it, undefined);
+
+// test that .keys() and .entries() have the same behaviour
+
+arr = [0, 1, 2];
+var ki = arr.keys();
+var ei = arr.entries();
+arr[0] = 1000;
+arr[2] = 2000;
+assertIteratorNext(ki, 0);
+assertIteratorNext(ei, [0, 1000]);
+assertIteratorNext(ki, 1);
+assertIteratorNext(ei, [1, 1]);
+assertIteratorNext(ki, 2);
+assertIteratorNext(ei, [2, 2000]);
+assertIteratorDone(ki, undefined);
+assertIteratorDone(ei, undefined);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/for-of/array-iterator-empty.js
@@ -0,0 +1,11 @@
+// Array.keys() and .entries() on an empty array produce empty iterators
+
+var arr = [];
+var ki = arr.keys(), ei = arr.entries();
+var p = Object.getPrototypeOf(ki);
+assertEq(Object.getPrototypeOf(ei), p);
+
+for (let k of ki)
+  throw "FAIL";
+for (let [k, v] of ei)
+  throw "FAIL";
--- a/js/src/jit-test/tests/for-of/array-iterator-generic.js
+++ b/js/src/jit-test/tests/for-of/array-iterator-generic.js
@@ -1,19 +1,26 @@
 // Array.prototype.iterator is generic.
 // That is, it can be applied to arraylike objects and strings, not just arrays.
 
 load(libdir + "asserts.js");
 load(libdir + "iteration.js");
 
 function test(obj) {
     var it = Array.prototype[std_iterator].call(obj);
-    for (var i = 0; i < (obj.length >>> 0); i++)
+    var ki = Array.prototype.keys.call(obj);
+    var ei = Array.prototype.entries.call(obj);
+    for (var i = 0; i < (obj.length >>> 0); i++) {
         assertIteratorNext(it, obj[i]);
+        assertIteratorNext(ki, i);
+        assertIteratorNext(ei, [i, obj[i]]);
+    }
     assertIteratorDone(it, undefined);
+    assertIteratorDone(ki, undefined);
+    assertIteratorDone(ei, undefined);
 }
 
 test({length: 0});
 test({length: 0, 0: 'x', 1: 'y'});
 test({length: 2, 0: 'x', 1: 'y'});
 test(Object.create(['x', 'y', 'z']));
 test(Object.create({length: 2, 0: 'x', 1: 'y'}));
 test("");
--- a/js/src/jit-test/tests/for-of/array-iterator-growing-1.js
+++ b/js/src/jit-test/tests/for-of/array-iterator-growing-1.js
@@ -1,14 +1,26 @@
 // If an array with an active iterator is lengthened, the iterator visits the new elements.
 
 load(libdir + "asserts.js");
 load(libdir + "iteration.js");
 
 var arr = [0, 1];
 var it = arr[std_iterator]();
+var ki = arr.keys();
+var ei = arr.entries();
 assertIteratorNext(it, 0);
+assertIteratorNext(ki, 0);
+assertIteratorNext(ei, [0, 0]);
 assertIteratorNext(it, 1);
+assertIteratorNext(ki, 1);
+assertIteratorNext(ei, [1, 1]);
 arr[2] = 2;
 arr.length = 4;
 assertIteratorNext(it, 2);
+assertIteratorNext(ki, 2);
+assertIteratorNext(ei, [2, 2]);
 assertIteratorNext(it, undefined);
+assertIteratorNext(ki, 3);
+assertIteratorNext(ei, [3, undefined]);
 assertIteratorDone(it, undefined);
+assertIteratorDone(ki, undefined);
+assertIteratorDone(ei, undefined);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/for-of/array-iterator-keys-entries.js
@@ -0,0 +1,16 @@
+// array.keys() returns an iterator over the index of elements
+// and array.entries() returns an iterator that yields pairs [index, element].
+
+load(libdir + "iteration.js");
+
+var data = [1, 2, 3, "abc"];
+
+var ki = data.keys();
+for (var i = 0; i < data.length; i++)
+  assertIteratorResult(ki.next(), i, false);
+assertIteratorDone(ki, undefined);
+
+var ei = data.entries();
+for (var i = 0; i < data.length; i++)
+  assertIteratorResult(ei.next(), [i, data[i]], false);
+assertIteratorDone(ei, undefined);
--- a/js/src/jit-test/tests/for-of/array-iterator-null.js
+++ b/js/src/jit-test/tests/for-of/array-iterator-null.js
@@ -1,9 +1,11 @@
 // Array.prototype.iterator applied to undefined or null throws directly.
 
 load(libdir + "asserts.js");
 load(libdir + "iteration.js");
 
 for (var v of [undefined, null]) {
     // ES6 draft 2013-09-05 section 22.1.5.1.
     assertThrowsInstanceOf(function () { Array.prototype[std_iterator].call(v); }, TypeError);
+    assertThrowsInstanceOf(function () { Array.prototype.keys.call(v); }, TypeError);
+    assertThrowsInstanceOf(function () { Array.prototype.entries.call(v); }, TypeError);
 }
--- a/js/src/jit-test/tests/for-of/array-iterator-proxy.js
+++ b/js/src/jit-test/tests/for-of/array-iterator-proxy.js
@@ -1,24 +1,47 @@
 // An array iterator for a proxy calls the traps in a predictable order.
 
 load(libdir + "asserts.js");
 load(libdir + "iteration.js");
 
 var s = '';
-var it = Array.prototype[std_iterator].call(Proxy.create({
+
+var proxyObj = {
     get: function (recipient, name) {
         if (name == 'length') {
             s += 'L';
             return 2;
         } else {
             s += name;
             return name;
         }
     }
-}));
+};
+
+var it = Array.prototype[std_iterator].call(Proxy.create(proxyObj));
 
 assertIteratorNext(it, "0");
 s += ' ';
 assertIteratorNext(it, "1");
 s += ' ';
 assertIteratorDone(it, undefined);
 assertEq(s, "L0 L1 L");
+
+s = '';
+var ki = Array.prototype.keys.call(Proxy.create(proxyObj));
+
+assertIteratorNext(ki, 0);
+s += ' ';
+assertIteratorNext(ki, 1);
+s += ' ';
+assertIteratorDone(ki, undefined);
+assertEq(s, "L L L");
+
+s = '';
+var ei = Array.prototype.entries.call(Proxy.create(proxyObj));
+
+assertIteratorNext(ei, [0, "0"]);
+s += ' ';
+assertIteratorNext(ei, [1, "1"]);
+s += ' ';
+assertIteratorDone(ei, undefined);
+assertEq(s, "L0 L1 L");
--- a/js/src/jit-test/tests/for-of/array-iterator-shrinking.js
+++ b/js/src/jit-test/tests/for-of/array-iterator-shrinking.js
@@ -1,11 +1,20 @@
 // If an array is truncated to the left of an iterator it, it.next() returns { done: true }.
 
 load(libdir + "asserts.js");
 load(libdir + "iteration.js");
 
 var arr = [0, 1, 2];
 var it = arr[std_iterator]();
+var ki = arr.keys();
+var ei = arr.entries();
+
 assertIteratorNext(it, 0);
 assertIteratorNext(it, 1);
+assertIteratorNext(ki, 0);
+assertIteratorNext(ki, 1);
+assertIteratorNext(ei, [0, 0]);
+assertIteratorNext(ei, [1, 1]);
 arr.length = 1;
 assertIteratorDone(it, undefined);
+assertIteratorDone(ki, undefined);
+assertIteratorDone(ei, undefined);
--- a/js/src/jit-test/tests/for-of/array-iterator-surfaces-2.js
+++ b/js/src/jit-test/tests/for-of/array-iterator-surfaces-2.js
@@ -1,14 +1,18 @@
 // Superficial tests for iterators created by Array.prototype.iterator
 
 load(libdir + "iteration.js");
 
 var proto = Object.getPrototypeOf([][std_iterator]());
 assertEq(Object.getPrototypeOf(proto), Iterator.prototype);
+proto = Object.getPrototypeOf([].keys());
+assertEq(Object.getPrototypeOf(proto), Iterator.prototype);
+proto = Object.getPrototypeOf([].entries());
+assertEq(Object.getPrototypeOf(proto), Iterator.prototype);
 
 function check(it) {
     assertEq(typeof it, 'object');
     assertEq(Object.getPrototypeOf(it), proto);
     assertEq(Object.getOwnPropertyNames(it).length, 0);
     assertEq(it[std_iterator](), it);
 
     // for-in enumerates the iterator's properties.
@@ -16,8 +20,12 @@ function check(it) {
     var s = '';
     for (var p in it)
         s += p + '.';
     assertEq(s, 'x.');
 }
 
 check([][std_iterator]());
 check(Array.prototype[std_iterator].call({}));
+check([].keys());
+check(Array.prototype.keys.call({}));
+check([].entries());
+check(Array.prototype.entries.call({}));
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2963,16 +2963,18 @@ static const JSFunctionSpec array_method
     JS_SELF_HOSTED_FN("filterPar",   "ArrayFilterPar",   2,0),
 #endif
 
     /* ES6 additions */
     JS_SELF_HOSTED_FN("find",        "ArrayFind",        1,0),
     JS_SELF_HOSTED_FN("findIndex",   "ArrayFindIndex",   1,0),
 
     JS_SELF_HOSTED_FN("@@iterator",  "ArrayValues",      0,0),
+    JS_SELF_HOSTED_FN("entries",     "ArrayEntries",     0,0),
+    JS_SELF_HOSTED_FN("keys",        "ArrayKeys",        0,0),
     JS_FS_END
 };
 
 static const JSFunctionSpec array_static_methods[] = {
     JS_FN("isArray",            array_isArray,      1,0),
     JS_SELF_HOSTED_FN("lastIndexOf", "ArrayStaticLastIndexOf", 2,0),
     JS_SELF_HOSTED_FN("indexOf",     "ArrayStaticIndexOf", 2,0),
     JS_SELF_HOSTED_FN("forEach",     "ArrayStaticForEach", 2,0),