OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/arguments.h" | 7 #include "src/arguments.h" |
8 #include "src/runtime/runtime-utils.h" | 8 #include "src/runtime/runtime-utils.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 // External arrays are always dense. | 282 // External arrays are always dense. |
283 return length; | 283 return length; |
284 } | 284 } |
285 // As an estimate, we assume that the prototype doesn't contain any | 285 // As an estimate, we assume that the prototype doesn't contain any |
286 // inherited elements. | 286 // inherited elements. |
287 return element_count; | 287 return element_count; |
288 } | 288 } |
289 | 289 |
290 | 290 |
291 template <class ExternalArrayClass, class ElementType> | 291 template <class ExternalArrayClass, class ElementType> |
292 static void IterateExternalArrayElements(Isolate* isolate, | 292 static void IterateTypedArrayElements(Isolate* isolate, |
293 Handle<JSObject> receiver, | 293 Handle<JSObject> receiver, |
294 bool elements_are_ints, | 294 bool elements_are_ints, |
295 bool elements_are_guaranteed_smis, | 295 bool elements_are_guaranteed_smis, |
296 ArrayConcatVisitor* visitor) { | 296 ArrayConcatVisitor* visitor) { |
297 Handle<ExternalArrayClass> array( | 297 Handle<ExternalArrayClass> array( |
298 ExternalArrayClass::cast(receiver->elements())); | 298 ExternalArrayClass::cast(receiver->elements())); |
299 uint32_t len = static_cast<uint32_t>(array->length()); | 299 uint32_t len = static_cast<uint32_t>(array->length()); |
300 | 300 |
301 DCHECK(visitor != NULL); | 301 DCHECK(visitor != NULL); |
302 if (elements_are_ints) { | 302 if (elements_are_ints) { |
303 if (elements_are_guaranteed_smis) { | 303 if (elements_are_guaranteed_smis) { |
304 for (uint32_t j = 0; j < len; j++) { | 304 for (uint32_t j = 0; j < len; j++) { |
305 HandleScope loop_scope(isolate); | 305 HandleScope loop_scope(isolate); |
306 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))), | 306 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))), |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 // The prototype will usually have no inherited element indices, | 433 // The prototype will usually have no inherited element indices, |
434 // but we have to check. | 434 // but we have to check. |
435 CollectElementIndices( | 435 CollectElementIndices( |
436 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), range, | 436 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), range, |
437 indices); | 437 indices); |
438 } | 438 } |
439 } | 439 } |
440 | 440 |
441 | 441 |
442 /** | 442 /** |
443 * A helper function that visits elements of a JSArray in numerical | 443 * A helper function that visits elements of a JSObject in numerical |
444 * order. | 444 * order. |
445 * | 445 * |
446 * The visitor argument called for each existing element in the array | 446 * The visitor argument called for each existing element in the array |
447 * with the element index and the element's value. | 447 * with the element index and the element's value. |
448 * Afterwards it increments the base-index of the visitor by the array | 448 * Afterwards it increments the base-index of the visitor by the array |
449 * length. | 449 * length. |
450 * Returns false if any access threw an exception, otherwise true. | 450 * Returns false if any access threw an exception, otherwise true. |
451 */ | 451 */ |
452 static bool IterateElements(Isolate* isolate, Handle<JSArray> receiver, | 452 static bool IterateElements(Isolate* isolate, Handle<JSObject> receiver, |
453 ArrayConcatVisitor* visitor) { | 453 ArrayConcatVisitor* visitor) { |
454 uint32_t length = static_cast<uint32_t>(receiver->length()->Number()); | 454 uint32_t length = 0; |
| 455 |
| 456 if (receiver->IsJSArray()) { |
| 457 Handle<JSArray> array(Handle<JSArray>::cast(receiver)); |
| 458 length = static_cast<uint32_t>(array->length()->Number()); |
| 459 } else { |
| 460 Handle<Object> val; |
| 461 Handle<Object> key(isolate->heap()->length_string(), isolate); |
| 462 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, val, |
| 463 Runtime::GetObjectProperty(isolate, receiver, key), false); |
| 464 // TODO(caitp): implement ToLength() abstract operation for C++ |
| 465 val->ToUint32(&length); |
| 466 } |
| 467 |
455 switch (receiver->GetElementsKind()) { | 468 switch (receiver->GetElementsKind()) { |
456 case FAST_SMI_ELEMENTS: | 469 case FAST_SMI_ELEMENTS: |
457 case FAST_ELEMENTS: | 470 case FAST_ELEMENTS: |
458 case FAST_HOLEY_SMI_ELEMENTS: | 471 case FAST_HOLEY_SMI_ELEMENTS: |
459 case FAST_HOLEY_ELEMENTS: { | 472 case FAST_HOLEY_ELEMENTS: { |
460 // Run through the elements FixedArray and use HasElement and GetElement | 473 // Run through the elements FixedArray and use HasElement and GetElement |
461 // to check the prototype for missing elements. | 474 // to check the prototype for missing elements. |
462 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); | 475 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); |
463 int fast_length = static_cast<int>(length); | 476 int fast_length = static_cast<int>(length); |
464 DCHECK(fast_length <= elements->length()); | 477 DCHECK(fast_length <= elements->length()); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
545 } | 558 } |
546 case EXTERNAL_UINT8_CLAMPED_ELEMENTS: { | 559 case EXTERNAL_UINT8_CLAMPED_ELEMENTS: { |
547 Handle<ExternalUint8ClampedArray> pixels( | 560 Handle<ExternalUint8ClampedArray> pixels( |
548 ExternalUint8ClampedArray::cast(receiver->elements())); | 561 ExternalUint8ClampedArray::cast(receiver->elements())); |
549 for (uint32_t j = 0; j < length; j++) { | 562 for (uint32_t j = 0; j < length; j++) { |
550 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate); | 563 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate); |
551 visitor->visit(j, e); | 564 visitor->visit(j, e); |
552 } | 565 } |
553 break; | 566 break; |
554 } | 567 } |
| 568 case UINT8_CLAMPED_ELEMENTS: { |
| 569 Handle<FixedUint8ClampedArray> pixels( |
| 570 FixedUint8ClampedArray::cast(receiver->elements())); |
| 571 for (uint32_t j = 0; j < length; j++) { |
| 572 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate); |
| 573 visitor->visit(j, e); |
| 574 } |
| 575 break; |
| 576 } |
555 case EXTERNAL_INT8_ELEMENTS: { | 577 case EXTERNAL_INT8_ELEMENTS: { |
556 IterateExternalArrayElements<ExternalInt8Array, int8_t>( | 578 IterateTypedArrayElements<ExternalInt8Array, int8_t>( |
557 isolate, receiver, true, true, visitor); | 579 isolate, receiver, true, true, visitor); |
558 break; | 580 break; |
559 } | 581 } |
| 582 case INT8_ELEMENTS: { |
| 583 IterateTypedArrayElements<FixedInt8Array, int8_t>( |
| 584 isolate, receiver, true, true, visitor); |
| 585 break; |
| 586 } |
560 case EXTERNAL_UINT8_ELEMENTS: { | 587 case EXTERNAL_UINT8_ELEMENTS: { |
561 IterateExternalArrayElements<ExternalUint8Array, uint8_t>( | 588 IterateTypedArrayElements<ExternalUint8Array, uint8_t>( |
562 isolate, receiver, true, true, visitor); | 589 isolate, receiver, true, true, visitor); |
563 break; | 590 break; |
564 } | 591 } |
| 592 case UINT8_ELEMENTS: { |
| 593 IterateTypedArrayElements<FixedUint8Array, uint8_t>( |
| 594 isolate, receiver, true, true, visitor); |
| 595 break; |
| 596 } |
565 case EXTERNAL_INT16_ELEMENTS: { | 597 case EXTERNAL_INT16_ELEMENTS: { |
566 IterateExternalArrayElements<ExternalInt16Array, int16_t>( | 598 IterateTypedArrayElements<ExternalInt16Array, int16_t>( |
567 isolate, receiver, true, true, visitor); | 599 isolate, receiver, true, true, visitor); |
568 break; | 600 break; |
569 } | 601 } |
| 602 case INT16_ELEMENTS: { |
| 603 IterateTypedArrayElements<FixedInt16Array, int16_t>( |
| 604 isolate, receiver, true, true, visitor); |
| 605 break; |
| 606 } |
570 case EXTERNAL_UINT16_ELEMENTS: { | 607 case EXTERNAL_UINT16_ELEMENTS: { |
571 IterateExternalArrayElements<ExternalUint16Array, uint16_t>( | 608 IterateTypedArrayElements<ExternalUint16Array, uint16_t>( |
572 isolate, receiver, true, true, visitor); | 609 isolate, receiver, true, true, visitor); |
573 break; | 610 break; |
574 } | 611 } |
| 612 case UINT16_ELEMENTS: { |
| 613 IterateTypedArrayElements<FixedUint16Array, uint16_t>( |
| 614 isolate, receiver, true, true, visitor); |
| 615 break; |
| 616 } |
575 case EXTERNAL_INT32_ELEMENTS: { | 617 case EXTERNAL_INT32_ELEMENTS: { |
576 IterateExternalArrayElements<ExternalInt32Array, int32_t>( | 618 IterateTypedArrayElements<ExternalInt32Array, int32_t>( |
577 isolate, receiver, true, false, visitor); | 619 isolate, receiver, true, false, visitor); |
578 break; | 620 break; |
579 } | 621 } |
| 622 case INT32_ELEMENTS: { |
| 623 IterateTypedArrayElements<FixedInt32Array, int32_t>( |
| 624 isolate, receiver, true, false, visitor); |
| 625 break; |
| 626 } |
580 case EXTERNAL_UINT32_ELEMENTS: { | 627 case EXTERNAL_UINT32_ELEMENTS: { |
581 IterateExternalArrayElements<ExternalUint32Array, uint32_t>( | 628 IterateTypedArrayElements<ExternalUint32Array, uint32_t>( |
582 isolate, receiver, true, false, visitor); | 629 isolate, receiver, true, false, visitor); |
583 break; | 630 break; |
584 } | 631 } |
| 632 case UINT32_ELEMENTS: { |
| 633 IterateTypedArrayElements<FixedUint32Array, uint32_t>( |
| 634 isolate, receiver, true, false, visitor); |
| 635 break; |
| 636 } |
585 case EXTERNAL_FLOAT32_ELEMENTS: { | 637 case EXTERNAL_FLOAT32_ELEMENTS: { |
586 IterateExternalArrayElements<ExternalFloat32Array, float>( | 638 IterateTypedArrayElements<ExternalFloat32Array, float>( |
587 isolate, receiver, false, false, visitor); | 639 isolate, receiver, false, false, visitor); |
588 break; | 640 break; |
589 } | 641 } |
| 642 case FLOAT32_ELEMENTS: { |
| 643 IterateTypedArrayElements<FixedFloat32Array, float>( |
| 644 isolate, receiver, false, false, visitor); |
| 645 break; |
| 646 } |
590 case EXTERNAL_FLOAT64_ELEMENTS: { | 647 case EXTERNAL_FLOAT64_ELEMENTS: { |
591 IterateExternalArrayElements<ExternalFloat64Array, double>( | 648 IterateTypedArrayElements<ExternalFloat64Array, double>( |
592 isolate, receiver, false, false, visitor); | 649 isolate, receiver, false, false, visitor); |
593 break; | 650 break; |
594 } | 651 } |
595 default: | 652 case FLOAT64_ELEMENTS: { |
596 UNREACHABLE(); | 653 IterateTypedArrayElements<FixedFloat64Array, double>( |
| 654 isolate, receiver, false, false, visitor); |
597 break; | 655 break; |
| 656 } |
| 657 case SLOPPY_ARGUMENTS_ELEMENTS: { |
| 658 ElementsAccessor* accessor = receiver->GetElementsAccessor(); |
| 659 for (uint32_t index = 0; index < length; index++) { |
| 660 HandleScope loop_scope(isolate); |
| 661 if (accessor->HasElement(receiver, receiver, index)) { |
| 662 Handle<Object> element; |
| 663 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 664 isolate, element, accessor->Get(receiver, receiver, index), |
| 665 false); |
| 666 visitor->visit(index, element); |
| 667 } |
| 668 } |
| 669 break; |
| 670 } |
598 } | 671 } |
599 visitor->increase_index_offset(length); | 672 visitor->increase_index_offset(length); |
600 return true; | 673 return true; |
601 } | 674 } |
602 | 675 |
603 | 676 |
| 677 static bool IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { |
| 678 HandleScope handle_scope(isolate); |
| 679 if (!obj->IsSpecObject()) return false; |
| 680 if (obj->IsJSArray()) return true; |
| 681 if (FLAG_harmony_arrays) { |
| 682 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); |
| 683 Handle<Object> value; |
| 684 MaybeHandle<Object> maybeValue = |
| 685 i::Runtime::GetObjectProperty(isolate, obj, key); |
| 686 if (maybeValue.ToHandle(&value)) { |
| 687 return value->BooleanValue(); |
| 688 } |
| 689 } |
| 690 return false; |
| 691 } |
| 692 |
| 693 |
604 /** | 694 /** |
605 * Array::concat implementation. | 695 * Array::concat implementation. |
606 * See ECMAScript 262, 15.4.4.4. | 696 * See ECMAScript 262, 15.4.4.4. |
607 * TODO(581): Fix non-compliance for very large concatenations and update to | 697 * TODO(581): Fix non-compliance for very large concatenations and update to |
608 * following the ECMAScript 5 specification. | 698 * following the ECMAScript 5 specification. |
609 */ | 699 */ |
610 RUNTIME_FUNCTION(Runtime_ArrayConcat) { | 700 RUNTIME_FUNCTION(Runtime_ArrayConcat) { |
611 HandleScope handle_scope(isolate); | 701 HandleScope handle_scope(isolate); |
612 DCHECK(args.length() == 1); | 702 DCHECK(args.length() == 1); |
613 | 703 |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
764 uint32_t at_least_space_for = | 854 uint32_t at_least_space_for = |
765 estimate_nof_elements + (estimate_nof_elements >> 2); | 855 estimate_nof_elements + (estimate_nof_elements >> 2); |
766 storage = Handle<FixedArray>::cast( | 856 storage = Handle<FixedArray>::cast( |
767 SeededNumberDictionary::New(isolate, at_least_space_for)); | 857 SeededNumberDictionary::New(isolate, at_least_space_for)); |
768 } | 858 } |
769 | 859 |
770 ArrayConcatVisitor visitor(isolate, storage, fast_case); | 860 ArrayConcatVisitor visitor(isolate, storage, fast_case); |
771 | 861 |
772 for (int i = 0; i < argument_count; i++) { | 862 for (int i = 0; i < argument_count; i++) { |
773 Handle<Object> obj(elements->get(i), isolate); | 863 Handle<Object> obj(elements->get(i), isolate); |
774 if (obj->IsJSArray()) { | 864 bool spreadable = IsConcatSpreadable(isolate, obj); |
775 Handle<JSArray> array = Handle<JSArray>::cast(obj); | 865 if (isolate->has_pending_exception()) return isolate->heap()->exception(); |
776 if (!IterateElements(isolate, array, &visitor)) { | 866 if (spreadable) { |
| 867 Handle<JSObject> object = Handle<JSObject>::cast(obj); |
| 868 if (!IterateElements(isolate, object, &visitor)) { |
777 return isolate->heap()->exception(); | 869 return isolate->heap()->exception(); |
778 } | 870 } |
779 } else { | 871 } else { |
780 visitor.visit(0, obj); | 872 visitor.visit(0, obj); |
781 visitor.increase_index_offset(1); | 873 visitor.increase_index_offset(1); |
782 } | 874 } |
783 } | 875 } |
784 | 876 |
785 if (visitor.exceeds_array_limit()) { | 877 if (visitor.exceeds_array_limit()) { |
786 THROW_NEW_ERROR_RETURN_FAILURE( | 878 THROW_NEW_ERROR_RETURN_FAILURE( |
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1187 } | 1279 } |
1188 | 1280 |
1189 | 1281 |
1190 RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) { | 1282 RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) { |
1191 SealHandleScope shs(isolate); | 1283 SealHandleScope shs(isolate); |
1192 DCHECK(args.length() == 2); | 1284 DCHECK(args.length() == 2); |
1193 return isolate->heap()->undefined_value(); | 1285 return isolate->heap()->undefined_value(); |
1194 } | 1286 } |
1195 } | 1287 } |
1196 } // namespace v8::internal | 1288 } // namespace v8::internal |
OLD | NEW |