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