changeset: 229386:2c92e43e29d8
authorTill Schneidereit <till@tillschneidereit.net>
Thu, 18 Sep 2014 17:22:05 +0800
changeset 206327 178df0290ee1b1f79599142cb0d2e7af81630690
parent 206326 cafe6d84215b803077e99d2379cbbe0cf15d82c2
child 206328 1c49dba274e4c0153497bdb1ae06a3a5538262a0
push id49410
push usertschneidereit@gmail.com
push dateSun, 21 Sep 2014 22:53:25 +0000
treeherdermozilla-inbound@1c49dba274e4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs229386, 1069063
milestone35.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
changeset: 229386:2c92e43e29d8 user: ziyunfei <446240525@qq.com> files: js/src/builtin/Array.js js/src/builtin/Utilities.js js/src/jsarray.cpp js/src/tests/ecma_7/Array/browser.js js/src/tests/ecma_7/Array/contains.js js/src/tests/ecma_7/Array/shell.js js/src/tests/ecma_7/browser.js js/src/tests/ecma_7/shell.js description: Bug 1069063 - Implement Array.prototype.contains. r=till,securityAudit=bholley
js/src/builtin/Array.js
js/src/builtin/Utilities.js
js/src/jsarray.cpp
js/src/tests/Makefile.in
js/src/tests/ecma_7/Array/browser.js
js/src/tests/ecma_7/Array/contains.js
js/src/tests/ecma_7/Array/shell.js
js/src/tests/ecma_7/browser.js
js/src/tests/ecma_7/shell.js
js/xpconnect/tests/chrome/test_xrayToJS.xul
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -576,16 +576,66 @@ function ArrayFill(value, start = 0, end
     for (; k < final; k++) {
         O[k] = value;
     }
 
     // Step 13.
     return O;
 }
 
+// Proposed for ES7:
+// https://github.com/domenic/Array.prototype.contains/blob/master/spec.md
+function ArrayContains(searchElement, fromIndex = 0) {
+    // Steps 1-2.
+    var O = ToObject(this);
+
+    // Steps 3-4.
+    var len = ToLength(O.length);
+
+    // Step 5.
+    if (len === 0)
+        return false;
+
+    // Steps 6-7.
+    var n = ToInteger(fromIndex);
+
+    // Step 8.
+    if (n >= len)
+        return false;
+
+    // Step 9.
+    var k;
+    if (n >= 0)
+        k = n;
+    // Step 10.
+    else {
+        // Step a.
+        k = len + n;
+        // Step b.
+        if (k < 0)
+            k = 0;
+    }
+
+    // Step 11.
+    while (k < len) {
+        // Steps a-b.
+        var elementK = O[k];
+
+        // Step c.
+        if (SameValueZero(searchElement, elementK))
+            return true;
+
+        // Step d.
+        k++;
+    }
+
+    // Step 12.
+    return false;
+}
+
 #define ARRAY_ITERATOR_SLOT_ITERATED_OBJECT 0
 #define ARRAY_ITERATOR_SLOT_NEXT_INDEX 1
 #define ARRAY_ITERATOR_SLOT_ITEM_KIND 2
 
 #define ITEM_KIND_VALUE 0
 #define ITEM_KIND_KEY_AND_VALUE 1
 #define ITEM_KIND_KEY 2
 
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -151,16 +151,21 @@ function ToLength(v) {
 
     if (v <= 0)
         return 0;
 
     // Math.pow(2, 53) - 1 = 0x1fffffffffffff
     return v < 0x1fffffffffffff ? v : 0x1fffffffffffff;
 }
 
+/* Spec: ECMAScript Draft, 6 edition Aug 24, 2014, 7.2.4 */
+function SameValueZero(x, y) {
+    return x !== x && y !== y || x === y
+}
+
 /********** Testing code **********/
 
 #ifdef ENABLE_PARALLEL_JS
 
 /**
  * Internal debugging tool: checks that the given `mode` permits
  * sequential execution
  */
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3018,16 +3018,22 @@ static const JSFunctionSpec array_method
     JS_SELF_HOSTED_FN("findIndex",   "ArrayFindIndex",   1,0),
     JS_SELF_HOSTED_FN("copyWithin",  "ArrayCopyWithin",  3,0),
 
     JS_SELF_HOSTED_FN("fill",        "ArrayFill",        3,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),
+
+    /* ES7 additions */
+#ifdef NIGHTLY_BUILD
+    JS_SELF_HOSTED_FN("contains",    "ArrayContains",    2,0),
+#endif
+
     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),
