text: /**
   * Copyright (c) Meta Platforms, Inc. and 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 -Xhermes-internal-test-methods -Xes6-proxy -O -gc-sanitize-handles=0 %s | %FileCheck %s
  
  'use strict';
  
  print("START");
  //CHECK:START
  
  function isLittleEndian() {
    var uint16 = new Uint16Array(1);
    uint16[0] = 1;
    var uint8 = new Uint8Array(uint16.buffer);
    return uint8[0] === 1;
  }
  
  function getByteWidth(cons) {
    switch (cons) {
      case Int8Array:
      case Uint8Array:
      case Uint8ClampedArray:
        return 1;
      case Int16Array:
      case Uint16Array:
        return 2;
      case Int32Array:
      case Uint32Array:
      case Float32Array:
        return 4;
      case Float64Array:
        return 8;
    }
  }
  
  // This has the same API as the Node.js assert object.
  var assert = {
    _isEqual: function(a, b) {
      // Remember to check for NaN which does not compare as equal with itself.
      return a === b || (Number.isNaN(a) && Number.isNaN(b));
    },
    equal: function(actual, expected, msg) {
      if (!assert._isEqual(actual, expected)) {
        assert.fail(
          (msg ? msg + ' -- ' : '') +
            'Not equal: actual <' +
            actual +
            '>, and expected <' +
            expected +
            '>',
        );
      }
    },
    _isArrayEqual: function(a, b) {
      if (a.length !== b.length)
        return false;
      for (var i = 0; i < a.length; i++) {
        if (!assert._isEqual(a[i], b[i]))
          return false;
      }
      return true;
    },
    arrayEqual: function(actual, expected, msg) {
      if (!assert._isArrayEqual(actual, expected)) {
        assert.fail(
          (msg ? msg + ' -- ' : '') +
            'Array not equal: actual <' +
            actual +
            '>, and expected <' +
            expected +
            '>',
        );
      }
    },
    notEqual: function(actual, expected, msg) {
      if (assert._isEqual(actual, expected)) {
        assert.fail(
          (msg ? msg + ' -- ' : '') +
            'Equal: actual <' +
            actual +
            '>, and expected <' +
            expected +
            '>',
        );
      }
    },
    ok: function(value, msg) {
      assert.equal(!!value, true, msg);
    },
    throws: function(block, error, msg) {
      try {
        block();
      } catch (e) {
        assert.equal(e.constructor, error, msg);
        return;
      }
      // Can't put fail inside the try because it will catch the AssertionError.
      assert.fail((msg ? msg + ' -- ' : '') + 'Failed to throw');
    },
    fail: function(msg) {
      throw new Error('AssertionError: ' + (msg ? msg : 'Failed'));
    },
  };
  
  var cons = [
    Int8Array,
    Int16Array,
    Int32Array,
    Uint8Array,
    Uint8ClampedArray,
    Uint16Array,
    Uint32Array,
    Float32Array,
    Float64Array,
  ];
  var LE = isLittleEndian();
  
  // Check length
  cons.forEach(function(TypedArray) {
    var buf = new ArrayBuffer(32);
    var view = new TypedArray(buf);
    assert.equal(view.length, buf.byteLength / getByteWidth(TypedArray));
  });
  
  // Check byteLength
  cons.forEach(function(TypedArray) {
    var buf = new ArrayBuffer(32);
    var view = new TypedArray(buf);
    assert.equal(view.byteLength, buf.byteLength);
  });
  
  // Check byteOffset
  cons.forEach(function(TypedArray) {
    assert.equal(new TypedArray(new ArrayBuffer(32), 8, 1).byteOffset, 8);
  });
  
  // Check BYTES_PER_ELEMENT
  cons.forEach(function(TypedArray) {
    assert.equal(TypedArray.BYTES_PER_ELEMENT, getByteWidth(TypedArray));
    assert.equal(new TypedArray().BYTES_PER_ELEMENT, getByteWidth(TypedArray));
    // Check flags of the field.
    var desc = Object.getOwnPropertyDescriptor(TypedArray, 'BYTES_PER_ELEMENT');
    assert.ok(!desc.writable);
    assert.ok(!desc.enumerable);
    assert.ok(!desc.configurable);
  
    desc = Object.getOwnPropertyDescriptor(
      TypedArray.prototype,
      'BYTES_PER_ELEMENT',
    );
    assert.ok(!desc.writable);
    assert.ok(!desc.enumerable);
    assert.ok(!desc.configurable);
  });
  
  // Check the flags for various fields.
  cons.forEach(function(TypedArray) {
    var proto = Object.getPrototypeOf(TypedArray);
    assert.ok(
      !Object.getOwnPropertyDescriptor(proto.prototype, 'buffer').enumerable,
    );
    assert.ok(
      !Object.getOwnPropertyDescriptor(proto.prototype, 'byteLength').enumerable,
    );
    assert.ok(
      !Object.getOwnPropertyDescriptor(proto.prototype, 'byteOffset').enumerable,
    );
  
    assert.ok(
      Object.getOwnPropertyDescriptor(proto.prototype, 'buffer').configurable,
    );
    assert.ok(
      Object.getOwnPropertyDescriptor(proto.prototype, 'byteLength').configurable,
    );
    assert.ok(
      Object.getOwnPropertyDescriptor(proto.prototype, 'byteOffset').configurable,
    );
  });
  
  // Check length of the constructors.
  cons.forEach(function(TypedArray) {
    assert.equal(TypedArray.length, 3);
  });
  
  // Check initialized to zero
  cons.forEach(function(TypedArray) {
    var buf = new ArrayBuffer(32);
    var view = new TypedArray(buf);
    for (var i = 0; i < view.length; i++) {
      assert.equal(view[i], 0);
    }
  });
  
  (function checkBufferShared() {
    var buf = new ArrayBuffer(32);
    var int8view = new Int8Array(buf);
    var uint8view = new Uint8Array(buf);
  
    // Check that the buffer is shared
    // Ensure they're both zero'd out before writing (in case previous tests left
    // data in them)
    int8view[0] = 0;
    uint8view[0] = 0;
    int8view[0] = 5;
    assert.equal(uint8view[0], 5);
  })();
  
  /// @name Constructors
  /// @{
  
  // Check constructor from Array with ints
  cons.forEach(function(TypedArray) {
    var view = new TypedArray([1, 2, 3]);
    assert.equal(view.length, 3);
    assert.equal(view[0], 1);
    assert.equal(view[1], 2);
    assert.equal(view[2], 3);
  });
  
  // Check constructor from Array with arbitrary types
  cons.forEach(function(TypedArray) {
    var view = new TypedArray(['1', {}, false]);
    assert.equal(view.length, 3);
    assert.equal(view[0], 1);
    if (TypedArray == Float32Array || TypedArray == Float64Array) {
      assert.equal(view[1], NaN);
    } else {
      assert.equal(view[1], 0);
    }
    assert.equal(view[2], 0);
  });
  
  // Check constructor from empty Array
  cons.forEach(function(TypedArray) {
    assert.equal(new TypedArray([]).length, 0);
  });
  
  // Constructor from undefined should give an empty TypedArray
  cons.forEach(function(TypedArray) {
    assert.equal(new TypedArray(undefined).length, 0);
  });
  
  // Check constructor from Array-esque object
  cons.forEach(function(TypedArray) {
    var arrayEsque = {length: 1};
    arrayEsque[0] = 1;
    var view = new TypedArray(arrayEsque);
    assert.equal(view.length, 1);
    assert.equal(view[0], 1);
  });
  
  // Empty constructor
  cons.forEach(function(TypedArray) {
    assert.equal(new TypedArray().length, 0);
  });
  
  // Constructor with length
  cons.forEach(function(TypedArray) {
    var view = new TypedArray(16);
    assert.equal(view.length, 16);
    assert.equal(view[0], 0);
  });
  
  // Constructor from buffer but with zero size
  cons.forEach(function(TypedArray) {
    var buf = new ArrayBuffer(32);
    var emptyArrayFromOtherBuffer = new TypedArray(buf, 16, 0);
    assert.equal(emptyArrayFromOtherBuffer.length, 0);
  });
  
  // Constructor from buffer with length smaller than offset
  cons.forEach(function(TypedArray) {
    var buf = new ArrayBuffer(32);
    var arrayFromBufferWithSmallLength = new TypedArray(buf, 8, 2);
    assert.equal(arrayFromBufferWithSmallLength.length, 2);
    assert.equal(arrayFromBufferWithSmallLength[0], 0);
    assert.equal(arrayFromBufferWithSmallLength[1], 0);
  });
  
  // Constructor from another TypedArray of the same type
  cons.forEach(function(TypedArray) {
    var original = new TypedArray(32);
    var sameTypeArray = new TypedArray(original);
    assert.equal(sameTypeArray.length, original.length);
    // The bytes should have been copied, and reside in a different buffer
    assert.notEqual(sameTypeArray.buffer, original.buffer);
  });
  
  (function checkLargeValuesInConstructor() {
    // Check constructor from Array with huge values
    // 256 should wrap around to be 0
    var consFromArray = new Uint8Array([256]);
    assert.equal(consFromArray.length, 1);
    assert.equal(consFromArray[0], 0);
  })();
  
  /// @}
  
  // Check for..of loop
  cons.forEach(function(TypedArray) {
    var arr = [10, 20, 30]
    var view = new TypedArray(arr);
    var result = [];
    for (var i of view)
      result.push(i);
    assert.arrayEqual(result, arr);
  });
  
  // Check for..in loop
  cons.forEach(function(TypedArray) {
    var view = new TypedArray(5);
    var result = [];
    for(var i in view)
      result.push(i);
    assert.arrayEqual(result, ["0", "1", "2", "3", "4"]);
    // Detach the buffer. Result should be the same because
    // IsDetachedBuffer is not checked in ES6 9.4.5.6 [[OwnPropertyKeys]].
    HermesInternal.detachArrayBuffer(view.buffer);
    result = [];
    for(var i in view)
      result.push(i);
    assert.arrayEqual(result, ["0", "1", "2", "3", "4"]);
  });
  
  // Check basic writability properties
  cons.forEach(function(TypedArray) {
    var view = new TypedArray(32);
    for (var i = 0; i < view.length; i++) {
      view[i] = i;
      assert.equal(view[i], i);
    }
  });
  
  // Check uint8clamped is clamped
  (function checkClamped() {
    var view = new Uint8ClampedArray(1);
    // Writing a value > 255 into uint8clampedview should give 255
    view[0] = 300;
    assert.equal(view[0], 255);
    // Also check for round-to-even behavior
    view[0] = 1.5;
    assert.equal(view[0], 2);
    view[0] = 2.5;
    assert.equal(view[0], 2);
  })();
  
  (function checkFloatMaxValue() {
    var view = new Float32Array(1);
    view[0] = Number.MAX_VALUE;
    assert.equal(view[0], Infinity);
  })();
  
  (function checkFloatSanitization() {
    // Check float is sanitized
    // Basis of this test is that in Hermes, a NaN can have a "payload" which
    // could represent a pointer. We must ensure that if such a value is read from,
    // the payload is sanitized out
    var buf = new ArrayBuffer(8);
    var uint8view = new Uint8Array(buf);
    var uint32view = new Uint32Array(buf);
    var float32view = new Float32Array(buf);
    var float64view = new Float64Array(buf);
    // all 1's
    uint32view[0] = 0xffffffff;
    assert.equal(float32view[0], NaN);
    // 64-bit version, need to use a uint8 array,
    // 0xff ff 00 01 00 e0 00 58
    // is an example tagged NaN value to sanitize
    if (LE) {
      // little-endian order of bytes
      uint8view[0] = 0x58;
      uint8view[1] = 0x00;
      uint8view[2] = 0xe0;
      uint8view[3] = 0x00;
      uint8view[4] = 0x01;
      uint8view[5] = 0x00;
      uint8view[6] = 0xff;
      uint8view[7] = 0xff;
    } else {
      // big-endian order of bytes
      uint8view[7] = 0xff;
      uint8view[6] = 0xff;
      uint8view[5] = 0x00;
      uint8view[4] = 0x01;
      uint8view[3] = 0x00;
      uint8view[2] = 0xe0;
      uint8view[1] = 0x00;
      uint8view[0] = 0x58;
    }
    assert.equal(float64view[0], NaN);
  })();
  
  (function checkConstructorFromDifferentType() {
    // Constructor from another TypedArray of a different type
    var int32view = new Int32Array([0, 1, 2, 3]);
    // This constructor copies the values
    var differentTypeArray = new Int16Array(int32view);
    assert.equal(differentTypeArray.length, int32view.length);
    // The bytes should have been copied
    for (var i = 0; i < differentTypeArray.length; i++) {
      assert.equal(differentTypeArray[i], i);
    }
  })();
  
  (function checkSignsInFloat() {
    // Signs in float
    var a = new Float64Array(4);
    a[0] = -0;
    assert.equal(1 / a[0], -Infinity);
  })();
  
  /// @name %TypedArray% in and delete
  /// @{
  cons.forEach(function(TA) {
    var ta = new TA([1,2,3,4,5]);
    assert.equal(false, -1 in ta);
    assert.equal(true, 0 in ta);
    assert.equal(true, 4 in ta);
    assert.equal(false, 5 in ta);
  
    assert.equal(true, delete ta[-1]);
    assert.throws(_ => delete ta[0], TypeError);
    assert.throws(_ => delete ta[4], TypeError);
    assert.equal(true, delete ta[5]);
  
    assert.equal(true, Reflect.deleteProperty(ta, -1));
    assert.equal(false, Reflect.deleteProperty(ta, 0));
    assert.equal(false, Reflect.deleteProperty(ta, 4));
    assert.equal(true, Reflect.deleteProperty(ta, 5));
  });
  /// @}
  
  /// @name %TypedArray%.prototype.buffer
  /// @{
  cons.forEach(function(TypedArray) {
    assert.throws(function() {
      TypedArray.prototype.buffer;
    }, TypeError);
  });
  /// @}
  
  /// @name %TypedArray%.prototype.copyWithin
  /// @{
  
  cons.forEach(function(TA) {
    assert.equal(new TA([1, 2, 3, 4, 5]).copyWithin(-2).toString(), '1,2,3,1,2');
    assert.equal(new TA([1, 2, 3, 4, 5]).copyWithin(0).toString(), '1,2,3,4,5');
    assert.equal(
      new TA([1, 2, 3, 4, 5]).copyWithin(0, 3, 4).toString(),
      '4,2,3,4,5',
    );
    assert.equal(
      new TA([1, 2, 3, 4, 5]).copyWithin(-2, -3, -1).toString(),
      '1,2,3,3,4',
    );
    if (HermesInternal.detachArrayBuffer) {
      var ta = new TA(1000);
      assert.throws(function() {
        ta.copyWithin(
          {
            valueOf: function() {
              HermesInternal.detachArrayBuffer(ta.buffer);
              return 1;
            },
          },
          4,
          256,
        );
      }, TypeError);
    }
  });
  
  (function() {
    // Ensure bit-level preservation.
    var A = new Float32Array(4);
    A[0] = 0 / 0;
    A[1] = -(0 / 0);
    var bytes1 = new Uint8Array(A.buffer, 0, 8);
    A.copyWithin(2, 0); // Copy bytes to the second half of A.
    var bytes2 = new Uint8Array(A.buffer, 8, 8);
    assert.equal(bytes1.length, bytes2.length);
    for (var i = 0; i < bytes1.length; ++i) {
      assert.equal(bytes1[i], bytes2[i]);
    }
  })();
  
  /// @}
  
  /// @name %TypedArray%.from
  /// @{
  
  cons.forEach(function(c, i) {
    // Function exists.
    assert.ok('from' in c);
    assert.ok(c.from);
  
    // Works on arrays.
    var ta = c.from([1, 2, 3]);
    assert.equal(ta.length, 3);
    assert.equal(ta[0], 1);
    assert.equal(ta[1], 2);
    assert.equal(ta[2], 3);
  
    // Works on a different typed array.
    var otherTA = new cons[i == 0 ? cons.length - 1 : i - 1]([1, 2, 3]);
    ta = c.from(otherTA);
    assert.equal(ta.length, 3);
    assert.equal(ta[0], 1);
    assert.equal(ta[1], 2);
    assert.equal(ta[2], 3);
  
    // "array-like" object.
    var arrayLike = {length: 3};
    arrayLike[0] = 1;
    arrayLike[1] = 2;
    arrayLike[2] = 3;
    ta = c.from(arrayLike);
    assert.equal(ta.length, 3);
    assert.equal(ta[0], 1);
    assert.equal(ta[1], 2);
    assert.equal(ta[2], 3);
  
    // Array with holes.
    ta = c.from([1, 2, , , 3]);
    assert.equal(ta.length, 5);
    assert.equal(ta[0], 1);
    assert.equal(ta[1], 2);
    // undefined is coerced to zero, except for floats which are NaN.
    if (c === Float32Array || c === Float64Array) {
      assert.equal(ta[2], NaN);
      assert.equal(ta[3], NaN);
    } else {
      assert.equal(ta[2], 0);
      assert.equal(ta[3], 0);
    }
    assert.equal(ta[4], 3);
  
    // Test calling without the this argument.
    var from = c.from;
    assert.throws(function() {
      from([]);
    }, TypeError);
  
    // Test a TypedArray whose length is greater than 2 ^ 32 - 1
    // NOTE: This behavior differs from v8 and JSC, because we use uint32_t as our
    // indexing type. They also disagree with each other.
    assert.throws(function() {
      var ta = new c();
      Object.defineProperty(ta, "length", {
        get: function() {
          // This number is 2 ^ 32 + 1.
          return 4294967297;
        }
      });
      return c.from(ta);
    }, RangeError);
  });
  
  /// @}
  
  /// @name %TypedArray%.of
  /// @{
  
  cons.forEach(function(TypedArray) {
    // Function exists.
    assert.ok('of' in TypedArray);
    assert.ok(TypedArray.of);
    assert.equal(TypedArray.of.length, 0);
  
    var ta = TypedArray.of(1, 2, 3);
    assert.equal(ta.length, 3);
    assert.equal(ta[0], 1);
    assert.equal(ta[1], 2);
    assert.equal(ta[2], 3);
  
    // Works on no arguments.
    ta = TypedArray.of();
    assert.equal(ta.length, 0);
  
    // Test calling without the this argument.
    var of = TypedArray.of;
    assert.throws(function() {
      of();
    }, TypeError);
  });
  
  // Returning a smaller array than requested.
  cons.forEach(function(TypedArray) {
    var thisArg = function() {
      return new TypedArray(1);
    };
  
    assert.throws(function() {
      TypedArray.of.call(thisArg, 1, 2, 3, 4);
    }, TypeError);
  });
  
  /// @}
  
  /// @name %TypedArray%.prototype.every && .some
  /// @{
  
  cons.forEach(function(TypedArray) {
    var view = new TypedArray([0, 1, 2, 3, 4]);
    // Check that callback function is passed parameters correctly
    assert.ok(
      view.every(function(elem, i, v) {
        return elem === i && v == view;
      }),
    );
  
    // Check basic properties
    assert.ok(
      view.every(function() {
        return true;
      }),
    );
    assert.ok(
      !view.every(function() {
        return false;
      }),
    );
  
    assert.ok(
      !view.every(function(elem, i) {
        return i !== 0;
      }),
    );
  
    // Check that callback function is passed parameters correctly
    assert.ok(
      !view.some(function(elem, i, v) {
        return !(elem === i && v == view);
      }),
    );
    // Check basic properties
    assert.ok(
      !view.some(function() {
        return false;
      }),
    );
    assert.ok(
      view.some(function() {
        return true;
      }),
    );
    assert.ok(
      view.some(function(elem, i) {
        if (i == 0) {
          return true;
        }
      }),
    );
  });
  
  /// @}
  
  /// @name %TypedArray%.prototype.fill
  /// @{
  
  cons.forEach(function(TypedArray) {
    var view = new TypedArray(4);
    view.fill(1);
    for (var i = 0; i < view.length; i++) {
      assert.equal(view[i], 1);
    }
  
    view.fill(2, 3);
    for (var i = 0; i < view.length; i++) {
      assert.equal(view[i], i < 3 ? 1 : 2);
    }
  
    view.fill(0);
    view.fill(1, 4, 6);
    for (var i = 0; i < view.length; i++) {
      assert.equal(view[i], i < 4 || i >= 6 ? 0 : 1);
    }
  
    view.fill(0);
    view.fill(1, 4, 100);
    for (var i = 0; i < view.length; i++) {
      assert.equal(view[i], i < 4 ? 0 : 1);
    }
  
    view.fill(0);
    view.fill(1, -100, 4);
    for (var i = 0; i < view.length; i++) {
      assert.equal(view[i], i < 4 ? 1 : 0);
    }
  
    view.fill(0);
    view.fill(1, -2, -1);
    for (var i = 0; i < view.length; i++) {
      assert.equal(view[i], i < view.length - 2 || i >= view.length - 1 ? 0 : 1);
    }
  
    view.fill(1);
    // This should not fill any elements.
    view.fill(0, Infinity);
    for (var i = 0; i < view.length; i++) {
      assert.equal(view[i], 1);
    }
    // This should fill all elements, Infinity is past the end.
    view.fill(2, 0, Infinity);
    for (var i = 0; i < view.length; i++) {
      assert.equal(view[i], 2);
    }
  
    // Calling fill on a detached TypedArray should throw TypeError.
    HermesInternal.detachArrayBuffer(view.buffer);
    assert.throws(function() {
      view.fill(0);
    }, TypeError);
  
    // Converting the first argument to a number can detach the TypedArray.
    view = new TypedArray(4);
    assert.throws(function() {
      view.fill({
        valueOf: function() {
          HermesInternal.detachArrayBuffer(view.buffer);
          return 1;
        },
      });
    }, TypeError);
  });
  
  cons.forEach(function(TypedArray) {
    // Fill with start >= end should remain the same.
    var arr = new TypedArray([0, 0, 0, 0]);
    arr.fill(8, 3, 1);
    assert.equal(arr.length, 4);
    assert.equal(arr[0], 0);
    assert.equal(arr[1], 0);
    assert.equal(arr[2], 0);
    assert.equal(arr[3], 0);
  
    arr.fill(8, -1, -3);
    assert.equal(arr.length, 4);
    assert.equal(arr[0], 0);
    assert.equal(arr[1], 0);
    assert.equal(arr[2], 0);
    assert.equal(arr[3], 0);
  });
  
  /// @}
  
  /// @name TypedArray.prototype.filter
  /// @{
  cons.forEach(function(TypedArray) {
    var arr = new TypedArray([0, 1, 2, 3]);
  
    // Result should be the same length and contain the same elements
    var filtered = arr.filter(function(elem, i, view) {
      return elem === i && view === arr;
    });
    // It should be a copy, not the same
    assert.notEqual(filtered, arr);
    assert.equal(filtered.length, arr.length);
    for (var i = 0; i < filtered.length; i++) {
      assert.equal(filtered[i], i);
    }
  
    filtered = arr.filter(function(_, i) {
      return i >= arr.length - 2 && i < arr.length;
    });
    assert.equal(filtered.length, 2);
    assert.equal(filtered[0], arr.length - 2);
    assert.equal(filtered[1], arr.length - 1);
  
    assert.throws(function() {
      arr.filter(function() {
        throw new RangeError();
      });
    }, RangeError);
  });
  /// @}
  
  /// @name TypedArray.prototype.findLast/.findLastIndex
  /// @{
  cons.forEach(function(TypedArray) {
    var arr = new TypedArray([0, 1, 2, 3]);
  
    var cb = function(elem, i, view) {
      assert.equal(view, arr);
      assert.equal(elem, i);
      return i === arr.length - 1;
    };
    assert.equal(arr.findLast(cb), arr.length - 1);
    assert.equal(arr.findLastIndex(cb), arr.length - 1);
    var numcalls = 0;
    cb = function() {
      ++numcalls;
      return true;
    };
    assert.equal(arr.findLast(cb), 3);
    assert.equal(arr.findLastIndex(cb), 3);
    assert.equal(numcalls, 2);
  
    cb = function() {
      return false;
    };
    assert.equal(arr.findLast(cb), undefined);
    assert.equal(arr.findLastIndex(cb), -1);
  
    var state = [];
    cb = function(elem, i, view) {
      state.push(elem);
      return elem === 2;
    };
    assert.equal(arr.findLast(cb), 2);
    assert.arrayEqual(state, [3, 2]);
  });
  /// @}
  
  /// @name TypedArray.prototype.find/.findIndex
  /// @{
  cons.forEach(function(TypedArray) {
    var arr = new TypedArray([0, 1, 2, 3]);
  
    var cb = function(elem, i, view) {
      assert.equal(view, arr);
      assert.equal(elem, i);
      return i === arr.length - 1;
    };
    assert.equal(arr.find(cb), arr.length - 1);
    assert.equal(arr.findIndex(cb), arr.length - 1);
    var numcalls = 0;
    cb = function() {
      ++numcalls;
      return true;
    };
    assert.equal(arr.find(cb), 0);
    assert.equal(arr.findIndex(cb), 0);
    assert.equal(numcalls, 2);
  
    cb = function() {
      return false;
    };
    assert.equal(arr.find(cb), undefined);
    assert.equal(arr.findIndex(cb), -1);
    var state = [];
    cb = function(elem, i, view) {
      state.push(elem);
      return elem === 2;
    };
    assert.equal(arr.find(cb), 2);
    assert.arrayEqual(state, [0, 1, 2]);
  });
  /// @}
  
  /// @name TypedArray.prototype.forEach
  /// @{
  cons.forEach(function(TypedArray) {
    var arr = new TypedArray([0, 1, 2, 3]);
  
    assert.equal(
      arr.forEach(function(elem, i, view) {
        assert.equal(elem, i);
        assert.equal(view, arr);
      }),
      undefined,
    );
  
    var numcalls = 0;
    arr.forEach(function() {
      numcalls++;
    });
    assert.equal(numcalls, arr.length);
  });
  /// @}
  
  /// @name TypedArray.prototype.includes && .indexOf
  /// @{
  cons.forEach(function(TypedArray) {
    var arr = new TypedArray([0, 1, 2, 3]);
    assert.ok(arr.includes(1));
    assert.equal(arr.indexOf(1), 1);
    assert.equal(arr.lastIndexOf(1), 1);
    assert.ok(!arr.includes(1000));
    assert.equal(arr.indexOf(1000), -1);
    assert.equal(arr.lastIndexOf(1000), -1);
  
    assert.ok(arr.includes(0, 0));
    assert.ok(!arr.includes(0, 1));
    assert.ok(!arr.includes(0, 1000));
    assert.equal(arr.indexOf(0, 0), 0);
    assert.equal(arr.indexOf(0, 1), -1);
    assert.equal(arr.indexOf(0, 1000), -1);
    assert.equal(arr.lastIndexOf(0, 0), 0);
    assert.equal(arr.lastIndexOf(0, 1), 0);
    assert.equal(arr.lastIndexOf(0, 1000), 0);
  
    assert.ok(arr.includes(arr.length - 2, -2));
    assert.ok(!arr.includes(arr.length - 3, -1));
    assert.equal(arr.indexOf(arr.length - 2, -2), arr.length - 2);
    assert.equal(arr.indexOf(arr.length - 3, -1), -1);
    assert.equal(arr.lastIndexOf(arr.length - 2, -2), arr.length - 2);
    assert.equal(arr.lastIndexOf(arr.length - 3, -1), arr.length - 3);
  
    // Set up duplicates to test indexOf vs lastIndexOf
    arr[0] = 50;
    arr[1] = 50;
    assert.equal(arr.indexOf(50), 0);
    assert.equal(arr.lastIndexOf(50), 1);
  
    assert.throws(function() {
      arr.includes(0, {
        valueOf() {
          HermesInternal.detachArrayBuffer(arr.buffer);
          return 0;
        },
      });
    }, TypeError);
  });
  /// @}
  
  /// @name TypedArray.prototype.join && .toString (since toString calls join)
  /// @{
  cons.forEach(function(ta) {
    var arr = new ta([1, 2, 3]);
    assert.equal(arr.join(), '1,2,3');
    assert.equal(arr.join(','), '1,2,3');
    assert.equal(arr.join(''), '123');
    assert.equal(arr.join('asdf'), '1asdf2asdf3');
  
    // Test empty case.
    assert.equal(new ta([]).join(), '');
  
    // Test toString.
    assert.equal(ta.prototype.toString, Array.prototype.toString);
    assert.equal(arr.toString(), arr.join());
    // Test difference between integral and floating toString
    if (ta === Float32Array || ta === Float64Array) {
      assert.equal(new ta([{}]).toString(), 'NaN');
    } else {
      assert.equal(new ta([{}]).toString(), '0', ta.toString());
    }
  });
  /// @}
  
  /// @name TypedArray.prototype.reverse
  /// @{
  cons.forEach(function(TypedArray) {
    var arr = new TypedArray([0, 1, 2, 3]);
  
    arr.reverse();
    for (var i = 0; i < arr.length; i++) {
      assert.equal(arr[i], arr.length - 1 - i);
    }
    var emptyReversed = new (Object.getPrototypeOf(arr)).constructor(
      [],
    ).reverse();
    assert.equal(emptyReversed.length, 0);
    var oddReversed = new (Object.getPrototypeOf(arr)).constructor([
      1,
      2,
      3,
    ]).reverse();
    assert.equal(oddReversed.length, 3);
    assert.equal(oddReversed[0], 3);
    assert.equal(oddReversed[1], 2);
    assert.equal(oddReversed[2], 1);
  });
  /// @}
  
  /// @name TypedArray.prototype.sort
  /// @{
  cons.forEach(function(ta) {
    var x = new ta([3, 2, 1]);
    x.sort();
    assert.equal(x[0], 1);
    assert.equal(x[1], 2);
    assert.equal(x[2], 3);
  
    // Check empty doesn't crash.
    x = new ta([]);
    x.sort();
    assert.equal(x.length, 0);
  
    // Check with comparefn.
    x = new ta([3, 2, 1]);
    // Use the reverse sorter, normal definition is a - b.
    x.sort(function(a, b) {
      return b - a;
    });
    assert.equal(x[0], 3);
    assert.equal(x[1], 2);
    assert.equal(x[2], 1);
  
    // Check stable.
    x = new ta([1, 111, 11, 22, 2, 33, 3]);
    x.sort(function(a, b) {
      return (a + "").length - (b + "").length;
    });
    assert.equal(x[0], 1);
    assert.equal(x[1], 2);
    assert.equal(x[2], 3);
    assert.equal(x[3], 11);
    assert.equal(x[4], 22);
    assert.equal(x[5], 33);
    assert.equal(x[6], 111);
  
    assert.throws(function() {
      x.sort(null);
    }, TypeError);
    assert.throws(function() {
      x.sort(true);
    }, TypeError);
    assert.throws(function() {
      x.sort(12);
    }, TypeError);
    assert.throws(function() {
      x.sort({});
    }, TypeError);
  
    // Sorting a TypedArray allocates handles linearly with respect to the size
    // of the buffer. Sorting a larger array will ensure that we clean those up
    // periodically.
    x = new ta(104);
    x.sort(function(unused1, unused2) {
      return true;
    });
    for (var i = 0; i < x.length; i++) {
      assert.equal(x[i], 0);
    }
  
    // Check that detaching in the middle of sorting will cause a TypeError.
    x = new ta([1, 2, 3]);
    assert.throws(function() {
      x.sort(function f(unused1, unused2) {
        var a = {};
        a.valueOf = function() {
          HermesInternal.detachArrayBuffer(x.buffer);
        };
        return a;
      });
    }, TypeError);
  });
  
  (function negativeZeroSort() {
    var x = new Float64Array([+0, -0]);
    x.sort();
    assert.equal(1 / x[0], -Infinity);
    assert.equal(1 / x[1], +Infinity);
  })();
  
  /// @}
  
  /// @name TypedArray.prototype.set
  /// @{
  (function checkPrototypeSet() {
    cons.forEach(function(ta, i) {
      var dst = new ta([1, 2, 3]);
      // Check setting to Object.
      dst.set([5]);
      assert.equal(dst[0], 5);
      // Check setting at an offset.
      dst.set([5], 2);
      assert.equal(dst[2], 5);
      assert.notEqual(dst[1], 5);
      // Check setting to larger object.
      dst.set([3, 2, 1]);
      assert.equal(dst[0], 3);
      assert.equal(dst[1], 2);
      assert.equal(dst[2], 1);
  
      // Check exception case of trying to set too large of an object.
      assert.throws(function() {
        dst.set([1, 2, 3, 4]);
      }, RangeError);
      assert.throws(function() {
        dst.set([1], 10);
      }, RangeError);
  
      dst = new ta([4, 5, 6]);
      // Check with other TypedArray of the same type.
      var other = new ta([1, 2]);
      dst.set(other);
      assert.equal(dst[0], 1);
      assert.equal(dst[1], 2);
      assert.equal(dst[2], 6);
  
      // Check with TypedArray of a different type.
      var otherCons = cons[i == 0 ? cons.length - 1 : i - 1];
      other = new otherCons([1, 2]);
      dst.set(other);
      assert.equal(dst[0], 1);
      assert.equal(dst[1], 2);
      assert.equal(dst[2], 6);
  
      // Check with self.
      dst = new ta([0, 1, 2]);
      dst.set(dst);
      for (var j = 0; j < dst.length; j++) {
        assert.equal(dst[j], j);
      }
      // New TypedArray pointing to the same memory location, but at a different
      // starting point.
      other = new ta(dst.buffer, getByteWidth(ta));
      assert.equal(other.length, dst.length - 1);
      assert.equal(other[0], 1);
      assert.equal(other[1], 2);
      // This should move the rest of the array leftwards 1 space.
      dst.set(other);
      for (var j = 0; j < dst.length - 1; j++) {
        assert.equal(dst[j], j + 1);
      }
      assert.equal(dst[dst.length - 1], dst.length - 1);
  
      // Check with setting to an empty TypedArray
      dst = new ta();
      dst.set(new ta());
      // Set empty to non-empty
      dst = new ta([1, 2, 3]);
      dst.set(new ta());
      // Set non-empty to empty should throw RangeError
      dst = new ta();
      assert.throws(function() {
        dst.set(new ta([1, 2, 3]));
      }, RangeError);
    });
    // Moving from one typed array view to another of the same data.
    var dst = new Int8Array([0, 1, 2, 3, 4, 5, 6, 7]);
    var src = new Int32Array(dst.buffer);
    dst.set(src);
    assert.equal(dst[0], 0);
    assert.equal(dst[1], 4);
    for (var i = 2; i < dst.length; i++) {
      assert.equal(dst[i], i);
    }
    // Check in reverse.
    dst = new Int8Array([7, 6, 5, 4, 3, 2, 1, 0]);
    src = new Int32Array(dst.buffer);
    dst.set(src);
    assert.equal(dst[0], 7);
    assert.equal(dst[1], 3);
    for (var i = 2; i < dst.length; i++) {
      assert.equal(dst[i], dst.length - 1 - i);
    }
  
    // Check smaller into bigger as well.
    dst = new Int32Array([5, 5, 0]);
    src = new Int8Array(dst.buffer, 9);
    // This should move the rest of the array leftwards 1 space.
    dst.set(src);
    assert.equal(dst[0], 0);
    assert.equal(dst[1], 0);
    assert.equal(dst[2], 0);
  
    // Check overlapping and src is before dst
    var buf = new Int8Array([1, 2, 3, 4]).buffer;
    dst = new Int8Array(buf, 2);
    src = new Int8Array(buf, 1, 2);
    dst.set(src);
    assert.equal(dst[0], 2);
    assert.equal(dst[1], 3);
  
    // Check that bitwise equivalence is preserved.
    var bytes = new Uint8Array([0xff, 0xff, 0xff, 0xff]);
    var flt = new Float32Array([1]);
    flt.set(new Float32Array(bytes.buffer));
    var chk = new Uint8Array(flt.buffer);
    assert.equal(chk[0], 0xff);
    assert.equal(chk[1], 0xff);
    assert.equal(chk[2], 0xff);
    assert.equal(chk[3], 0xff);
  
    // Check that detach check is called after returning to runtime.
    var typedarray = new Uint8Array(16);
    var evilNumber = {
      valueOf: function() {
        HermesInternal.detachArrayBuffer(typedarray.buffer);
        return 0;
      },
    };
    assert.throws(function() {
      typedarray.set([evilNumber, 5, 5], 5);
    }, TypeError);
  })();
  
  /// @name TypedArray.prototype.slice
  /// @{
  (function checkPrototypeSlice() {
    cons.forEach(function(TypedArray) {
      var arr = new TypedArray([0, 1, 2, 3]);
      var x = arr.slice(0, 2);
      assert.equal(x.length, 2);
      assert.equal(x[0], arr[0]);
      assert.equal(x[1], arr[1]);
  
      // Check for the case where end is undefined.
      x = arr.slice(1);
      assert.equal(x.length, arr.length - 1);
      for (var i = 0; i < x.length; i++) {
        assert.equal(x[i], i + 1);
      }
  
      // Check negatives.
      x = arr.slice(-2, -1);
      assert.equal(x.length, 1);
      assert.equal(x[0], arr.length - 2);
  
      x = arr.slice(-2);
      assert.equal(x.length, 2);
      assert.equal(x[0], arr.length - 2);
      assert.equal(x[1], arr.length - 1);
  
      // Check empty.
      arr = new (Object.getPrototypeOf(arr)).constructor([]);
      x = arr.slice(0);
      assert.equal(x.length, 0);
    });
    // Check that byte-wise equality is maintained.
    var bytes = new Uint8Array([0xff, 0xff, 0xff, 0xff]);
    var chk = new Uint8Array(new Float32Array(bytes.buffer).slice(0).buffer);
    assert.equal(chk[0], 0xff);
    assert.equal(chk[1], 0xff);
    assert.equal(chk[2], 0xff);
    assert.equal(chk[3], 0xff);
  })();
  /// @}
  
  /// @name TypedArray.prototype.subarray
  /// @{
  cons.forEach(function(ta) {
    var x = new ta([1, 2, 3]);
    // Check when it's the full length.
    var y = x.subarray(0, x.length);
    assert.equal(y.length, x.length);
    // They should share a buffer.
    assert.equal(y.buffer, x.buffer);
    for (var i = 0; i < x.length; i++) {
      assert.equal(y[i], x[i]);
    }
    // Check undefined second parameter.
    y = x.subarray(0);
    assert.equal(y.length, x.length);
    for (var i = 0; i < x.length; i++) {
      assert.equal(y[i], x[i]);
    }
    // Check smaller range.
    y = x.subarray(1);
    assert.equal(y.length, x.length - 1);
    for (var i = 0; i < y.length; i++) {
      assert.equal(y[i], x[i + 1]);
    }
    // Check negative start.
    y = x.subarray(-1);
    assert.equal(y.length, 1);
    assert.equal(y[0], x[x.length - 1]);
  
    // Check negative end.
    y = x.subarray(1, -1);
    assert.equal(y.length, x.length - 2);
    for (var i = 0; i < y.length; i++) {
      assert.equal(y[i], x[i + 1]);
    }
  
    // Check negative start and end.
    y = x.subarray(-2, -1);
    assert.equal(y.length, 1);
    assert.equal(y[0], x[x.length - 2]);
  
    // Check end < begin (zero length result).
    y = x.subarray(2, 0);
    assert.equal(y.length, 0);
  
    // Check that zero-sized array yields another zero size array.
    y = new ta(0).subarray();
    assert.equal(y.length, 0);
  
    // Check that creating a subarray from a subarray works, and doesn't read
    // off the end of the original.
    y = new ta(10);
    var z = y.subarray(5);
    z.subarray();
  });
  
  /// @name TypedArray.prototype.toLocaleString
  /// @{
  cons.forEach(function(TypedArray) {
    var arr = new TypedArray([1, 2, 3]);
    assert.equal(arr.toLocaleString(), '1,2,3');
    var n = 0;
    var oldToLocale = Number.prototype.toLocaleString;
    Number.prototype.toLocaleString = function() {
      ++n;
      return this;
    };
    assert.equal(arr.toLocaleString(), '1,2,3');
    assert.equal(n, 3);
    Number.prototype.toLocaleString = oldToLocale;
  });
  
  /// @name TypedArray.prototype.map
  /// @{
  cons.forEach(function(TypedArray) {
    var arr = new TypedArray([0, 1, 2, 3]);
    var other = arr.map(function(elem) {
      return elem + 1;
    });
    // Should be a copy, not the same.
    assert.notEqual(other, arr);
    assert.equal(other.length, arr.length);
    for (var i = 0; i < arr.length; i++) {
      assert.equal(other[i], arr[i] + 1);
    }
    // Check non-number usages.
    other = arr.map(function(elem) {
      return {
        valueOf: function() {
          return 0;
        },
      };
    });
    assert.equal(other.length, arr.length);
    for (var i = 0; i < other.length; i++) {
      assert.equal(other[i], 0);
    }
  });
  /// @}
  
  /// @name TypedArray.prototype.reduce && reduceRight
  /// @{
  cons.forEach(function(TypedArray) {
    var arr = new TypedArray([0, 1, 2, 3]);
    var count = function(acc) {
      return acc + 1;
    };
    var sum = function(acc, elem) {
      return acc + elem;
    };
    // sum(0, 1, ..., len - 1) == (len - 1) * (len) / 2
    var totalsum = (arr.length * (arr.length - 1)) / 2;
    assert.equal(arr.reduce(count, 0), arr.length);
    assert.equal(arr.reduce(sum), totalsum);
    assert.equal(arr.reduce(sum, 0), totalsum);
    assert.equal(arr.reduceRight(count, 0), arr.length);
    assert.equal(arr.reduceRight(sum), totalsum);
    assert.equal(arr.reduceRight(sum, 0), totalsum);
  
    // Check that it properly uses the first element
    assert.equal(
      arr.reduce(function(acc) {
        return acc;
      }),
      0,
    );
    assert.equal(
      arr.reduce(function(acc) {
        return acc;
      }, 1),
      1,
    );
    assert.equal(
      arr.reduceRight(function(acc) {
        return acc;
      }),
      arr.length - 1,
    );
    assert.equal(
      arr.reduceRight(function(acc) {
        return acc;
      }, 1),
      1,
    );
  
    // Check non-objects:
    var anEmptyObject = {};
    assert.equal(
      arr.reduce(function() {
        return anEmptyObject;
      }),
      anEmptyObject,
    );
    assert.equal(
      arr.reduceRight(function() {
        return anEmptyObject;
      }),
      anEmptyObject,
    );
  
    // Check empty array.
    var empty = new (Object.getPrototypeOf(arr)).constructor([]);
    var numcalls = 0;
    assert.throws(function() {
      empty.reduce(function() {});
    }, TypeError);
    assert.equal(
      empty.reduce(function() {
        numcalls++;
      }, 0),
      0,
    );
    assert.equal(numcalls, 0);
    numcalls = 0;
    assert.throws(function() {
      empty.reduceRight(function() {});
    }, TypeError);
    assert.equal(
      empty.reduceRight(function() {
        numcalls++;
      }, 0),
      0,
    );
    assert.equal(numcalls, 0);
  
    // Check reduce and reduceRight are different
    assert.equal(
      arr.reduce(function(acc, elem) {
        return elem;
      }),
      arr.length - 1,
    );
    assert.equal(
      arr.reduceRight(function(acc, elem) {
        return elem;
      }),
      0,
    );
  });
  /// @}
  
  /// @name Exception cases
  /// @{
  
  // Constructor with non-evenly-divisable length
  assert.throws(function() {
    new Int32Array(new ArrayBuffer(9));
  }, RangeError);
  
  // Constructor with negative offset
  assert.throws(function() {
    new Int8Array(new ArrayBuffer(8), -1);
  }, RangeError);
  
  // Constructor with offset not aligned
  assert.throws(function() {
    new Int32Array(new ArrayBuffer(8), 3);
  }, RangeError);
  
  // Constructor with offset out of bounds
  assert.throws(function() {
    new Int8Array(new ArrayBuffer(8), 9);
  }, RangeError);
  
  // Constructor with offset + length out of bounds
  assert.throws(function() {
    new Int8Array(new ArrayBuffer(8), 5, 5);
  }, RangeError);
  
  // TypedArray shouldn't be a symbol.
  assert.throws(function() {
    print(TypedArray);
  }, ReferenceError);
  
  /// @}
  
  print("OK");
  //CHECK-NEXT:OK
  