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