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 422 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 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
585 case EXTERNAL_FLOAT32_ELEMENTS: { | 598 case EXTERNAL_FLOAT32_ELEMENTS: { |
586 IterateExternalArrayElements<ExternalFloat32Array, float>( | 599 IterateExternalArrayElements<ExternalFloat32Array, float>( |
587 isolate, receiver, false, false, visitor); | 600 isolate, receiver, false, false, visitor); |
588 break; | 601 break; |
589 } | 602 } |
590 case EXTERNAL_FLOAT64_ELEMENTS: { | 603 case EXTERNAL_FLOAT64_ELEMENTS: { |
591 IterateExternalArrayElements<ExternalFloat64Array, double>( | 604 IterateExternalArrayElements<ExternalFloat64Array, double>( |
592 isolate, receiver, false, false, visitor); | 605 isolate, receiver, false, false, visitor); |
593 break; | 606 break; |
594 } | 607 } |
608 case SLOPPY_ARGUMENTS_ELEMENTS: { | |
609 ElementsAccessor* accessor = receiver->GetElementsAccessor(); | |
610 for (uint32_t index = 0; index < length; index++) { | |
611 HandleScope loop_scope(isolate); | |
612 Handle<Object> element; | |
613 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
614 isolate, element, accessor->Get(receiver, receiver, index), false); | |
615 if (!element->IsTheHole()) { | |
Dmitry Lomov (no reviews)
2014/12/11 14:01:50
Use accessor->HasElement(receiver, receiver, index
| |
616 visitor->visit(index, element); | |
617 } | |
618 } | |
619 break; | |
620 } | |
595 default: | 621 default: |
596 UNREACHABLE(); | 622 UNREACHABLE(); |
597 break; | 623 break; |
598 } | 624 } |
599 visitor->increase_index_offset(length); | 625 visitor->increase_index_offset(length); |
600 return true; | 626 return true; |
601 } | 627 } |
602 | 628 |
603 | 629 |
630 static bool IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { | |
631 HandleScope handle_scope(isolate); | |
632 if (!obj->IsSpecObject()) return false; | |
633 if (obj->IsJSArray()) return true; | |
634 if (FLAG_harmony_arrays) { | |
635 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); | |
636 Handle<Object> value; | |
637 MaybeHandle<Object> maybeValue = | |
638 i::Runtime::GetObjectProperty(isolate, obj, key); | |
639 if (maybeValue.ToHandle(&value)) { | |
640 return value->BooleanValue(); | |
641 } | |
642 } | |
643 return false; | |
644 } | |
645 | |
646 | |
604 /** | 647 /** |
605 * Array::concat implementation. | 648 * Array::concat implementation. |
606 * See ECMAScript 262, 15.4.4.4. | 649 * See ECMAScript 262, 15.4.4.4. |
607 * TODO(581): Fix non-compliance for very large concatenations and update to | 650 * TODO(581): Fix non-compliance for very large concatenations and update to |
608 * following the ECMAScript 5 specification. | 651 * following the ECMAScript 5 specification. |
609 */ | 652 */ |
610 RUNTIME_FUNCTION(Runtime_ArrayConcat) { | 653 RUNTIME_FUNCTION(Runtime_ArrayConcat) { |
611 HandleScope handle_scope(isolate); | 654 HandleScope handle_scope(isolate); |
612 DCHECK(args.length() == 1); | 655 DCHECK(args.length() == 1); |
613 | 656 |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
764 uint32_t at_least_space_for = | 807 uint32_t at_least_space_for = |
765 estimate_nof_elements + (estimate_nof_elements >> 2); | 808 estimate_nof_elements + (estimate_nof_elements >> 2); |
766 storage = Handle<FixedArray>::cast( | 809 storage = Handle<FixedArray>::cast( |
767 SeededNumberDictionary::New(isolate, at_least_space_for)); | 810 SeededNumberDictionary::New(isolate, at_least_space_for)); |
768 } | 811 } |
769 | 812 |
770 ArrayConcatVisitor visitor(isolate, storage, fast_case); | 813 ArrayConcatVisitor visitor(isolate, storage, fast_case); |
771 | 814 |
772 for (int i = 0; i < argument_count; i++) { | 815 for (int i = 0; i < argument_count; i++) { |
773 Handle<Object> obj(elements->get(i), isolate); | 816 Handle<Object> obj(elements->get(i), isolate); |
774 if (obj->IsJSArray()) { | 817 bool spreadable = IsConcatSpreadable(isolate, obj); |
775 Handle<JSArray> array = Handle<JSArray>::cast(obj); | 818 if (isolate->has_pending_exception()) return isolate->heap()->exception(); |
776 if (!IterateElements(isolate, array, &visitor)) { | 819 if (spreadable) { |
820 Handle<JSObject> object = Handle<JSObject>::cast(obj); | |
821 if (!IterateElements(isolate, object, &visitor)) { | |
777 return isolate->heap()->exception(); | 822 return isolate->heap()->exception(); |
778 } | 823 } |
779 } else { | 824 } else { |
780 visitor.visit(0, obj); | 825 visitor.visit(0, obj); |
781 visitor.increase_index_offset(1); | 826 visitor.increase_index_offset(1); |
782 } | 827 } |
783 } | 828 } |
784 | 829 |
785 if (visitor.exceeds_array_limit()) { | 830 if (visitor.exceeds_array_limit()) { |
786 THROW_NEW_ERROR_RETURN_FAILURE( | 831 THROW_NEW_ERROR_RETURN_FAILURE( |
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1187 } | 1232 } |
1188 | 1233 |
1189 | 1234 |
1190 RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) { | 1235 RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) { |
1191 SealHandleScope shs(isolate); | 1236 SealHandleScope shs(isolate); |
1192 DCHECK(args.length() == 2); | 1237 DCHECK(args.length() == 2); |
1193 return isolate->heap()->undefined_value(); | 1238 return isolate->heap()->undefined_value(); |
1194 } | 1239 } |
1195 } | 1240 } |
1196 } // namespace v8::internal | 1241 } // namespace v8::internal |
OLD | NEW |