• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
15var ArrayToString = utils.ImportNow("ArrayToString");
16var ArrayValues;
17var GetIterator;
18var GetMethod;
19var GlobalArray = global.Array;
20var GlobalArrayBuffer = global.ArrayBuffer;
21var GlobalArrayBufferPrototype = GlobalArrayBuffer.prototype;
22var GlobalObject = global.Object;
23var InnerArrayEvery;
24var InnerArrayFill;
25var InnerArrayFilter;
26var InnerArrayFind;
27var InnerArrayFindIndex;
28var InnerArrayForEach;
29var InnerArrayJoin;
30var InnerArrayReduce;
31var InnerArrayReduceRight;
32var InnerArraySome;
33var InnerArraySort;
34var InnerArrayToLocaleString;
35var InternalArray = utils.InternalArray;
36var MaxSimple;
37var MinSimple;
38var PackedArrayReverse;
39var SpeciesConstructor;
40var ToPositiveInteger;
41var ToIndex;
42var iteratorSymbol = utils.ImportNow("iterator_symbol");
43var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
44
45macro TYPED_ARRAYS(FUNCTION)
46// arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
47FUNCTION(1, Uint8Array, 1)
48FUNCTION(2, Int8Array, 1)
49FUNCTION(3, Uint16Array, 2)
50FUNCTION(4, Int16Array, 2)
51FUNCTION(5, Uint32Array, 4)
52FUNCTION(6, Int32Array, 4)
53FUNCTION(7, Float32Array, 4)
54FUNCTION(8, Float64Array, 8)
55FUNCTION(9, Uint8ClampedArray, 1)
56endmacro
57
58macro DECLARE_GLOBALS(INDEX, NAME, SIZE)
59var GlobalNAME = global.NAME;
60endmacro
61
62TYPED_ARRAYS(DECLARE_GLOBALS)
63
64var GlobalTypedArray = %object_get_prototype_of(GlobalUint8Array);
65
66utils.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
92function TypedArrayDefaultConstructor(typedArray) {
93  switch (%_ClassOf(typedArray)) {
94macro TYPED_ARRAY_CONSTRUCTOR_CASE(ARRAY_ID, NAME, ELEMENT_SIZE)
95    case "NAME":
96      return GlobalNAME;
97endmacro
98TYPED_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
106function 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
122function 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
129macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
130function 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
175function 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
192function 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
215function 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 )
236function 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
251function 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
272function 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}
306endmacro
307
308TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTOR)
309
310function TypedArraySubArray(begin, end) {
311  switch (%_ClassOf(this)) {
312macro TYPED_ARRAY_SUBARRAY_CASE(ARRAY_ID, NAME, ELEMENT_SIZE)
313    case "NAME":
314      return %_Call(NAMESubArray, this, begin, end);
315endmacro
316TYPED_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
325function 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
338function 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
390function 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
430function 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
439function 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
450function 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
461function 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
472function 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
490function 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
501function 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
512function 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
521function 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
535function 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
569function 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
609function 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
625function 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
636function 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
646function 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
656function 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
667function 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
677function 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
721function 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
754function 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 )
765function 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 ] ] )
785function 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.
812function TypedArrayConstructor() {
813  throw %make_type_error(kConstructAbstractClass, "TypedArray");
814}
815
816// -------------------------------------------------------------------
817
818%SetCode(GlobalTypedArray, TypedArrayConstructor);
819utils.InstallFunctions(GlobalTypedArray, DONT_ENUM, [
820  "from", TypedArrayFrom,
821  "of", TypedArrayOf
822]);
823utils.InstallGetter(GlobalTypedArray.prototype, toStringTagSymbol,
824                    TypedArrayGetToStringTag);
825utils.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
852macro 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);
866endmacro
867
868TYPED_ARRAYS(SETUP_TYPED_ARRAY)
869
870})
871