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