Home | History | Annotate | Download | only in js
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 (function(global, utils) {
      6 
      7 "use strict";
      8 
      9 %CheckIsBootstrapping();
     10 
     11 // -------------------------------------------------------------------
     12 // Imports
     13 
     14 var ArrayFrom;
     15 var ArrayToString;
     16 var ArrayValues;
     17 var GlobalArray = global.Array;
     18 var GlobalArrayBuffer = global.ArrayBuffer;
     19 var GlobalDataView = global.DataView;
     20 var GlobalObject = global.Object;
     21 var InternalArray = utils.InternalArray;
     22 var InnerArrayCopyWithin;
     23 var InnerArrayEvery;
     24 var InnerArrayFill;
     25 var InnerArrayFilter;
     26 var InnerArrayFind;
     27 var InnerArrayFindIndex;
     28 var InnerArrayForEach;
     29 var InnerArrayIncludes;
     30 var InnerArrayIndexOf;
     31 var InnerArrayJoin;
     32 var InnerArrayLastIndexOf;
     33 var InnerArrayReduce;
     34 var InnerArrayReduceRight;
     35 var InnerArraySome;
     36 var InnerArraySort;
     37 var InnerArrayToLocaleString;
     38 var InternalArray = utils.InternalArray;
     39 var IsNaN;
     40 var MakeRangeError;
     41 var MakeTypeError;
     42 var MaxSimple;
     43 var MinSimple;
     44 var PackedArrayReverse;
     45 var SpeciesConstructor;
     46 var ToPositiveInteger;
     47 var iteratorSymbol = utils.ImportNow("iterator_symbol");
     48 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
     49 
     50 macro TYPED_ARRAYS(FUNCTION)
     51 // arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
     52 FUNCTION(1, Uint8Array, 1)
     53 FUNCTION(2, Int8Array, 1)
     54 FUNCTION(3, Uint16Array, 2)
     55 FUNCTION(4, Int16Array, 2)
     56 FUNCTION(5, Uint32Array, 4)
     57 FUNCTION(6, Int32Array, 4)
     58 FUNCTION(7, Float32Array, 4)
     59 FUNCTION(8, Float64Array, 8)
     60 FUNCTION(9, Uint8ClampedArray, 1)
     61 endmacro
     62 
     63 macro DECLARE_GLOBALS(INDEX, NAME, SIZE)
     64 var GlobalNAME = global.NAME;
     65 endmacro
     66 
     67 TYPED_ARRAYS(DECLARE_GLOBALS)
     68 
     69 utils.Import(function(from) {
     70   ArrayFrom = from.ArrayFrom;
     71   ArrayToString = from.ArrayToString;
     72   ArrayValues = from.ArrayValues;
     73   InnerArrayCopyWithin = from.InnerArrayCopyWithin;
     74   InnerArrayEvery = from.InnerArrayEvery;
     75   InnerArrayFill = from.InnerArrayFill;
     76   InnerArrayFilter = from.InnerArrayFilter;
     77   InnerArrayFind = from.InnerArrayFind;
     78   InnerArrayFindIndex = from.InnerArrayFindIndex;
     79   InnerArrayForEach = from.InnerArrayForEach;
     80   InnerArrayIncludes = from.InnerArrayIncludes;
     81   InnerArrayIndexOf = from.InnerArrayIndexOf;
     82   InnerArrayJoin = from.InnerArrayJoin;
     83   InnerArrayLastIndexOf = from.InnerArrayLastIndexOf;
     84   InnerArrayReduce = from.InnerArrayReduce;
     85   InnerArrayReduceRight = from.InnerArrayReduceRight;
     86   InnerArraySome = from.InnerArraySome;
     87   InnerArraySort = from.InnerArraySort;
     88   InnerArrayToLocaleString = from.InnerArrayToLocaleString;
     89   IsNaN = from.IsNaN;
     90   MakeRangeError = from.MakeRangeError;
     91   MakeTypeError = from.MakeTypeError;
     92   MaxSimple = from.MaxSimple;
     93   MinSimple = from.MinSimple;
     94   PackedArrayReverse = from.PackedArrayReverse;
     95   SpeciesConstructor = from.SpeciesConstructor;
     96   ToPositiveInteger = from.ToPositiveInteger;
     97 });
     98 
     99 // --------------- Typed Arrays ---------------------
    100 
    101 function TypedArrayDefaultConstructor(typedArray) {
    102   switch (%_ClassOf(typedArray)) {
    103 macro TYPED_ARRAY_CONSTRUCTOR_CASE(ARRAY_ID, NAME, ELEMENT_SIZE)
    104     case "NAME":
    105       return GlobalNAME;
    106 endmacro
    107 TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTOR_CASE)
    108   }
    109   // The TypeError should not be generated since all callers should
    110   // have already called ValidateTypedArray.
    111   throw MakeTypeError(kIncompatibleMethodReceiver,
    112                       "TypedArrayDefaultConstructor", this);
    113 }
    114 
    115 function TypedArrayCreate(constructor, arg0, arg1, arg2) {
    116   if (IS_UNDEFINED(arg1)) {
    117     var newTypedArray = new constructor(arg0);
    118   } else {
    119     var newTypedArray = new constructor(arg0, arg1, arg2);
    120   }
    121   if (!%_IsTypedArray(newTypedArray)) throw MakeTypeError(kNotTypedArray);
    122   // TODO(littledan): Check for being detached, here and elsewhere
    123   // All callers where the first argument is a Number have no additional
    124   // arguments.
    125   if (IS_NUMBER(arg0) && %_TypedArrayGetLength(newTypedArray) < arg0) {
    126     throw MakeTypeError(kTypedArrayTooShort);
    127   }
    128   return newTypedArray;
    129 }
    130 
    131 function TypedArraySpeciesCreate(exemplar, arg0, arg1, arg2, conservative) {
    132   var defaultConstructor = TypedArrayDefaultConstructor(exemplar);
    133   var constructor = SpeciesConstructor(exemplar, defaultConstructor,
    134                                        conservative);
    135   return TypedArrayCreate(constructor, arg0, arg1, arg2);
    136 }
    137 
    138 macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
    139 function NAMEConstructByArrayBuffer(obj, buffer, byteOffset, length) {
    140   if (!IS_UNDEFINED(byteOffset)) {
    141     byteOffset = ToPositiveInteger(byteOffset, kInvalidTypedArrayLength);
    142   }
    143   if (!IS_UNDEFINED(length)) {
    144     length = ToPositiveInteger(length, kInvalidTypedArrayLength);
    145   }
    146 
    147   var bufferByteLength = %_ArrayBufferGetByteLength(buffer);
    148   var offset;
    149   if (IS_UNDEFINED(byteOffset)) {
    150     offset = 0;
    151   } else {
    152     offset = byteOffset;
    153 
    154     if (offset % ELEMENT_SIZE !== 0) {
    155       throw MakeRangeError(kInvalidTypedArrayAlignment,
    156                            "start offset", "NAME", ELEMENT_SIZE);
    157     }
    158     if (offset > bufferByteLength) {
    159       throw MakeRangeError(kInvalidTypedArrayOffset);
    160     }
    161   }
    162 
    163   var newByteLength;
    164   var newLength;
    165   if (IS_UNDEFINED(length)) {
    166     if (bufferByteLength % ELEMENT_SIZE !== 0) {
    167       throw MakeRangeError(kInvalidTypedArrayAlignment,
    168                            "byte length", "NAME", ELEMENT_SIZE);
    169     }
    170     newByteLength = bufferByteLength - offset;
    171     newLength = newByteLength / ELEMENT_SIZE;
    172   } else {
    173     var newLength = length;
    174     newByteLength = newLength * ELEMENT_SIZE;
    175   }
    176   if ((offset + newByteLength > bufferByteLength)
    177       || (newLength > %_MaxSmi())) {
    178     throw MakeRangeError(kInvalidTypedArrayLength);
    179   }
    180   %_TypedArrayInitialize(obj, ARRAY_ID, buffer, offset, newByteLength, true);
    181 }
    182 
    183 function NAMEConstructByLength(obj, length) {
    184   var l = IS_UNDEFINED(length) ?
    185     0 : ToPositiveInteger(length, kInvalidTypedArrayLength);
    186   if (l > %_MaxSmi()) {
    187     throw MakeRangeError(kInvalidTypedArrayLength);
    188   }
    189   var byteLength = l * ELEMENT_SIZE;
    190   if (byteLength > %_TypedArrayMaxSizeInHeap()) {
    191     var buffer = new GlobalArrayBuffer(byteLength);
    192     %_TypedArrayInitialize(obj, ARRAY_ID, buffer, 0, byteLength, true);
    193   } else {
    194     %_TypedArrayInitialize(obj, ARRAY_ID, null, 0, byteLength, true);
    195   }
    196 }
    197 
    198 function NAMEConstructByArrayLike(obj, arrayLike) {
    199   var length = arrayLike.length;
    200   var l = ToPositiveInteger(length, kInvalidTypedArrayLength);
    201 
    202   if (l > %_MaxSmi()) {
    203     throw MakeRangeError(kInvalidTypedArrayLength);
    204   }
    205   var initialized = false;
    206   var byteLength = l * ELEMENT_SIZE;
    207   if (byteLength <= %_TypedArrayMaxSizeInHeap()) {
    208     %_TypedArrayInitialize(obj, ARRAY_ID, null, 0, byteLength, false);
    209   } else {
    210     initialized =
    211         %TypedArrayInitializeFromArrayLike(obj, ARRAY_ID, arrayLike, l);
    212   }
    213   if (!initialized) {
    214     for (var i = 0; i < l; i++) {
    215       // It is crucial that we let any execptions from arrayLike[i]
    216       // propagate outside the function.
    217       obj[i] = arrayLike[i];
    218     }
    219   }
    220 }
    221 
    222 function NAMEConstructByIterable(obj, iterable, iteratorFn) {
    223   var list = new InternalArray();
    224   // Reading the Symbol.iterator property of iterable twice would be
    225   // observable with getters, so instead, we call the function which
    226   // was already looked up, and wrap it in another iterable. The
    227   // __proto__ of the new iterable is set to null to avoid any chance
    228   // of modifications to Object.prototype being observable here.
    229   var iterator = %_Call(iteratorFn, iterable);
    230   var newIterable = {
    231     __proto__: null
    232   };
    233   // TODO(littledan): Computed properties don't work yet in nosnap.
    234   // Rephrase when they do.
    235   newIterable[iteratorSymbol] = function() { return iterator; }
    236   for (var value of newIterable) {
    237     list.push(value);
    238   }
    239   NAMEConstructByArrayLike(obj, list);
    240 }
    241 
    242 function NAMEConstructor(arg1, arg2, arg3) {
    243   if (!IS_UNDEFINED(new.target)) {
    244     if (IS_ARRAYBUFFER(arg1) || IS_SHAREDARRAYBUFFER(arg1)) {
    245       NAMEConstructByArrayBuffer(this, arg1, arg2, arg3);
    246     } else if (IS_NUMBER(arg1) || IS_STRING(arg1) ||
    247                IS_BOOLEAN(arg1) || IS_UNDEFINED(arg1)) {
    248       NAMEConstructByLength(this, arg1);
    249     } else {
    250       // TODO(littledan): If arg1 is a TypedArray, follow the constructor
    251       // path in ES2015 22.2.4.3, and call SpeciesConstructor, in a
    252       // path that seems to be an optimized version of what's below, but
    253       // in an observably different way.
    254       var iteratorFn = arg1[iteratorSymbol];
    255       if (IS_UNDEFINED(iteratorFn) || iteratorFn === ArrayValues) {
    256         NAMEConstructByArrayLike(this, arg1);
    257       } else {
    258         NAMEConstructByIterable(this, arg1, iteratorFn);
    259       }
    260     }
    261   } else {
    262     throw MakeTypeError(kConstructorNotFunction, "NAME")
    263   }
    264 }
    265 
    266 // TODO(littledan): Remove this performance workaround BUG(chromium:579905)
    267 function NAME_GetLength() {
    268   if (!(%_ClassOf(this) === 'NAME')) {
    269     throw MakeTypeError(kIncompatibleMethodReceiver, "NAME.length", this);
    270   }
    271   return %_TypedArrayGetLength(this);
    272 }
    273 
    274 function NAMESubArray(begin, end) {
    275   var beginInt = TO_INTEGER(begin);
    276   if (!IS_UNDEFINED(end)) {
    277     var endInt = TO_INTEGER(end);
    278     var srcLength = %_TypedArrayGetLength(this);
    279   } else {
    280     var srcLength = %_TypedArrayGetLength(this);
    281     var endInt = srcLength;
    282   }
    283 
    284   if (beginInt < 0) {
    285     beginInt = MaxSimple(0, srcLength + beginInt);
    286   } else {
    287     beginInt = MinSimple(beginInt, srcLength);
    288   }
    289 
    290   if (endInt < 0) {
    291     endInt = MaxSimple(0, srcLength + endInt);
    292   } else {
    293     endInt = MinSimple(endInt, srcLength);
    294   }
    295 
    296   if (endInt < beginInt) {
    297     endInt = beginInt;
    298   }
    299 
    300   var newLength = endInt - beginInt;
    301   var beginByteOffset =
    302       %_ArrayBufferViewGetByteOffset(this) + beginInt * ELEMENT_SIZE;
    303   return TypedArraySpeciesCreate(this, %TypedArrayGetBuffer(this),
    304                                  beginByteOffset, newLength, true);
    305 }
    306 endmacro
    307 
    308 TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTOR)
    309 
    310 function TypedArraySubArray(begin, end) {
    311   switch (%_ClassOf(this)) {
    312 macro TYPED_ARRAY_SUBARRAY_CASE(ARRAY_ID, NAME, ELEMENT_SIZE)
    313     case "NAME":
    314       return %_Call(NAMESubArray, this, begin, end);
    315 endmacro
    316 TYPED_ARRAYS(TYPED_ARRAY_SUBARRAY_CASE)
    317   }
    318   throw MakeTypeError(kIncompatibleMethodReceiver,
    319                       "get TypedArray.prototype.subarray", this);
    320 }
    321 %SetForceInlineFlag(TypedArraySubArray);
    322 
    323 function TypedArrayGetBuffer() {
    324   if (!%_IsTypedArray(this)) {
    325     throw MakeTypeError(kIncompatibleMethodReceiver,
    326                         "get TypedArray.prototype.buffer", this);
    327   }
    328   return %TypedArrayGetBuffer(this);
    329 }
    330 %SetForceInlineFlag(TypedArrayGetBuffer);
    331 
    332 function TypedArrayGetByteLength() {
    333   if (!%_IsTypedArray(this)) {
    334     throw MakeTypeError(kIncompatibleMethodReceiver,
    335                         "get TypedArray.prototype.byteLength", this);
    336   }
    337   return %_ArrayBufferViewGetByteLength(this);
    338 }
    339 %SetForceInlineFlag(TypedArrayGetByteLength);
    340 
    341 function TypedArrayGetByteOffset() {
    342   if (!%_IsTypedArray(this)) {
    343     throw MakeTypeError(kIncompatibleMethodReceiver,
    344                         "get TypedArray.prototype.byteOffset", this);
    345   }
    346   return %_ArrayBufferViewGetByteOffset(this);
    347 }
    348 %SetForceInlineFlag(TypedArrayGetByteOffset);
    349 
    350 function TypedArrayGetLength() {
    351   if (!%_IsTypedArray(this)) {
    352     throw MakeTypeError(kIncompatibleMethodReceiver,
    353                         "get TypedArray.prototype.length", this);
    354   }
    355   return %_TypedArrayGetLength(this);
    356 }
    357 %SetForceInlineFlag(TypedArrayGetLength);
    358 
    359 
    360 
    361 function TypedArraySetFromArrayLike(target, source, sourceLength, offset) {
    362   if (offset > 0) {
    363     for (var i = 0; i < sourceLength; i++) {
    364       target[offset + i] = source[i];
    365     }
    366   }
    367   else {
    368     for (var i = 0; i < sourceLength; i++) {
    369       target[i] = source[i];
    370     }
    371   }
    372 }
    373 
    374 function TypedArraySetFromOverlappingTypedArray(target, source, offset) {
    375   var sourceElementSize = source.BYTES_PER_ELEMENT;
    376   var targetElementSize = target.BYTES_PER_ELEMENT;
    377   var sourceLength = source.length;
    378 
    379   // Copy left part.
    380   function CopyLeftPart() {
    381     // First un-mutated byte after the next write
    382     var targetPtr = target.byteOffset + (offset + 1) * targetElementSize;
    383     // Next read at sourcePtr. We do not care for memory changing before
    384     // sourcePtr - we have already copied it.
    385     var sourcePtr = source.byteOffset;
    386     for (var leftIndex = 0;
    387          leftIndex < sourceLength && targetPtr <= sourcePtr;
    388          leftIndex++) {
    389       target[offset + leftIndex] = source[leftIndex];
    390       targetPtr += targetElementSize;
    391       sourcePtr += sourceElementSize;
    392     }
    393     return leftIndex;
    394   }
    395   var leftIndex = CopyLeftPart();
    396 
    397   // Copy rigth part;
    398   function CopyRightPart() {
    399     // First unmutated byte before the next write
    400     var targetPtr =
    401       target.byteOffset + (offset + sourceLength - 1) * targetElementSize;
    402     // Next read before sourcePtr. We do not care for memory changing after
    403     // sourcePtr - we have already copied it.
    404     var sourcePtr =
    405       source.byteOffset + sourceLength * sourceElementSize;
    406     for(var rightIndex = sourceLength - 1;
    407         rightIndex >= leftIndex && targetPtr >= sourcePtr;
    408         rightIndex--) {
    409       target[offset + rightIndex] = source[rightIndex];
    410       targetPtr -= targetElementSize;
    411       sourcePtr -= sourceElementSize;
    412     }
    413     return rightIndex;
    414   }
    415   var rightIndex = CopyRightPart();
    416 
    417   var temp = new GlobalArray(rightIndex + 1 - leftIndex);
    418   for (var i = leftIndex; i <= rightIndex; i++) {
    419     temp[i - leftIndex] = source[i];
    420   }
    421   for (i = leftIndex; i <= rightIndex; i++) {
    422     target[offset + i] = temp[i - leftIndex];
    423   }
    424 }
    425 
    426 function TypedArraySet(obj, offset) {
    427   var intOffset = IS_UNDEFINED(offset) ? 0 : TO_INTEGER(offset);
    428   if (intOffset < 0) throw MakeTypeError(kTypedArraySetNegativeOffset);
    429 
    430   if (intOffset > %_MaxSmi()) {
    431     throw MakeRangeError(kTypedArraySetSourceTooLarge);
    432   }
    433   switch (%TypedArraySetFastCases(this, obj, intOffset)) {
    434     // These numbers should be synchronized with runtime.cc.
    435     case 0: // TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE
    436       return;
    437     case 1: // TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING
    438       TypedArraySetFromOverlappingTypedArray(this, obj, intOffset);
    439       return;
    440     case 2: // TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING
    441       TypedArraySetFromArrayLike(this, obj, obj.length, intOffset);
    442       return;
    443     case 3: // TYPED_ARRAY_SET_NON_TYPED_ARRAY
    444       var l = obj.length;
    445       if (IS_UNDEFINED(l)) {
    446         if (IS_NUMBER(obj)) {
    447             // For number as a first argument, throw TypeError
    448             // instead of silently ignoring the call, so that
    449             // the user knows (s)he did something wrong.
    450             // (Consistent with Firefox and Blink/WebKit)
    451             throw MakeTypeError(kInvalidArgument);
    452         }
    453         return;
    454       }
    455       l = TO_LENGTH(l);
    456       if (intOffset + l > this.length) {
    457         throw MakeRangeError(kTypedArraySetSourceTooLarge);
    458       }
    459       TypedArraySetFromArrayLike(this, obj, l, intOffset);
    460       return;
    461   }
    462 }
    463 
    464 function TypedArrayGetToStringTag() {
    465   if (!%_IsTypedArray(this)) return;
    466   var name = %_ClassOf(this);
    467   if (IS_UNDEFINED(name)) return;
    468   return name;
    469 }
    470 
    471 
    472 function TypedArrayCopyWithin(target, start, end) {
    473   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    474 
    475   var length = %_TypedArrayGetLength(this);
    476 
    477   // TODO(littledan): Replace with a memcpy for better performance
    478   return InnerArrayCopyWithin(target, start, end, this, length);
    479 }
    480 %FunctionSetLength(TypedArrayCopyWithin, 2);
    481 
    482 
    483 // ES6 draft 05-05-15, section 22.2.3.7
    484 function TypedArrayEvery(f, receiver) {
    485   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    486 
    487   var length = %_TypedArrayGetLength(this);
    488 
    489   return InnerArrayEvery(f, receiver, this, length);
    490 }
    491 %FunctionSetLength(TypedArrayEvery, 1);
    492 
    493 
    494 // ES6 draft 08-24-14, section 22.2.3.12
    495 function TypedArrayForEach(f, receiver) {
    496   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    497 
    498   var length = %_TypedArrayGetLength(this);
    499 
    500   InnerArrayForEach(f, receiver, this, length);
    501 }
    502 %FunctionSetLength(TypedArrayForEach, 1);
    503 
    504 
    505 // ES6 draft 04-05-14 section 22.2.3.8
    506 function TypedArrayFill(value, start, end) {
    507   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    508 
    509   var length = %_TypedArrayGetLength(this);
    510 
    511   return InnerArrayFill(value, start, end, this, length);
    512 }
    513 %FunctionSetLength(TypedArrayFill, 1);
    514 
    515 
    516 // ES6 draft 07-15-13, section 22.2.3.9
    517 function TypedArrayFilter(f, thisArg) {
    518   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    519 
    520   var length = %_TypedArrayGetLength(this);
    521   if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
    522   var result = new InternalArray();
    523   InnerArrayFilter(f, thisArg, this, length, result);
    524   var captured = result.length;
    525   var output = TypedArraySpeciesCreate(this, captured);
    526   for (var i = 0; i < captured; i++) {
    527     output[i] = result[i];
    528   }
    529   return output;
    530 }
    531 %FunctionSetLength(TypedArrayFilter, 1);
    532 
    533 
    534 // ES6 draft 07-15-13, section 22.2.3.10
    535 function TypedArrayFind(predicate, thisArg) {
    536   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    537 
    538   var length = %_TypedArrayGetLength(this);
    539 
    540   return InnerArrayFind(predicate, thisArg, this, length);
    541 }
    542 %FunctionSetLength(TypedArrayFind, 1);
    543 
    544 
    545 // ES6 draft 07-15-13, section 22.2.3.11
    546 function TypedArrayFindIndex(predicate, thisArg) {
    547   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    548 
    549   var length = %_TypedArrayGetLength(this);
    550 
    551   return InnerArrayFindIndex(predicate, thisArg, this, length);
    552 }
    553 %FunctionSetLength(TypedArrayFindIndex, 1);
    554 
    555 
    556 // ES6 draft 05-18-15, section 22.2.3.21
    557 function TypedArrayReverse() {
    558   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    559 
    560   var length = %_TypedArrayGetLength(this);
    561 
    562   return PackedArrayReverse(this, length);
    563 }
    564 
    565 
    566 function TypedArrayComparefn(x, y) {
    567   if (IsNaN(x) && IsNaN(y)) {
    568     return IsNaN(y) ? 0 : 1;
    569   }
    570   if (IsNaN(x)) {
    571     return 1;
    572   }
    573   if (x === 0 && x === y) {
    574     if (%_IsMinusZero(x)) {
    575       if (!%_IsMinusZero(y)) {
    576         return -1;
    577       }
    578     } else if (%_IsMinusZero(y)) {
    579       return 1;
    580     }
    581   }
    582   return x - y;
    583 }
    584 
    585 
    586 // ES6 draft 05-18-15, section 22.2.3.25
    587 function TypedArraySort(comparefn) {
    588   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    589 
    590   var length = %_TypedArrayGetLength(this);
    591 
    592   if (IS_UNDEFINED(comparefn)) {
    593     comparefn = TypedArrayComparefn;
    594   }
    595 
    596   return InnerArraySort(this, length, comparefn);
    597 }
    598 
    599 
    600 // ES6 section 22.2.3.13
    601 function TypedArrayIndexOf(element, index) {
    602   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    603 
    604   var length = %_TypedArrayGetLength(this);
    605   return InnerArrayIndexOf(this, element, index, length);
    606 }
    607 %FunctionSetLength(TypedArrayIndexOf, 1);
    608 
    609 
    610 // ES6 section 22.2.3.16
    611 function TypedArrayLastIndexOf(element, index) {
    612   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    613 
    614   var length = %_TypedArrayGetLength(this);
    615 
    616   return InnerArrayLastIndexOf(this, element, index, length,
    617                         %_ArgumentsLength());
    618 }
    619 %FunctionSetLength(TypedArrayLastIndexOf, 1);
    620 
    621 
    622 // ES6 draft 07-15-13, section 22.2.3.18
    623 function TypedArrayMap(f, thisArg) {
    624   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    625 
    626   var length = %_TypedArrayGetLength(this);
    627   var result = TypedArraySpeciesCreate(this, length);
    628   if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
    629   for (var i = 0; i < length; i++) {
    630     var element = this[i];
    631     result[i] = %_Call(f, thisArg, element, i, this);
    632   }
    633   return result;
    634 }
    635 %FunctionSetLength(TypedArrayMap, 1);
    636 
    637 
    638 // ES6 draft 05-05-15, section 22.2.3.24
    639 function TypedArraySome(f, receiver) {
    640   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    641 
    642   var length = %_TypedArrayGetLength(this);
    643 
    644   return InnerArraySome(f, receiver, this, length);
    645 }
    646 %FunctionSetLength(TypedArraySome, 1);
    647 
    648 
    649 // ES6 section 22.2.3.27
    650 function TypedArrayToLocaleString() {
    651   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    652 
    653   var length = %_TypedArrayGetLength(this);
    654 
    655   return InnerArrayToLocaleString(this, length);
    656 }
    657 
    658 
    659 // ES6 section 22.2.3.28
    660 function TypedArrayToString() {
    661   return %_Call(ArrayToString, this);
    662 }
    663 
    664 
    665 // ES6 section 22.2.3.14
    666 function TypedArrayJoin(separator) {
    667   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    668 
    669   var length = %_TypedArrayGetLength(this);
    670 
    671   return InnerArrayJoin(separator, this, length);
    672 }
    673 
    674 
    675 // ES6 draft 07-15-13, section 22.2.3.19
    676 function TypedArrayReduce(callback, current) {
    677   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    678 
    679   var length = %_TypedArrayGetLength(this);
    680   return InnerArrayReduce(callback, current, this, length,
    681                           %_ArgumentsLength());
    682 }
    683 %FunctionSetLength(TypedArrayReduce, 1);
    684 
    685 
    686 // ES6 draft 07-15-13, section 22.2.3.19
    687 function TypedArrayReduceRight(callback, current) {
    688   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    689 
    690   var length = %_TypedArrayGetLength(this);
    691   return InnerArrayReduceRight(callback, current, this, length,
    692                                %_ArgumentsLength());
    693 }
    694 %FunctionSetLength(TypedArrayReduceRight, 1);
    695 
    696 
    697 function TypedArraySlice(start, end) {
    698   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    699   var len = %_TypedArrayGetLength(this);
    700 
    701   var relativeStart = TO_INTEGER(start);
    702 
    703   var k;
    704   if (relativeStart < 0) {
    705     k = MaxSimple(len + relativeStart, 0);
    706   } else {
    707     k = MinSimple(relativeStart, len);
    708   }
    709 
    710   var relativeEnd;
    711   if (IS_UNDEFINED(end)) {
    712     relativeEnd = len;
    713   } else {
    714     relativeEnd = TO_INTEGER(end);
    715   }
    716 
    717   var final;
    718   if (relativeEnd < 0) {
    719     final = MaxSimple(len + relativeEnd, 0);
    720   } else {
    721     final = MinSimple(relativeEnd, len);
    722   }
    723 
    724   var count = MaxSimple(final - k, 0);
    725   var array = TypedArraySpeciesCreate(this, count);
    726   // The code below is the 'then' branch; the 'else' branch species
    727   // a memcpy. Because V8 doesn't canonicalize NaN, the difference is
    728   // unobservable.
    729   var n = 0;
    730   while (k < final) {
    731     var kValue = this[k];
    732     array[n] = kValue;
    733     k++;
    734     n++;
    735   }
    736   return array;
    737 }
    738 
    739 
    740 // ES2016 draft, section 22.2.3.14
    741 function TypedArrayIncludes(searchElement, fromIndex) {
    742   if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
    743 
    744   var length = %_TypedArrayGetLength(this);
    745 
    746   return InnerArrayIncludes(searchElement, fromIndex, this, length);
    747 }
    748 %FunctionSetLength(TypedArrayIncludes, 1);
    749 
    750 
    751 // ES6 draft 08-24-14, section 22.2.2.2
    752 function TypedArrayOf() {
    753   var length = %_ArgumentsLength();
    754   var array = TypedArrayCreate(this, length);
    755   for (var i = 0; i < length; i++) {
    756     array[i] = %_Arguments(i);
    757   }
    758   return array;
    759 }
    760 
    761 
    762 function TypedArrayFrom(source, mapfn, thisArg) {
    763   // TODO(littledan): Investigate if there is a receiver which could be
    764   // faster to accumulate on than Array, e.g., a TypedVector.
    765   // TODO(littledan): Rewrite this code to ensure that things happen
    766   // in the right order, e.g., the constructor needs to be called before
    767   // the mapping function on array-likes.
    768   var array = %_Call(ArrayFrom, GlobalArray, source, mapfn, thisArg);
    769   return TypedArrayCreate(this, array);
    770 }
    771 %FunctionSetLength(TypedArrayFrom, 1);
    772 
    773 function TypedArray() {
    774   if (IS_UNDEFINED(new.target)) {
    775     throw MakeTypeError(kConstructorNonCallable, "TypedArray");
    776   }
    777   if (new.target === TypedArray) {
    778     throw MakeTypeError(kConstructAbstractClass, "TypedArray");
    779   }
    780 }
    781 
    782 // -------------------------------------------------------------------
    783 
    784 %FunctionSetPrototype(TypedArray, new GlobalObject());
    785 %AddNamedProperty(TypedArray.prototype,
    786                   "constructor", TypedArray, DONT_ENUM);
    787 utils.InstallFunctions(TypedArray, DONT_ENUM | DONT_DELETE | READ_ONLY, [
    788   "from", TypedArrayFrom,
    789   "of", TypedArrayOf
    790 ]);
    791 utils.InstallGetter(TypedArray.prototype, "buffer", TypedArrayGetBuffer);
    792 utils.InstallGetter(TypedArray.prototype, "byteOffset", TypedArrayGetByteOffset,
    793                     DONT_ENUM | DONT_DELETE);
    794 utils.InstallGetter(TypedArray.prototype, "byteLength",
    795                     TypedArrayGetByteLength, DONT_ENUM | DONT_DELETE);
    796 utils.InstallGetter(TypedArray.prototype, "length", TypedArrayGetLength,
    797                     DONT_ENUM | DONT_DELETE);
    798 utils.InstallGetter(TypedArray.prototype, toStringTagSymbol,
    799                     TypedArrayGetToStringTag);
    800 utils.InstallFunctions(TypedArray.prototype, DONT_ENUM, [
    801   "subarray", TypedArraySubArray,
    802   "set", TypedArraySet,
    803   "copyWithin", TypedArrayCopyWithin,
    804   "every", TypedArrayEvery,
    805   "fill", TypedArrayFill,
    806   "filter", TypedArrayFilter,
    807   "find", TypedArrayFind,
    808   "findIndex", TypedArrayFindIndex,
    809   "includes", TypedArrayIncludes,
    810   "indexOf", TypedArrayIndexOf,
    811   "join", TypedArrayJoin,
    812   "lastIndexOf", TypedArrayLastIndexOf,
    813   "forEach", TypedArrayForEach,
    814   "map", TypedArrayMap,
    815   "reduce", TypedArrayReduce,
    816   "reduceRight", TypedArrayReduceRight,
    817   "reverse", TypedArrayReverse,
    818   "slice", TypedArraySlice,
    819   "some", TypedArraySome,
    820   "sort", TypedArraySort,
    821   "toString", TypedArrayToString,
    822   "toLocaleString", TypedArrayToLocaleString
    823 ]);
    824 
    825 
    826 macro SETUP_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE)
    827   %SetCode(GlobalNAME, NAMEConstructor);
    828   %FunctionSetPrototype(GlobalNAME, new GlobalObject());
    829   %InternalSetPrototype(GlobalNAME, TypedArray);
    830   %InternalSetPrototype(GlobalNAME.prototype, TypedArray.prototype);
    831 
    832   %AddNamedProperty(GlobalNAME, "BYTES_PER_ELEMENT", ELEMENT_SIZE,
    833                     READ_ONLY | DONT_ENUM | DONT_DELETE);
    834 
    835   %AddNamedProperty(GlobalNAME.prototype,
    836                     "constructor", global.NAME, DONT_ENUM);
    837   %AddNamedProperty(GlobalNAME.prototype,
    838                     "BYTES_PER_ELEMENT", ELEMENT_SIZE,
    839                     READ_ONLY | DONT_ENUM | DONT_DELETE);
    840   // TODO(littledan): Remove this performance workaround BUG(chromium:579905)
    841   utils.InstallGetter(GlobalNAME.prototype, "length", NAME_GetLength,
    842                       DONT_ENUM | DONT_DELETE);
    843 endmacro
    844 
    845 TYPED_ARRAYS(SETUP_TYPED_ARRAY)
    846 
    847 // --------------------------- DataView -----------------------------
    848 
    849 function DataViewConstructor(buffer, byteOffset, byteLength) { // length = 3
    850   if (IS_UNDEFINED(new.target)) {
    851     throw MakeTypeError(kConstructorNotFunction, "DataView");
    852   }
    853 
    854   // TODO(binji): support SharedArrayBuffers?
    855   if (!IS_ARRAYBUFFER(buffer)) throw MakeTypeError(kDataViewNotArrayBuffer);
    856   if (!IS_UNDEFINED(byteOffset)) {
    857     byteOffset = ToPositiveInteger(byteOffset, kInvalidDataViewOffset);
    858   }
    859   if (!IS_UNDEFINED(byteLength)) {
    860     byteLength = TO_INTEGER(byteLength);
    861   }
    862 
    863   var bufferByteLength = %_ArrayBufferGetByteLength(buffer);
    864 
    865   var offset = IS_UNDEFINED(byteOffset) ?  0 : byteOffset;
    866   if (offset > bufferByteLength) throw MakeRangeError(kInvalidDataViewOffset);
    867 
    868   var length = IS_UNDEFINED(byteLength)
    869       ? bufferByteLength - offset
    870       : byteLength;
    871   if (length < 0 || offset + length > bufferByteLength) {
    872     throw new MakeRangeError(kInvalidDataViewLength);
    873   }
    874   var result = %NewObject(GlobalDataView, new.target);
    875   %_DataViewInitialize(result, buffer, offset, length);
    876   return result;
    877 }
    878 
    879 function DataViewGetBufferJS() {
    880   if (!IS_DATAVIEW(this)) {
    881     throw MakeTypeError(kIncompatibleMethodReceiver, 'DataView.buffer', this);
    882   }
    883   return %DataViewGetBuffer(this);
    884 }
    885 
    886 function DataViewGetByteOffset() {
    887   if (!IS_DATAVIEW(this)) {
    888     throw MakeTypeError(kIncompatibleMethodReceiver,
    889                         'DataView.byteOffset', this);
    890   }
    891   return %_ArrayBufferViewGetByteOffset(this);
    892 }
    893 
    894 function DataViewGetByteLength() {
    895   if (!IS_DATAVIEW(this)) {
    896     throw MakeTypeError(kIncompatibleMethodReceiver,
    897                         'DataView.byteLength', this);
    898   }
    899   return %_ArrayBufferViewGetByteLength(this);
    900 }
    901 
    902 macro DATA_VIEW_TYPES(FUNCTION)
    903   FUNCTION(Int8)
    904   FUNCTION(Uint8)
    905   FUNCTION(Int16)
    906   FUNCTION(Uint16)
    907   FUNCTION(Int32)
    908   FUNCTION(Uint32)
    909   FUNCTION(Float32)
    910   FUNCTION(Float64)
    911 endmacro
    912 
    913 
    914 macro DATA_VIEW_GETTER_SETTER(TYPENAME)
    915 function DataViewGetTYPENAMEJS(offset, little_endian) {
    916   if (!IS_DATAVIEW(this)) {
    917     throw MakeTypeError(kIncompatibleMethodReceiver,
    918                         'DataView.getTYPENAME', this);
    919   }
    920   if (%_ArgumentsLength() < 1) throw MakeTypeError(kInvalidArgument);
    921   offset = ToPositiveInteger(offset, kInvalidDataViewAccessorOffset);
    922   return %DataViewGetTYPENAME(this, offset, !!little_endian);
    923 }
    924 
    925 function DataViewSetTYPENAMEJS(offset, value, little_endian) {
    926   if (!IS_DATAVIEW(this)) {
    927     throw MakeTypeError(kIncompatibleMethodReceiver,
    928                         'DataView.setTYPENAME', this);
    929   }
    930   if (%_ArgumentsLength() < 2) throw MakeTypeError(kInvalidArgument);
    931   offset = ToPositiveInteger(offset, kInvalidDataViewAccessorOffset);
    932   %DataViewSetTYPENAME(this, offset, TO_NUMBER(value), !!little_endian);
    933 }
    934 endmacro
    935 
    936 DATA_VIEW_TYPES(DATA_VIEW_GETTER_SETTER)
    937 
    938 // Setup the DataView constructor.
    939 %SetCode(GlobalDataView, DataViewConstructor);
    940 %FunctionSetPrototype(GlobalDataView, new GlobalObject);
    941 
    942 // Set up constructor property on the DataView prototype.
    943 %AddNamedProperty(GlobalDataView.prototype, "constructor", GlobalDataView,
    944                   DONT_ENUM);
    945 %AddNamedProperty(GlobalDataView.prototype, toStringTagSymbol, "DataView",
    946                   READ_ONLY|DONT_ENUM);
    947 
    948 utils.InstallGetter(GlobalDataView.prototype, "buffer", DataViewGetBufferJS);
    949 utils.InstallGetter(GlobalDataView.prototype, "byteOffset",
    950                     DataViewGetByteOffset);
    951 utils.InstallGetter(GlobalDataView.prototype, "byteLength",
    952                     DataViewGetByteLength);
    953 
    954 utils.InstallFunctions(GlobalDataView.prototype, DONT_ENUM, [
    955   "getInt8", DataViewGetInt8JS,
    956   "setInt8", DataViewSetInt8JS,
    957 
    958   "getUint8", DataViewGetUint8JS,
    959   "setUint8", DataViewSetUint8JS,
    960 
    961   "getInt16", DataViewGetInt16JS,
    962   "setInt16", DataViewSetInt16JS,
    963 
    964   "getUint16", DataViewGetUint16JS,
    965   "setUint16", DataViewSetUint16JS,
    966 
    967   "getInt32", DataViewGetInt32JS,
    968   "setInt32", DataViewSetInt32JS,
    969 
    970   "getUint32", DataViewGetUint32JS,
    971   "setUint32", DataViewSetUint32JS,
    972 
    973   "getFloat32", DataViewGetFloat32JS,
    974   "setFloat32", DataViewSetFloat32JS,
    975 
    976   "getFloat64", DataViewGetFloat64JS,
    977   "setFloat64", DataViewSetFloat64JS
    978 ]);
    979 
    980 })
    981