OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/builtins.h" | 5 #include "src/builtins.h" |
6 | 6 |
7 #include "src/api.h" | 7 #include "src/api.h" |
8 #include "src/api-natives.h" | 8 #include "src/api-natives.h" |
9 #include "src/arguments.h" | 9 #include "src/arguments.h" |
10 #include "src/base/once.h" | 10 #include "src/base/once.h" |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 called_function(); | 83 called_function(); |
84 } | 84 } |
85 #endif | 85 #endif |
86 | 86 |
87 | 87 |
88 #define DEF_ARG_TYPE(name, spec) \ | 88 #define DEF_ARG_TYPE(name, spec) \ |
89 typedef BuiltinArguments<spec> name##ArgumentsType; | 89 typedef BuiltinArguments<spec> name##ArgumentsType; |
90 BUILTIN_LIST_C(DEF_ARG_TYPE) | 90 BUILTIN_LIST_C(DEF_ARG_TYPE) |
91 #undef DEF_ARG_TYPE | 91 #undef DEF_ARG_TYPE |
92 | 92 |
93 } // namespace | |
94 | 93 |
95 // ---------------------------------------------------------------------------- | 94 // ---------------------------------------------------------------------------- |
96 // Support macro for defining builtins in C++. | 95 // Support macro for defining builtins in C++. |
97 // ---------------------------------------------------------------------------- | 96 // ---------------------------------------------------------------------------- |
98 // | 97 // |
99 // A builtin function is defined by writing: | 98 // A builtin function is defined by writing: |
100 // | 99 // |
101 // BUILTIN(name) { | 100 // BUILTIN(name) { |
102 // ... | 101 // ... |
103 // } | 102 // } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset); | 157 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset); |
159 bool result = (marker == kConstructMarker); | 158 bool result = (marker == kConstructMarker); |
160 DCHECK_EQ(result, reference_result); | 159 DCHECK_EQ(result, reference_result); |
161 return result; | 160 return result; |
162 } | 161 } |
163 #endif | 162 #endif |
164 | 163 |
165 | 164 |
166 // ---------------------------------------------------------------------------- | 165 // ---------------------------------------------------------------------------- |
167 | 166 |
168 BUILTIN(Illegal) { | 167 |
169 UNREACHABLE(); | 168 bool ClampedToInteger(Object* object, int* out) { |
170 return isolate->heap()->undefined_value(); // Make compiler happy. | 169 // This is an extended version of ECMA-262 7.1.11 handling signed values |
| 170 // Try to convert object to a number and clamp values to [kMinInt, kMaxInt] |
| 171 if (object->IsSmi()) { |
| 172 *out = Smi::cast(object)->value(); |
| 173 return true; |
| 174 } else if (object->IsHeapNumber()) { |
| 175 *out = FastD2IChecked(HeapNumber::cast(object)->value()); |
| 176 return true; |
| 177 } else if (object->IsUndefined()) { |
| 178 *out = 0; |
| 179 return true; |
| 180 } else if (object->IsBoolean()) { |
| 181 *out = object->IsTrue(); |
| 182 return true; |
| 183 } |
| 184 return false; |
171 } | 185 } |
172 | 186 |
173 | 187 |
174 BUILTIN(EmptyFunction) { | |
175 return isolate->heap()->undefined_value(); | |
176 } | |
177 | |
178 | |
179 static void MoveDoubleElements(FixedDoubleArray* dst, int dst_index, | 188 static void MoveDoubleElements(FixedDoubleArray* dst, int dst_index, |
180 FixedDoubleArray* src, int src_index, int len) { | 189 FixedDoubleArray* src, int src_index, int len) { |
181 if (len == 0) return; | 190 if (len == 0) return; |
182 MemMove(dst->data_start() + dst_index, src->data_start() + src_index, | 191 MemMove(dst->data_start() + dst_index, src->data_start() + src_index, |
183 len * kDoubleSize); | 192 len * kDoubleSize); |
184 } | 193 } |
185 | 194 |
186 | 195 |
187 static bool ArrayPrototypeHasNoElements(PrototypeIterator* iter) { | 196 static bool ArrayPrototypeHasNoElements(PrototypeIterator* iter) { |
188 DisallowHeapAllocation no_gc; | 197 DisallowHeapAllocation no_gc; |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 isolate, result, | 306 isolate, result, |
298 Execution::Call(isolate, | 307 Execution::Call(isolate, |
299 function, | 308 function, |
300 args.receiver(), | 309 args.receiver(), |
301 argc, | 310 argc, |
302 argv.start())); | 311 argv.start())); |
303 return *result; | 312 return *result; |
304 } | 313 } |
305 | 314 |
306 | 315 |
| 316 } // namespace |
| 317 |
| 318 |
| 319 BUILTIN(Illegal) { |
| 320 UNREACHABLE(); |
| 321 return isolate->heap()->undefined_value(); // Make compiler happy. |
| 322 } |
| 323 |
| 324 |
| 325 BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); } |
| 326 |
| 327 |
307 BUILTIN(ArrayPush) { | 328 BUILTIN(ArrayPush) { |
308 HandleScope scope(isolate); | 329 HandleScope scope(isolate); |
309 Handle<Object> receiver = args.receiver(); | 330 Handle<Object> receiver = args.receiver(); |
310 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 331 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
311 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); | 332 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); |
312 Handle<FixedArrayBase> elms_obj; | 333 Handle<FixedArrayBase> elms_obj; |
313 if (!maybe_elms_obj.ToHandle(&elms_obj)) { | 334 if (!maybe_elms_obj.ToHandle(&elms_obj)) { |
314 return CallJsIntrinsic(isolate, isolate->array_push(), args); | 335 return CallJsIntrinsic(isolate, isolate->array_push(), args); |
315 } | 336 } |
316 // Fast Elements Path | 337 // Fast Elements Path |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
607 | 628 |
608 ElementsAccessor* accessor = object->GetElementsAccessor(); | 629 ElementsAccessor* accessor = object->GetElementsAccessor(); |
609 accessor->CopyElements( | 630 accessor->CopyElements( |
610 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len); | 631 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len); |
611 return *result_array; | 632 return *result_array; |
612 } | 633 } |
613 | 634 |
614 | 635 |
615 BUILTIN(ArraySplice) { | 636 BUILTIN(ArraySplice) { |
616 HandleScope scope(isolate); | 637 HandleScope scope(isolate); |
617 Heap* heap = isolate->heap(); | |
618 Handle<Object> receiver = args.receiver(); | 638 Handle<Object> receiver = args.receiver(); |
619 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 639 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
620 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); | 640 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); |
621 Handle<FixedArrayBase> elms_obj; | 641 Handle<FixedArrayBase> elms_obj; |
622 if (!maybe_elms_obj.ToHandle(&elms_obj)) { | 642 if (!maybe_elms_obj.ToHandle(&elms_obj)) { |
623 return CallJsIntrinsic(isolate, isolate->array_splice(), args); | 643 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
624 } | 644 } |
625 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 645 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
626 DCHECK(!array->map()->is_observed()); | 646 DCHECK(!array->map()->is_observed()); |
627 | 647 |
628 int len = Smi::cast(array->length())->value(); | 648 int argument_count = args.length() - 1; |
629 | |
630 int n_arguments = args.length() - 1; | |
631 | |
632 int relative_start = 0; | 649 int relative_start = 0; |
633 if (n_arguments > 0) { | 650 if (argument_count > 0) { |
634 DisallowHeapAllocation no_gc; | 651 DisallowHeapAllocation no_gc; |
635 Object* arg1 = args[1]; | 652 if (!ClampedToInteger(args[1], &relative_start)) { |
636 if (arg1->IsSmi()) { | |
637 relative_start = Smi::cast(arg1)->value(); | |
638 } else if (arg1->IsHeapNumber()) { | |
639 double start = HeapNumber::cast(arg1)->value(); | |
640 if (start < kMinInt || start > kMaxInt) { | |
641 AllowHeapAllocation allow_allocation; | |
642 return CallJsIntrinsic(isolate, isolate->array_splice(), args); | |
643 } | |
644 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); | |
645 } else if (!arg1->IsUndefined()) { | |
646 AllowHeapAllocation allow_allocation; | 653 AllowHeapAllocation allow_allocation; |
647 return CallJsIntrinsic(isolate, isolate->array_splice(), args); | 654 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
648 } | 655 } |
649 } | 656 } |
| 657 int len = Smi::cast(array->length())->value(); |
| 658 // clip relative start to [0, len] |
650 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) | 659 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) |
651 : Min(relative_start, len); | 660 : Min(relative_start, len); |
652 | 661 |
653 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is | |
654 // given as a request to delete all the elements from the start. | |
655 // And it differs from the case of undefined delete count. | |
656 // This does not follow ECMA-262, but we do the same for | |
657 // compatibility. | |
658 int actual_delete_count; | 662 int actual_delete_count; |
659 if (n_arguments == 1) { | 663 if (argument_count == 1) { |
| 664 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is |
| 665 // given as a request to delete all the elements from the start. |
| 666 // And it differs from the case of undefined delete count. |
| 667 // This does not follow ECMA-262, but we do the same for compatibility. |
660 DCHECK(len - actual_start >= 0); | 668 DCHECK(len - actual_start >= 0); |
661 actual_delete_count = len - actual_start; | 669 actual_delete_count = len - actual_start; |
662 } else { | 670 } else { |
663 int value = 0; // ToInteger(undefined) == 0 | 671 int delete_count = 0; |
664 if (n_arguments > 1) { | 672 DisallowHeapAllocation no_gc; |
665 DisallowHeapAllocation no_gc; | 673 if (argument_count > 1) { |
666 Object* arg2 = args[2]; | 674 if (!ClampedToInteger(args[2], &delete_count)) { |
667 if (arg2->IsSmi()) { | |
668 value = Smi::cast(arg2)->value(); | |
669 } else { | |
670 AllowHeapAllocation allow_allocation; | 675 AllowHeapAllocation allow_allocation; |
671 return CallJsIntrinsic(isolate, isolate->array_splice(), args); | 676 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
672 } | 677 } |
673 } | 678 } |
674 actual_delete_count = Min(Max(value, 0), len - actual_start); | 679 actual_delete_count = Min(Max(delete_count, 0), len - actual_start); |
675 } | 680 } |
676 | 681 |
677 ElementsKind elements_kind = array->GetElementsKind(); | 682 int add_count = (argument_count > 1) ? (argument_count - 2) : 0; |
678 | 683 int new_length = len - actual_delete_count + add_count; |
679 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; | |
680 int new_length = len - actual_delete_count + item_count; | |
681 | |
682 // For double mode we do not support changing the length. | |
683 if (new_length > len && IsFastDoubleElementsKind(elements_kind)) { | |
684 return CallJsIntrinsic(isolate, isolate->array_splice(), args); | |
685 } | |
686 | 684 |
687 if (new_length != len && JSArray::HasReadOnlyLength(array)) { | 685 if (new_length != len && JSArray::HasReadOnlyLength(array)) { |
688 AllowHeapAllocation allow_allocation; | 686 AllowHeapAllocation allow_allocation; |
689 return CallJsIntrinsic(isolate, isolate->array_splice(), args); | 687 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
690 } | 688 } |
691 | 689 ElementsAccessor* accessor = array->GetElementsAccessor(); |
692 if (new_length == 0) { | 690 Handle<JSArray> result = accessor->Splice( |
693 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements( | 691 array, elms_obj, actual_start, actual_delete_count, args, add_count); |
694 elms_obj, elements_kind, actual_delete_count); | 692 return *result; |
695 array->set_elements(heap->empty_fixed_array()); | |
696 array->set_length(Smi::FromInt(0)); | |
697 return *result; | |
698 } | |
699 | |
700 Handle<JSArray> result_array = | |
701 isolate->factory()->NewJSArray(elements_kind, | |
702 actual_delete_count, | |
703 actual_delete_count); | |
704 | |
705 if (actual_delete_count > 0) { | |
706 DisallowHeapAllocation no_gc; | |
707 ElementsAccessor* accessor = array->GetElementsAccessor(); | |
708 accessor->CopyElements( | |
709 elms_obj, actual_start, elements_kind, | |
710 handle(result_array->elements(), isolate), 0, actual_delete_count); | |
711 } | |
712 | |
713 bool elms_changed = false; | |
714 if (item_count < actual_delete_count) { | |
715 // Shrink the array. | |
716 const bool trim_array = !heap->lo_space()->Contains(*elms_obj) && | |
717 ((actual_start + item_count) < | |
718 (len - actual_delete_count - actual_start)); | |
719 if (trim_array) { | |
720 const int delta = actual_delete_count - item_count; | |
721 | |
722 if (elms_obj->IsFixedDoubleArray()) { | |
723 Handle<FixedDoubleArray> elms = | |
724 Handle<FixedDoubleArray>::cast(elms_obj); | |
725 MoveDoubleElements(*elms, delta, *elms, 0, actual_start); | |
726 } else { | |
727 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); | |
728 DisallowHeapAllocation no_gc; | |
729 heap->MoveElements(*elms, delta, 0, actual_start); | |
730 } | |
731 | |
732 if (heap->CanMoveObjectStart(*elms_obj)) { | |
733 // On the fast path we move the start of the object in memory. | |
734 elms_obj = handle(heap->LeftTrimFixedArray(*elms_obj, delta)); | |
735 } else { | |
736 // This is the slow path. We are going to move the elements to the left | |
737 // by copying them. For trimmed values we store the hole. | |
738 if (elms_obj->IsFixedDoubleArray()) { | |
739 Handle<FixedDoubleArray> elms = | |
740 Handle<FixedDoubleArray>::cast(elms_obj); | |
741 MoveDoubleElements(*elms, 0, *elms, delta, len - delta); | |
742 elms->FillWithHoles(len - delta, len); | |
743 } else { | |
744 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); | |
745 DisallowHeapAllocation no_gc; | |
746 heap->MoveElements(*elms, 0, delta, len - delta); | |
747 elms->FillWithHoles(len - delta, len); | |
748 } | |
749 } | |
750 elms_changed = true; | |
751 } else { | |
752 if (elms_obj->IsFixedDoubleArray()) { | |
753 Handle<FixedDoubleArray> elms = | |
754 Handle<FixedDoubleArray>::cast(elms_obj); | |
755 MoveDoubleElements(*elms, actual_start + item_count, | |
756 *elms, actual_start + actual_delete_count, | |
757 (len - actual_delete_count - actual_start)); | |
758 elms->FillWithHoles(new_length, len); | |
759 } else { | |
760 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); | |
761 DisallowHeapAllocation no_gc; | |
762 heap->MoveElements(*elms, actual_start + item_count, | |
763 actual_start + actual_delete_count, | |
764 (len - actual_delete_count - actual_start)); | |
765 elms->FillWithHoles(new_length, len); | |
766 } | |
767 } | |
768 } else if (item_count > actual_delete_count) { | |
769 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); | |
770 // Currently fixed arrays cannot grow too big, so | |
771 // we should never hit this case. | |
772 DCHECK((item_count - actual_delete_count) <= (Smi::kMaxValue - len)); | |
773 | |
774 // Check if array need to grow. | |
775 if (new_length > elms->length()) { | |
776 // New backing storage is needed. | |
777 int capacity = new_length + (new_length >> 1) + 16; | |
778 Handle<FixedArray> new_elms = | |
779 isolate->factory()->NewUninitializedFixedArray(capacity); | |
780 | |
781 DisallowHeapAllocation no_gc; | |
782 | |
783 ElementsKind kind = array->GetElementsKind(); | |
784 ElementsAccessor* accessor = array->GetElementsAccessor(); | |
785 if (actual_start > 0) { | |
786 // Copy the part before actual_start as is. | |
787 accessor->CopyElements( | |
788 elms, 0, kind, new_elms, 0, actual_start); | |
789 } | |
790 accessor->CopyElements( | |
791 elms, actual_start + actual_delete_count, kind, | |
792 new_elms, actual_start + item_count, | |
793 ElementsAccessor::kCopyToEndAndInitializeToHole); | |
794 | |
795 elms_obj = new_elms; | |
796 elms_changed = true; | |
797 } else { | |
798 DisallowHeapAllocation no_gc; | |
799 heap->MoveElements(*elms, actual_start + item_count, | |
800 actual_start + actual_delete_count, | |
801 (len - actual_delete_count - actual_start)); | |
802 } | |
803 } | |
804 | |
805 if (IsFastDoubleElementsKind(elements_kind)) { | |
806 Handle<FixedDoubleArray> elms = Handle<FixedDoubleArray>::cast(elms_obj); | |
807 for (int k = actual_start; k < actual_start + item_count; k++) { | |
808 Object* arg = args[3 + k - actual_start]; | |
809 if (arg->IsSmi()) { | |
810 elms->set(k, Smi::cast(arg)->value()); | |
811 } else { | |
812 elms->set(k, HeapNumber::cast(arg)->value()); | |
813 } | |
814 } | |
815 } else { | |
816 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); | |
817 DisallowHeapAllocation no_gc; | |
818 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); | |
819 for (int k = actual_start; k < actual_start + item_count; k++) { | |
820 elms->set(k, args[3 + k - actual_start], mode); | |
821 } | |
822 } | |
823 | |
824 if (elms_changed) { | |
825 array->set_elements(*elms_obj); | |
826 } | |
827 // Set the length. | |
828 array->set_length(Smi::FromInt(new_length)); | |
829 | |
830 return *result_array; | |
831 } | 693 } |
832 | 694 |
833 | 695 |
834 BUILTIN(ArrayConcat) { | 696 BUILTIN(ArrayConcat) { |
835 HandleScope scope(isolate); | 697 HandleScope scope(isolate); |
836 | 698 |
837 int n_arguments = args.length(); | 699 int n_arguments = args.length(); |
838 int result_len = 0; | 700 int result_len = 0; |
839 ElementsKind elements_kind = GetInitialFastElementsKind(); | 701 ElementsKind elements_kind = GetInitialFastElementsKind(); |
840 bool has_double = false; | 702 bool has_double = false; |
(...skipping 686 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1527 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) | 1389 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) |
1528 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) | 1390 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) |
1529 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 1391 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) |
1530 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 1392 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
1531 #undef DEFINE_BUILTIN_ACCESSOR_C | 1393 #undef DEFINE_BUILTIN_ACCESSOR_C |
1532 #undef DEFINE_BUILTIN_ACCESSOR_A | 1394 #undef DEFINE_BUILTIN_ACCESSOR_A |
1533 | 1395 |
1534 | 1396 |
1535 } // namespace internal | 1397 } // namespace internal |
1536 } // namespace v8 | 1398 } // namespace v8 |
OLD | NEW |