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