text: /**
   * Copyright (c) Facebook, Inc. and its affiliates.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   */
  
  // RUN: %hermes -target=HBC -O %s | %FileCheck --match-full-lines %s
  // RUN: %hermes -target=HBC -O -emit-binary -out %t.hbc %s && %hermes %t.hbc | %FileCheck --match-full-lines %s
  "use strict";
  
  // Performs a nested array comparison between the two arrays.
  function arrayEquals(a, b) {
    if (a.length !== b.length) {
      return false;
    }
    for (var i = 0; i < a.length; ++i) {
      if (Array.isArray(a[i]) && Array.isArray(b[i])) {
        if (!arrayEquals(a[i], b[i])) {
          return false;
        }
      } else {
        if (a[i] !== b[i]) {
          return false;
        }
      }
    }
    return true;
  }
  
  print('toString');
  // CHECK-LABEL: toString
  print(Array(1,2,3).toString());
  // CHECK-NEXT: 1,2,3
  print('empty', Array().toString());
  // CHECK-NEXT: empty
  
  // Overwrite join and make sure it fails over to Object.prototype.toString().
  var a = Array(1,2,3);
  a.join = null;
  print(a.toString());
  // CHECK-NEXT: [object Array]
  var ots = Object.prototype.toString;
  Object.prototype.toString = null;
  print(a.toString());
  // CHECK-NEXT: [object Array]
  Object.prototype.toString = ots;
  var a = [1,2];
  a.push(a);
  print(a.toString());
  // CHECK-NEXT: 1,2,
  var a = [1,2];
  var b = [3,4,a];
  a.push(b);
  print(a.toString());
  // CHECK-NEXT: 1,2,3,4,
  var a = [1,2];
  var b = [3,4];
  var c = [5,6,b];
  b.push(c);
  a.push(b);
  print(a.toString());
  // CHECK-NEXT: 1,2,3,4,5,6,
  
  print('of');
  // CHECK-LABEL: of
  print(Array.of(1,2,3));
  // CHECK-NEXT: 1,2,3
  print(Array.of('asdf', {}));
  // CHECK-NEXT: asdf,[object Object]
  print(Array.of.call(Math.sin, 1, 2, 3));
  // CHECK-NEXT: 1,2,3
  print(Array.of.call(Math.sin.bind(), 1, 2, 3));
  // CHECK-NEXT: 1,2,3
  print(Array.of.call(Math.sin.bind().bind(), 1, 2, 3));
  // CHECK-NEXT: 1,2,3
  print(Array.of(), "EMPTY");
  // CHECK-NEXT: EMPTY
  var res = Array.of.call(Object, 1, 2, 3);
  print(Array.isArray(res), res[0], res[1], res[2]);
  // CHECK-NEXT: false 1 2 3
  var f = function() {}
  var res = Array.of.call(f, 1, 2, 3);
  print(res instanceof f, res[0], res[1], res[2]);
  // CHECK-NEXT: true 1 2 3
  var res = Array.of.call(f.bind(), 1, 2, 3);
  print(res instanceof f, res[0], res[1], res[2]);
  // CHECK-NEXT: true 1 2 3
  
  print('from');
  // CHECK-LABEL: from
  var emptyRes = Array.from([]);
  print(emptyRes.length);
  // CHECK-NEXT: 0
  emptyRes = Array.from("");
  print(emptyRes.length);
  // CHECK-NEXT: 0
  emptyRes = Array.from({});
  print(emptyRes.length);
  // CHECK-NEXT: 0
  var fromRes = Array.from('foo');
  print(fromRes);
  // CHECK-NEXT: f,o,o
  print(fromRes.length);
  // CHECK-NEXT: 3
  print(Array.from(new Set(['foo', 1])));
  // CHECK-NEXT: foo,1
  print(Array.from([1, 2, 3], function(x) { return x + 1; }));
  // CHECK-NEXT: 2,3,4
  print(Array.from({length: 5}, function(v, i) { return i; }));
  // CHECK-NEXT: 0,1,2,3,4
  var thisObj = {a : "hello"};
  Array.from([0, 1], function() { print(this.a); return 0;}, thisObj);
  // CHECK-NEXT: hello
  // CHECK-NEXT: hello
  
  // user-defined iterator
  var iterable = {};
  iterable[Symbol.iterator] = function () {
      var step = 0;
      var iterator = {
          next: function() {
              if (step == 5) {
                return {value: undefined, done: true};
              } else {
          			return {value: step++, done: false};
              }
          }
      };
  	return iterator;
  }
  var iterableArr = Array.from(iterable);
  print(iterableArr);
  // CHECK-NEXT: 0,1,2,3,4
  print(iterableArr.length);
  // CHECK-NEXT: 5
  iterableArr = Array.from(iterable, function(x, i) { return x + i; });
  print(iterableArr);
  // CHECK-NEXT: 0,2,4,6,8
  print(iterableArr.length);
  // CHECK-NEXT: 5
  Array.from(iterable, function() { print(this.a); return 0;}, thisObj);
  // CHECK-NEXT: hello
  // CHECK-NEXT: hello
  // CHECK-NEXT: hello
  // CHECK-NEXT: hello
  // CHECK-NEXT: hello
  
  function testThisAsConstructor(items) {
    var ctor = function() {return {hello : "hello"};};
    var res = Array.from.call(ctor, items);
    print(res.length);
    print(res.hello);
  }
  testThisAsConstructor([1, 2]);
  // CHECK-NEXT: 2
  // CHECK-NEXT: hello
  testThisAsConstructor({1: 1, 2: 2, length: 2});
  // CHECK-NEXT: 2
  // CHECK-NEXT: hello
  testThisAsConstructor(iterable);
  // CHECK-NEXT: 5
  // CHECK-NEXT: hello
  
  print('toLocaleString');
  // CHECK-LABEL: toLocaleString
  print([1,2,3].toLocaleString());
  // CHECK-NEXT: 1,2,3
  var n = 0;
  var obj = {toLocaleString: function() {++n; return 1337;}};
  print([1,2,obj,3,obj].toLocaleString());
  print(n);
  // CHECK-NEXT: 1,2,1337,3,1337
  // CHECK-NEXT: 2
  var a = [1,2];
  a.push(a);
  print(a.toLocaleString());
  // CHECK-NEXT: 1,2,
  var a = [1,2];
  var b = [3,4,a];
  a.push(b);
  print(a.toLocaleString());
  // CHECK-NEXT: 1,2,3,4,
  var a = [1,2];
  var b = [3,4];
  var c = [5,6,b];
  b.push(c);
  a.push(b);
  print(a.toLocaleString());
  // CHECK-NEXT: 1,2,3,4,5,6,
  try {[{toLocaleString:1}].toLocaleString()}
  catch(e) {print('caught', e.name, e.message);}
  // CHECK-NEXT: caught TypeError {{.*}}
  
  print('concat');
  // CHECK-LABEL: concat
  print([1,2].concat([3,4]));
  // CHECK-NEXT: 1,2,3,4
  print([].concat([3,4]));
  // CHECK-NEXT: 3,4
  print([1,2].concat([]));
  // CHECK-NEXT: 1,2
  print('empty', [].concat([]));
  // CHECK-NEXT: empty
  print(['a','b'].concat(['c','d'], 'efg', 123, {}));
  // CHECK-NEXT: a,b,c,d,efg,123,[object Object]
  var a = [1,2].concat([[3,4],[5,6]]);
  print(a[0], a[1], a[2][0], a[2][1], a[3][0], a[3][1]);
  // CHECK-NEXT: 1 2 3 4 5 6
  print([1,2].concat(3, {0: 4, 1: 5, length: 2}));
  // CHECK-NEXT: 1,2,3,[object Object]
  var a = [1,,];
  a.__proto__[1] = 2;
  print(a.concat(3));
  // CHECK-NEXT: 1,2,3
  delete a.__proto__[1];
  var a = [1,2,3]
  a = [];
  print(typeof a.concat(100)[0]);
  // CHECK-NEXT: number
  Array.prototype[1] = 1;
  var x = [];
  x.length = 2;
  var a = x.concat();
  print(a.hasOwnProperty('1'));
  // CHECK-NEXT: true
  delete Array.prototype[1];
  var args = [];
  for (var i = 0; i < 1000; ++i) args.push([]);
  Array.prototype.concat.apply([], args);
  var obj = {
    length: Number.MAX_SAFE_INTEGER,
    get '0'() {
      throw 'in_getter';
    },
  };
  obj[Symbol.isConcatSpreadable] = true;
  try {
    [].concat(obj);
  } catch (e) {
    print(e);
  }
  // CHECK-NEXT: in_getter
  
  print('copyWithin');
  // CHECK-LABEL: copyWithin
  print([1,2,3,4,5].copyWithin(0,3,4));
  // CHECK-NEXT: 4,2,3,4,5
  print([4,2,3,4,5].copyWithin(1,3));
  // CHECK-NEXT: 4,4,5,4,5
  print([1,2,3,4,5].copyWithin(-2));
  // CHECK-NEXT: 1,2,3,1,2
  print([1,2,3,4,5].copyWithin(1));
  // CHECK-NEXT: 1,1,2,3,4
  print([1,2,3,4,5].copyWithin(1));
  // CHECK-NEXT: 1,1,2,3,4
  print([1,2,,,5].copyWithin(0,2,4));
  // CHECK-NEXT: ,,,,5
  print([1,2,3,4,5].copyWithin(-2, -3, -1));
  // CHECK-NEXT: 1,2,3,3,4
  print([1,2,3,4,5].copyWithin(-100, -1, -3));
  // CHECK-NEXT: 1,2,3,4,5
  print([1,2,3,4,5].copyWithin(100, -1, -3));
  // CHECK-NEXT: 1,2,3,4,5
  print([1,2,3,4,5].copyWithin(-2, -1, -3));
  // CHECK-NEXT: 1,2,3,4,5
  print([].copyWithin(-2, -1, -3), "EMPTY");
  // CHECK-NEXT: EMPTY
  var res = [].copyWithin.call({length: 5, 3: 1}, 0, 3);
  print(res[0], res[1], res[2], res[3], res[4], res.length);
  // CHECK-NEXT: 1 undefined undefined 1 undefined 5
  
  print('join');
  // CHECK-LABEL: join
  print(Array(1,2,3).join());
  // CHECK-NEXT: 1,2,3
  print(Array(1,2,3).join(','));
  // CHECK-NEXT: 1,2,3
  print(Array(1,2,3).join(':'));
  // CHECK-NEXT: 1:2:3
  print(Array(1,2,Array(3,4),5).join(':'));
  // CHECK-NEXT: 1:2:3,4:5
  print(Array(1,2,3).join(' SEPARATOR '));
  // CHECK-NEXT: 1 SEPARATOR 2 SEPARATOR 3
  print('empty', Array().join());
  // CHECK-NEXT: empty
  print('empty', Array().join('::::'));
  // CHECK-NEXT: empty
  print(Array(null,2,undefined,3,null).join('-'));
  // CHECK-NEXT: -2--3-
  
  print('pop');
  // CHECK-LABEL: pop
  var a = Array(1,2,3);
  print(a.pop(), a.length, a[0], a[1], a[2]);
  // CHECK-NEXT: 3 2 1 2 undefined
  print(a.pop(), a.length, a[0], a[1], a[2]);
  // CHECK-NEXT: 2 1 1 undefined undefined
  print(a.pop(), a.length, a[0], a[1], a[2]);
  // CHECK-NEXT: 1 0 undefined undefined undefined
  print(a.pop(), a.length, a[0], a[1], a[2]);
  // CHECK-NEXT: undefined 0 undefined undefined undefined
  print(a.pop(), a.length, a[0], a[1], a[2]);
  // CHECK-NEXT: undefined 0 undefined undefined undefined
  // Test recursion of pop re-entering itself.
  var a = [];
  Object.defineProperty(a, 9, {
    get: Array.prototype.pop,
  });
  try {
    print(a.pop());
  } catch (e) {
    // Infinite recursion, should throw call stack exceeded.
    print(e.name);
  }
  // CHECK-NEXT: RangeError
  var a = [];
  a[0xFFFFFFFE] = 1;
  print(a.length);
  // CHECK-NEXT: 4294967295
  print(a.pop());
  // CHECK-NEXT: 1
  print(a.length);
  // CHECK-NEXT: 4294967294
  
  print('push');
  // CHECK-LABEL: push
  var a = [1,2,3];
  print(a.push(1834), a.toString());
  // CHECK-NEXT: 4 1,2,3,1834
  print(a.push('abcd', 746, 133), a.toString());
  // CHECK-NEXT: 7 1,2,3,1834,abcd,746,133
  print(a.push(), a.toString());
  // CHECK-NEXT: 7 1,2,3,1834,abcd,746,133
  print(a.pop(), a.toString());
  // CHECK-NEXT: 133 1,2,3,1834,abcd,746
  print(a.push('last'), a.toString());
  // CHECK-NEXT: 7 1,2,3,1834,abcd,746,last
  var a = [,,,'x','y','z'];
  print(a)
  // CHECK-NEXT: ,,,x,y,z
  print(a.push(1,2,3), a);
  // CHECK-NEXT: 9 ,,,x,y,z,1,2,3
  var a = {3: 'x', 4: 'y', length: 5};
  Array.prototype.push.call(a, 'z', 'last');
  print(a.length, a[5], a[6]);
  // CHECK-NEXT: 7 z last
  var a = Array(0xfffffffe);
  print(a.length);
  // CHECK-NEXT: 4294967294
  a.push('arrEnd');
  print(a.length, a[4294967294]);
  // CHECK-NEXT: 4294967295 arrEnd
  try { a.push('a','b','c'); } catch (e) { print('caught', e.name) }
  // CHECK-NEXT: caught RangeError
  print(a[4294967295], a[4294967296], a[4294967297]);
  // CHECK-NEXT: a b c
  Array.prototype[1] = 'asdf';
  Object.defineProperty(Array.prototype, '1', {
    value: 'asdf',
    writable: false,
    configurable: true,
  });
  var a = [];
  try { a.push('x','y','z'); } catch (e) { print('caught', e.name) }
  // CHECK-NEXT: caught TypeError
  delete Array.prototype[1];
  Object.defineProperty(Array.prototype, '1', {
    get: function() { return 'asdf'; },
    set: function() { print('setter'); },
    configurable: true,
  });
  var a = [];
  print(a.push(1,2), a);
  // CHECK-NEXT: setter
  // CHECK-NEXT: 2 1,asdf
  delete Array.prototype[1];
  var a = [];
  a[0] = 'x1';
  a[10000] = 'x2';
  print(a.push('last'), a[0], a[10000], a[10001]);
  // CHECK-NEXT: 10002 x1 x2 last
  a = null;
  var a = {length: 2**53 - 1};
  try { a.push(1); } catch (e) { print('caught', e.name) }
  // CHECK-NEXT: caught TypeError
  
  print('reverse');
  // CHECK-LABEL: reverse
  var a = [1,2,3];
  print(a.reverse(), a);
  // CHECK-NEXT: 3,2,1 3,2,1
  print([1,2].reverse());
  // CHECK-NEXT: 2,1
  print('empty', [].reverse());
  // CHECK-NEXT: empty
  print([12,13,14,15,16,17,18].reverse());
  // CHECK-NEXT: 18,17,16,15,14,13,12
  print([,,,1].reverse());
  // CHECK-NEXT: 1,,,
  print([,,1,,5,7,,].reverse());
  // CHECK-NEXT: ,7,5,,1,,
  var a = {};
  a[0] = 'a';
  a[1] = 'b';
  a[5] = 'c';
  a.length = 6;
  Array.prototype.reverse.call(a);
  print(a[0], a[4], a[5]);
  // CHECK-NEXT: c b a
  var a = [0, 1, 2, 3];
  Object.defineProperty(a, 3, {
    get: function() {
      delete a[1];
      return -1;
    },
    set: function() { print('setter'); }
  });
  a.reverse();
  print(a);
  // CHECK-NEXT: setter
  // CHECK-NEXT: -1,2,,-1
  var a = [0, 1];
  Object.defineProperty(a, 0, {
    get: function() {
      a.pop();
      return -1;
    }
  });
  a.reverse();
  print(a);
  // CHECK-NEXT: ,-1
  var a = [];
  Object.defineProperties(a, {
    '0': {
      get: function() {
        print('getter 0');
        return a.val_0;
      },
      set: function(v) { a.val_0 = v; }
    },
    '1': {
      get: function() {
        print('getter 1');
        return a.val_1;
      },
      set: function(v) { a.val_1 = v; }
    },
  });
  a[0] = 0;
  a[1] = 1;
  a.reverse();
  print(a);
  // CHECK-NEXT: getter 0
  // CHECK-NEXT: getter 1
  // CHECK-NEXT: getter 0
  // CHECK-NEXT: getter 1
  // CHECK-NEXT: 1,0
  var a = [0, 1, 2, 3, 4, 5, 6];
  Object.defineProperties(a, {
    '0': {
      get: function() {
        a.pop();
        return -1;
      }
    },
    '1': {
      set: function() { a.push('a'); }
    },
    '2': {
      get: function() {
        a.push('b');
        return -2;
      },
      set: function() { a.pop(); }
    }
  });
  a.reverse();
  print(a);
  // CHECK-NEXT: ,,-2,3,-2,,-1,a
  
  print('shift');
  // CHECK-LABEL: shift
  var a = [1,2,3];
  print(a.shift(), a, a.length);
  // CHECK-NEXT: 1 2,3 2
  print(a.shift(), a, a.length);
  // CHECK-NEXT: 2 3 1
  print(a.shift(), a, a.length);
  // CHECK-NEXT: 3  0
  print(a.shift(), a, a.length);
  // CHECK-NEXT: undefined  0
  print(a.shift(), a, a.length);
  // CHECK-NEXT: undefined  0
  
  print('slice');
  // CHECK-LABEL: slice
  var a = ['a','b','c','d','e'];
  print(a.slice(1, 3), a.slice(1,3).length, a);
  // CHECK-NEXT: b,c 2 a,b,c,d,e
  print(a.slice(1));
  // CHECK-NEXT: b,c,d,e
  print(a.slice(1, 1000));
  // CHECK-NEXT: b,c,d,e
  print(a.slice());
  // CHECK-NEXT: a,b,c,d,e
  print(a.slice(-1000));
  // CHECK-NEXT: a,b,c,d,e
  print(a.slice(-1000, 1000));
  // CHECK-NEXT: a,b,c,d,e
  print(a.slice(4, 1000));
  // CHECK-NEXT: e
  print('empty', a.slice(4, -1000));
  // CHECK-NEXT: empty
  var a = [];
  print('empty', a.slice(4, 1000));
  // CHECK-NEXT: empty
  print('empty', a.slice(-10, 10));
  // CHECK-NEXT: empty
  print('empty', a.slice());
  // CHECK-NEXT: empty
  
  print('sort');
  // CHECK-LABEL: sort
  print('empty', [].sort());
  // CHECK-NEXT: empty
  print([1,2].sort());
  // CHECK-NEXT: 1,2
  print([2,1].sort());
  // CHECK-NEXT: 1,2
  print([2,13].sort());
  // CHECK-NEXT: 13,2
  print([2,13].sort(function(x,y) {return x - y}));
  // CHECK-NEXT: 2,13
  print(['a', 'aaa', 'aa'].sort(function(x,y) {return x.length - y.length}));
  // CHECK-NEXT: a,aa,aaa
  print([4,3,5,1,8,6,7,2].sort());
  // CHECK-NEXT: 1,2,3,4,5,6,7,8
  print([8,7,6,5,4,3,2,1].sort());
  // CHECK-NEXT: 1,2,3,4,5,6,7,8
  print([,undefined,,8,,,7,6,5,4,3,2,1].sort());
  // CHECK-NEXT: 1,2,3,4,5,6,7,8,,,,,
  print([8,32,86,25,71,92,66,68,97,52].sort(function(x,y) {return y - x;}));
  // CHECK-NEXT: 97,92,86,71,68,66,52,32,25,8
  print([
    93,62,92,70,2,64,61,16,85,18,3,18,59,35,54,9,31,50,67,37,82,6,36
  ].sort(function(x,y) {return x - y;}));
  // CHECK-NEXT: 2,3,6,9,16,18,18,31,35,36,37,50,54,59,61,62,64,67,70,82,85,92,93
  var a = {0: 'c', 1: 'b', 2: 'a', 3: 'f', 4: 'd', 5: 'g', 6: 'e'};
  a.length = 7;
  print(Array.prototype.join.call(Array.prototype.sort.call(a), ''));
  // CHECK-NEXT: abcdefg
  var a = {0: 2, 1: 13};
  a.length = 2;
  print(Array.prototype.join.call(Array.prototype.sort.call(a)));
  // CHECK-NEXT: 13,2
  var a = {0: 2, 1: 13};
  a.length = 2;
  print(Array.prototype.join.call(Array.prototype.sort.call(a, function(x,y) {
    return x - y;
  })));
  // CHECK-NEXT: 2,13
  try { [1,2,3].sort(null); } catch(e) { print('caught', e.name); }
  // CHECK-NEXT: caught TypeError
  var badobj = {
    get length() { throw RangeError("Don't get the length"); }
  }
  try { [].sort.call(badobj, null); } catch(e) { print('caught', e.name); }
  // CHECK-NEXT: caught TypeError
  try { [1].sort(12); } catch(e) { print('caught', e.name); }
  // CHECK-NEXT: caught TypeError
  try { [].sort(true); } catch(e) { print('caught', e.name); }
  // CHECK-NEXT: caught TypeError
  try { [1,2,3].sort({}); } catch(e) { print('caught', e.name); }
  // CHECK-NEXT: caught TypeError
  var a = [{}, {}];
  a.__defineGetter__(1, function() { a.length = 0; return 0; });
  a.sort();
  print('sorting', a, 'did not crash');
  // CHECK-NEXT: sorting 0,[object Object] did not crash
  var a = new Array(2);
  // hole at 0
  a[1] = 1;
  a.__proto__ = new Proxy([],{});
  a.sort();
  print(a);
  // CHECK-NEXT: 1,
  
  print('splice');
  // CHECK-LABEL: splice
  var a = ['a','b','c','d'];
  print(a.splice(), a);
  // CHECK-NEXT:  a,b,c,d
  var a = ['a','b','c','d'];
  print(a.splice(1), a);
  // CHECK-NEXT: b,c,d a
  var a = ['a','b','c','d'];
  print(a.splice(1, 2), a);
  // CHECK-NEXT: b,c a,d
  var a = ['a','b','c','d'];
  print(a.splice(1, 2, 'x'), a);
  // CHECK-NEXT: b,c a,x,d
  var a = ['a','b','c','d'];
  print(a.splice(1, 2, 'x', 'y', 'z'), a);
  // CHECK-NEXT: b,c a,x,y,z,d
  var a = ['a','b','c','d'];
  print(a.splice(1, 1000, 'x', 'y', 'z'), a);
  // CHECK-NEXT: b,c,d a,x,y,z
  var a = ['a','b','c','d'];
  print(a.splice(-1, 1, 'x', 'y', 'z'), a);
  // CHECK-NEXT: d a,b,c,x,y,z
  var a = ['a','b','c','d'];
  print(a.splice(-1, 1, 'x', 'y', 'z'), a);
  // CHECK-NEXT: d a,b,c,x,y,z
  var a = ['a','b','c','d'];
  print(a.splice(2, 0, 'x', 'y', 'z'), a);
  // CHECK-NEXT:  a,b,x,y,z,c,d
  var a = ['a','b','c','d'];
  print(a.splice(2, -100, 'x', 'y', 'z'), a);
  // CHECK-NEXT:  a,b,x,y,z,c,d
  var a = ['a',,'b',,,'c'];
  print(a.splice(0, 3, 'x', 'y'), a);
  // CHECK-NEXT: a,,b x,y,,,c
  
  print('unshift');
  // CHECK-LABEL: unshift
  var a = [1,2,3];
  print(a.unshift('a', 'b'), a);
  // CHECK-NEXT: 5 a,b,1,2,3
  print(a.unshift(), a);
  // CHECK-NEXT: 5 a,b,1,2,3
  print(a.unshift('c'), a);
  // CHECK-NEXT: 6 c,a,b,1,2,3
  var a = [];
  print(a.unshift(1,2,3), a);
  // CHECK-NEXT: 3 1,2,3
  var a = [];
  print(a.unshift(0,0,0,0,0,0,0,0,0,0), a);
  // CHECK-NEXT 10 0,0,0,0,0,0,0,0,0,0
  
  print('indexOf');
  // CHECK-LABEL: indexOf
  var a = ['a','b','c','b','x'];
  print(a.indexOf('b'));
  // CHECK-NEXT: 1
  print(a.indexOf('b', 0));
  // CHECK-NEXT: 1
  print(a.indexOf('b', -2));
  // CHECK-NEXT: 3
  print(a.indexOf('b', 2));
  // CHECK-NEXT: 3
  print(a.indexOf('b', -1));
  // CHECK-NEXT: -1
  print(a.indexOf('b', 4));
  // CHECK-NEXT: -1
  print(a.indexOf('d'));
  // CHECK-NEXT: -1
  var a = [];
  print(a.indexOf('a', -1));
  // CHECK-NEXT: -1
  print(a.indexOf('a', 4));
  // CHECK-NEXT: -1
  print(a.indexOf('a'));
  // CHECK-NEXT: -1
  print(1 / [true].indexOf(true, -0));
  //CHECK-NEXT: Infinity
  
  print('lastIndexOf');
  // CHECK-LABEL: lastIndexOf
  var a = ['a','b','c','b','x'];
  print(a.lastIndexOf('b'));
  // CHECK-NEXT: 3
  print(a.lastIndexOf('b', 0));
  // CHECK-NEXT: -1
  print(a.lastIndexOf('b', -2));
  // CHECK-NEXT: 3
  print(a.lastIndexOf('b', 2));
  // CHECK-NEXT: 1
  print(a.lastIndexOf('b', -1));
  // CHECK-NEXT: 3
  print(a.lastIndexOf('b', 4));
  // CHECK-NEXT: 3
  print(a.lastIndexOf('d'));
  // CHECK-NEXT: -1
  var a = [];
  print(a.lastIndexOf('a', -1));
  // CHECK-NEXT: -1
  print(a.lastIndexOf('a', 4));
  // CHECK-NEXT: -1
  print(a.lastIndexOf('a'));
  // CHECK-NEXT: -1
  
  print('every');
  // CHECK-LABEL: every
  print([1,2,3].every(function(x) {return x < 4}));
  // CHECK-NEXT: true
  print([1,2,3].every(function(x) {return x < 2}));
  // CHECK-NEXT: false
  print([].every(function(x) {return false}));
  // CHECK-NEXT: true
  print(['!', '@', '#'].every(function(x, i, arr) {
    print(this, x, i, arr);
    return x === '!';
  }, 'thisval'));
  // CHECK-NEXT: thisval ! 0 !,@,#
  // CHECK-NEXT: thisval @ 1 !,@,#
  // CHECK-NEXT: false
  try {[1].every(1)} catch(e) {print('caught', e.name, e.message);}
  // CHECK-NEXT: caught TypeError {{.*}}
  
  print('some');
  // CHECK-LABEL: some
  print([1,2,3].some(function(x) {return x < 4}));
  // CHECK-NEXT: true
  print([1,2,3].some(function(x) {return x < 2}));
  // CHECK-NEXT: true
  print([1,2,3].some(function(x) {return x < 0}));
  // CHECK-NEXT: false
  print([].some(function(x) {return false}));
  // CHECK-NEXT: false
  print(['!', '@', '#'].some(function(x, i, arr) {
    print(this, x, i, arr);
    return x === '!';
  }, 'thisval'));
  // CHECK-NEXT: thisval ! 0 !,@,#
  // CHECK-NEXT: true
  
  print('foreach');
  // CHECK-LABEL: foreach
  print(['!', '@', '#'].forEach(function(x, i, arr) {
    print(this, x, i, arr);
    return x === '!';
  }));
  // CHECK-NEXT: undefined ! 0 !,@,#
  // CHECK-NEXT: undefined @ 1 !,@,#
  // CHECK-NEXT: undefined # 2 !,@,#
  // CHECK-NEXT: undefined
  print(['!', '@', '#'].forEach(function(x, i, arr) {
    print(this, x, i, arr);
    return x === '!';
  }, 'thisval'));
  // CHECK-NEXT: thisval ! 0 !,@,#
  // CHECK-NEXT: thisval @ 1 !,@,#
  // CHECK-NEXT: thisval # 2 !,@,#
  // CHECK-NEXT: undefined
  try {[1].forEach(1)} catch(e) {print('caught', e.name, e.message);}
  // CHECK-NEXT: caught TypeError {{.*}}
  
  print('map');
  // CHECK-LABEL: map
  print(['!', '@', '#'].map(function(x, i, arr) {
    print(this, x, i, arr);
    return x === '!';
  }));
  // CHECK-NEXT: undefined ! 0 !,@,#
  // CHECK-NEXT: undefined @ 1 !,@,#
  // CHECK-NEXT: undefined # 2 !,@,#
  // CHECK-NEXT: true,false,false
  print(['!', '@', '#'].map(function(x, i, arr) {
    print(this, x, i, arr);
    return x === '!';
  }, 'thisval'));
  // CHECK-NEXT: thisval ! 0 !,@,#
  // CHECK-NEXT: thisval @ 1 !,@,#
  // CHECK-NEXT: thisval # 2 !,@,#
  // CHECK-NEXT: true,false,false
  try {[1].map(1)} catch(e) {print('caught', e.name, e.message);}
  // CHECK-NEXT: caught TypeError {{.*}}
  
  print('filter');
  // CHECK-LABEL: filter
  var a = [1,2,3];
  print(a.filter(function(x) {return x === 2}));
  // CHECK-NEXT: 2
  print(a.filter(function(x) {return x !== 2}));
  // CHECK-NEXT: 1,3
  print(a.filter(function() {return true}));
  // CHECK-NEXT: 1,2,3
  print('empty', a.filter(function() {return false}));
  // CHECK-NEXT: empty
  var a = [];
  print('empty', a.filter(function() {return true}));
  // CHECK-NEXT: empty
  print(['!', '@', '#'].filter(function(x, i, arr) {
    print(this, x, i, arr);
    return x === '!';
  }, 'thisval'));
  // CHECK-NEXT: thisval ! 0 !,@,#
  // CHECK-NEXT: thisval @ 1 !,@,#
  // CHECK-NEXT: thisval # 2 !,@,#
  // CHECK-NEXT: !
  var a = [null,2,3];
  var acc = {get: function() {return 1000}};
  Object.defineProperty(a, 0, acc);
  print(a.filter(function(x) {return x === 1000}));
  // CHECK-NEXT: 1000
  var a = {};
  a[0] = 1239;
  a[3] = 18583;
  a.length = 6;
  print(Array.prototype.filter.call(a, function(x) {return x === 1239}));
  // CHECK-NEXT: 1239
  try {[1].filter(1)} catch(e) {print('caught', e.name, e.message);}
  // CHECK-NEXT: caught TypeError {{.*}}
  
  print('fill');
  // CHECK-LABEL: fill
  var a = Array(3);
  a.fill();
  print(a[0], a[1], a[2]);
  // CHECK-NEXT: undefined undefined undefined
  a.fill(1);
  print(a[0], a[1], a[2]);
  // CHECK-NEXT: 1 1 1
  a.fill(2, 0, a.length);
  print(a[0], a[1], a[2]);
  // CHECK-NEXT: 2 2 2
  a.fill(3, -1);
  print(a[0], a[1], a[2]);
  // CHECK-NEXT: 2 2 3
  a.fill(4, 1, -1);
  print(a[0], a[1], a[2]);
  // CHECK-NEXT: 2 4 3
  var a = {};
  a[0] = 1;
  a[3] = 2;
  a.length = 6;
  Array.prototype.fill.call(a, 0);
  print(a[0], a[1], a[2], a[3], a[4], a[5]);
  // CHECK-NEXT: 0 0 0 0 0 0
  
  print('Pop from large array');
  // CHECK-LABEL: Pop from large array
  // This caused a crash with SegmentedArray used as the backing storage.
  // It was due to an off-by-one error in SegmentedArray::decreaseSize.
  var a = Array(4097).fill();
  // This pop causes the backing storage to shrink to only be inline storage.
  a.pop();
  print(a[a.length - 1]);
  // CHECK-NEXT: undefined
  a = Array(5121).fill();
  // This pop causes the backing storage to shrink to one segment instead of 2.
  a.pop();
  print(a[a.length - 1]);
  // CHECK-NEXT: undefined
  
  print('find');
  // CHECK-LABEL: find
  print(Array.prototype.find.length);
  // CHECK-NEXT: 1
  print([].find(function(){}));
  // CHECK-NEXT: undefined
  print([1,2,3].find(function(v){ return v === 4 }));
  // CHECK-NEXT: undefined
  print([0,1,2].find(function(v){ return v }));
  // CHECK-NEXT: 1
  print(['a','b','c'].find(function(v, k, obj) {
    print(this, v, k, obj);
    return v === 'b';
  }, 'thisarg'));
  // CHECK-NEXT: thisarg a 0 a,b,c
  // CHECK-NEXT: thisarg b 1 a,b,c
  // CHECK-NEXT: b
  print(Array.prototype.find.call(
    {0:'a',1:'b',length:3},
    function(v) { return v === 'b'; }
  ));
  // CHECK-NEXT: b
  
  print('findIndex');
  // CHECK-LABEL: findIndex
  print(Array.prototype.findIndex.length);
  // CHECK-NEXT: 1
  print([].findIndex(function(){}));
  // CHECK-NEXT: -1
  print([1,2,3].findIndex(function(v){ return v === 4 }));
  // CHECK-NEXT: -1
  print([0,1,2].findIndex(function(v){ return v }));
  // CHECK-NEXT: 1
  print(['a','b','c'].findIndex(function(v, k, obj) {
    print(this, v, k, obj);
    return v === 'b';
  }, 'thisarg'));
  // CHECK-NEXT: thisarg a 0 a,b,c
  // CHECK-NEXT: thisarg b 1 a,b,c
  // CHECK-NEXT: 1
  print(Array.prototype.findIndex.call(
    {0:'a',1:'b',length:3},
    function(v) { return v === 'b'; }
  ));
  // CHECK-NEXT: 1
  
  print('reduce');
  // CHECK-LABEL: reduce
  var a = [1,2,3,4];
  print(a.reduce(function(x,y) {return x + y}));
  // CHECK-NEXT: 10
  print(a.reduce(function(x,y) {return x + y}, 100));
  // CHECK-NEXT: 110
  print(a.reduce(function(x,y) {return x * y}));
  // CHECK-NEXT: 24
  var a = [];
  print(a.reduce(function() {}, 10));
  // CHECK-NEXT: 10
  var a = [,,,,1,2,,,,3,,4,,,];
  print(a.reduce(function(x,y) {return x + y}));
  // CHECK-NEXT: 10
  print(a.reduce(function(x,y) {return x + y}, 100));
  // CHECK-NEXT: 110
  print(['!', '@', '#'].reduce(function(x, y, i, arr) {
    print(this, x, y, i, arr);
    return x + y;
  }, '**'));
  // CHECK-NEXT: undefined ** ! 0 !,@,#
  // CHECK-NEXT: undefined **! @ 1 !,@,#
  // CHECK-NEXT: undefined **!@ # 2 !,@,#
  // CHECK-NEXT: **!@#
  try {[1].reduce(1)} catch(e) {print('caught', e.name, e.message);}
  // CHECK-NEXT: caught TypeError {{.*}}
  var a = Array(10);
  try {print(a.reduce(function(){}));} catch(e) {print('caught', e.name, e.message)}
  // CHECK-NEXT: caught TypeError {{.*}}
  
  print('reduceRight');
  // CHECK-LABEL: reduceRight
  var a = [1,2,3,4];
  print(a.reduceRight(function(x,y) {return x + y}));
  // CHECK-NEXT: 10
  print(a.reduceRight(function(x,y) {return x + y}, 100));
  // CHECK-NEXT: 110
  print(a.reduceRight(function(x,y) {return x * y}));
  // CHECK-NEXT: 24
  var a = [];
  print(a.reduceRight(function() {}, 10));
  // CHECK-NEXT: 10
  var a = [,,,,1,2,,,,3,,4,,,];
  print(a.reduceRight(function(x,y) {return x + y}));
  // CHECK-NEXT: 10
  print(a.reduceRight(function(x,y) {return x + y}, 100));
  // CHECK-NEXT: 110
  print(['!', '@', '#'].reduceRight(function(x, y, i, arr) {
    print(this, x, y, i, arr);
    return x + y;
  }, '**'));
  // CHECK-NEXT: undefined ** # 2 !,@,#
  // CHECK-NEXT: undefined **# @ 1 !,@,#
  // CHECK-NEXT: undefined **#@ ! 0 !,@,#
  // CHECK-NEXT: **#@!
  var a = Array(10);
  try {print(a.reduceRight(function(){}));} catch(e) {print('caught', e.name, e.message)}
  // CHECK-NEXT: caught TypeError {{.*}}
  try {[1].reduceRight(1)} catch(e) {print('caught', e.name, e.message);}
  // CHECK-NEXT: caught TypeError {{.*}}
  try {print(a.reduce(function(){}));} catch(e) {print('caught', e.name, e.message)}
  // CHECK-NEXT: caught TypeError {{.*}}
  
  print('includes');
  // CHECK-LABEL: includes
  print([1,2,3,4].includes(1));
  // CHECK-NEXT: true
  print([1,2,3,4].includes(1, Infinity));
  // CHECK-NEXT: false
  print([1,2,3,4].includes(1, 1));
  // CHECK-NEXT: false
  print([1,2,3,4].includes(1, -2));
  // CHECK-NEXT: false
  print([1,2,3,4].includes(1, -4));
  // CHECK-NEXT: true
  print([1,2,3,4].includes(3));
  // CHECK-NEXT: true
  print([1,2,3,4].includes(4));
  // CHECK-NEXT: true
  print([1,2,3,4].includes(4, -1));
  // CHECK-NEXT: true
  print([1,2,3,4].includes(4, 3));
  // CHECK-NEXT: true
  print([1,2,3,4].includes({}));
  // CHECK-NEXT: false
  print([1,2,3,4].includes(10));
  // CHECK-NEXT: false
  print([].includes(10));
  // CHECK-NEXT: false
  print(Array.prototype.includes.call({length: 3, 0: 'a', 1: 'b', 2: 'c'}, 'a'));
  // CHECK-NEXT: true
  var o = {};
  print([,,,o,,,].includes(o));
  // CHECK-NEXT: true
  
  print('flat');
  // CHECK-LABEL: flat
  print([].flat().length);
  // CHECK-NEXT: 0
  print(arrayEquals([1,2,3].flat(), [1,2,3]));
  // CHECK-NEXT: true
  print(arrayEquals([1,[2,3]].flat(), [1,2,3]));
  // CHECK-NEXT: true
  print(arrayEquals([1,[2,[3]]].flat(), [1,2,[3]]));
  // CHECK-NEXT: true
  print(arrayEquals([1,[2,[3,[4]]]].flat(0), [1,[2,[3,[4]]]]));
  // CHECK-NEXT: true
  print(arrayEquals([1,[2,[3,[4]]]].flat(), [1,2,[3,[4]]]));
  // CHECK-NEXT: true
  print(arrayEquals([1,[2,[3,[4]]]].flat(1), [1,2,[3,[4]]]));
  // CHECK-NEXT: true
  print(arrayEquals([1,[2,[3,[4]]]].flat(2), [1,2,3,[4]]));
  // CHECK-NEXT: true
  print(arrayEquals([1,[2,[3,[4]]]].flat(Infinity), [1,2,3,4]));
  // CHECK-NEXT: true
  var a = [1];
  for (var i = 0; i < 1000; ++i) {
    a = [a];
  }
  try { a.flat(Infinity); } catch(e) { print('caught', e.name) }
  // CHECK-NEXT: caught RangeError
  
  print('flatMap');
  // CHECK-LABEL: flatMap
  print([].flatMap(() => { throw Error('fail') }).length);
  // CHECK-NEXT: 0
  print(arrayEquals([1,2,3].flatMap(x => x+1), [2,3,4]));
  // CHECK-NEXT: true
  print(arrayEquals([1,2,3].flatMap(function(x) {
    return x + this;
  }, 100), [101, 102, 103]));
  // CHECK-NEXT: true
  print(arrayEquals([1,2,3].flatMap(function(x) {
    return [x, x+this];
  }, 100), [1,101,2,102,3,103]));
  // CHECK-NEXT: true
  