--- a/js/src/tests/Makefile.in
+++ b/js/src/tests/Makefile.in
@@ -13,16 +13,17 @@ TEST_FILES = \
   js-test-driver-end.js \
   user.js \
   ecma/ \
   ecma_2/ \
   ecma_3/ \
   ecma_3_1/ \
   ecma_5/ \
   ecma_6/ \
+  ecma_7/ \
   Intl/ \
   js1_1/ \
   js1_2/ \
   js1_3/ \
   js1_4/ \
   js1_5/ \
   js1_6/ \
   js1_7/ \
copy from js/src/tests/ecma_6/Array/browser.js
copy to js/src/tests/ecma_7/Array/browser.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_7/Array/contains.js
@@ -0,0 +1,61 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var BUGNUMBER = 1069063;
+var summary = "Implement Array.prototype.contains";
+
+print(BUGNUMBER + ": " + summary);
+
+if ('contains' in Array.prototype) {
+    assertEq(typeof [].contains, "function");
+    assertEq([].contains.length, 1);
+    
+    assertTrue([1, 2, 3].contains(2));
+    assertTrue([1,,2].contains(2));
+    assertTrue([1, 2, 3].contains(2, 1));
+    assertTrue([1, 2, 3].contains(2, -2));
+    assertTrue([1, 2, 3].contains(2, -100));
+    assertTrue([Object, Function, Array].contains(Function));
+    assertTrue([-0].contains(0));
+    assertTrue([NaN].contains(NaN));
+    assertTrue([,].contains());
+    assertTrue(staticContains("123", "2"));
+    assertTrue(staticContains({length: 3, 1: 2}, 2));
+    assertTrue(staticContains({length: 3, 1: 2, get 3(){throw ""}}, 2));
+    assertTrue(staticContains({length: 3, get 1() {return 2}}, 2));
+    assertTrue(staticContains({__proto__: {1: 2}, length: 3}, 2));
+    assertTrue(staticContains(new Proxy([1], {get(){return 2}}), 2));
+    
+    assertFalse([1, 2, 3].contains("2"));
+    assertFalse([1, 2, 3].contains(2, 2));
+    assertFalse([1, 2, 3].contains(2, -1));
+    assertFalse([undefined].contains(NaN));
+    assertFalse([{}].contains({}));
+    assertFalse(staticContains({length: 3, 1: 2}, 2, 2));
+    assertFalse(staticContains({length: 3, get 0(){delete this[1]}, 1: 2}, 2));
+    assertFalse(staticContains({length: -100, 0: 1}, 1));
+    
+    assertThrowsInstanceOf(() => staticContains(), TypeError);
+    assertThrowsInstanceOf(() => staticContains(null), TypeError);
+    assertThrowsInstanceOf(() => staticContains({get length(){throw TypeError()}}), TypeError);
+    assertThrowsInstanceOf(() => staticContains({length: 3, get 1() {throw TypeError()}}, 2), TypeError);
+    assertThrowsInstanceOf(() => staticContains({__proto__: {get 1() {throw TypeError()}}, length: 3}, 2), TypeError);
+    assertThrowsInstanceOf(() => staticContains(new Proxy([1], {get(){throw TypeError()}})), TypeError);
+}
+
+function assertTrue(v){
+    assertEq(v, true)
+}
+
+function assertFalse(v){
+    assertEq(v, false)
+}
+
+function staticContains(o, v, f){
+    return [].contains.call(o, v, f)
+}
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
copy from js/src/tests/ecma_6/Array/browser.js
copy to js/src/tests/ecma_7/Array/shell.js
copy from js/src/tests/ecma_6/browser.js
copy to js/src/tests/ecma_7/browser.js
copy from js/src/tests/ecma_6/shell.js
copy to js/src/tests/ecma_7/shell.js
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -171,16 +171,17 @@ https://bugzilla.mozilla.org/show_bug.cg
      "unwatch", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
      "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__"];
   gPrototypeProperties['Array'] =
     ["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push",
       "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf",
       "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find",
       "findIndex", "copyWithin", "fill", "@@iterator", "entries", "keys", "constructor"];
   if (isNightlyBuild) {
+    gPrototypeProperties['Array'].push('contains');
     let pjsMethods = ['mapPar', 'reducePar', 'scanPar', 'scatterPar', 'filterPar'];
     gPrototypeProperties['Array'] = gPrototypeProperties['Array'].concat(pjsMethods);
   }
   for (var c of typedArrayClasses) {
     gPrototypeProperties[c] = ["constructor", "BYTES_PER_ELEMENT", "length", "buffer",
                                "byteLength", "byteOffset", "@@iterator", "subarray", "set",
                                "copyWithin"];
   }