Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(278)

Side by Side Diff: src/builtins.cc

Issue 1293683005: Adding ElementsAccessor::Splice (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: simpliftying splice arg copying Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/elements.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 // has been specialized for each architecture so if any one of them 153 // has been specialized for each architecture so if any one of them
155 // changes this code has to be changed as well. 154 // changes this code has to be changed as well.
156 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset; 155 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
157 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT); 156 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
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
163 } // namespace
164 164
165 165
166 // ---------------------------------------------------------------------------- 166 // ----------------------------------------------------------------------------
167 167
168 BUILTIN(Illegal) { 168 BUILTIN(Illegal) {
169 UNREACHABLE(); 169 UNREACHABLE();
170 return isolate->heap()->undefined_value(); // Make compiler happy. 170 return isolate->heap()->undefined_value(); // Make compiler happy.
171 } 171 }
172 172
173 173
174 BUILTIN(EmptyFunction) { 174 BUILTIN(EmptyFunction) {
175 return isolate->heap()->undefined_value(); 175 return isolate->heap()->undefined_value();
176 } 176 }
177 177
178 178
179 namespace {
180
181 bool ClampedToInteger(Object* object, int* out) {
182 // This is an extended version of ECMA-262 9.4, but additionally
183 // clamps values to [kMinInt, kMaxInt]
184 if (object->IsSmi()) {
185 *out = Smi::cast(object)->value();
186 return true;
187 } else if (object->IsHeapNumber()) {
188 *out = FastD2IChecked(HeapNumber::cast(object)->value());
189 return true;
190 } else if (object->IsUndefined()) {
191 *out = 0;
192 return true;
193 } else if (object->IsBoolean()) {
194 *out = (Oddball::cast(object)->kind() == Oddball::kTrue) ? 1 : 0;
195 return true;
196 }
197 return false;
198 }
199
200
179 static void MoveDoubleElements(FixedDoubleArray* dst, int dst_index, 201 static void MoveDoubleElements(FixedDoubleArray* dst, int dst_index,
180 FixedDoubleArray* src, int src_index, int len) { 202 FixedDoubleArray* src, int src_index, int len) {
181 if (len == 0) return; 203 if (len == 0) return;
182 MemMove(dst->data_start() + dst_index, src->data_start() + src_index, 204 MemMove(dst->data_start() + dst_index, src->data_start() + src_index,
183 len * kDoubleSize); 205 len * kDoubleSize);
184 } 206 }
185 207
186 208
187 static bool ArrayPrototypeHasNoElements(PrototypeIterator* iter) { 209 static bool ArrayPrototypeHasNoElements(PrototypeIterator* iter) {
188 DisallowHeapAllocation no_gc; 210 DisallowHeapAllocation no_gc;
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 isolate, result, 319 isolate, result,
298 Execution::Call(isolate, 320 Execution::Call(isolate,
299 function, 321 function,
300 args.receiver(), 322 args.receiver(),
301 argc, 323 argc,
302 argv.start())); 324 argv.start()));
303 return *result; 325 return *result;
304 } 326 }
305 327
306 328
329 } // namespace
330
331
307 BUILTIN(ArrayPush) { 332 BUILTIN(ArrayPush) {
308 HandleScope scope(isolate); 333 HandleScope scope(isolate);
309 Handle<Object> receiver = args.receiver(); 334 Handle<Object> receiver = args.receiver();
310 MaybeHandle<FixedArrayBase> maybe_elms_obj = 335 MaybeHandle<FixedArrayBase> maybe_elms_obj =
311 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); 336 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1);
312 Handle<FixedArrayBase> elms_obj; 337 Handle<FixedArrayBase> elms_obj;
313 if (!maybe_elms_obj.ToHandle(&elms_obj)) { 338 if (!maybe_elms_obj.ToHandle(&elms_obj)) {
314 return CallJsIntrinsic(isolate, isolate->array_push(), args); 339 return CallJsIntrinsic(isolate, isolate->array_push(), args);
315 } 340 }
316 // Fast Elements Path 341 // Fast Elements Path
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
607 632
608 ElementsAccessor* accessor = object->GetElementsAccessor(); 633 ElementsAccessor* accessor = object->GetElementsAccessor();
609 accessor->CopyElements( 634 accessor->CopyElements(
610 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len); 635 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len);
611 return *result_array; 636 return *result_array;
612 } 637 }
613 638
614 639
615 BUILTIN(ArraySplice) { 640 BUILTIN(ArraySplice) {
616 HandleScope scope(isolate); 641 HandleScope scope(isolate);
617 Heap* heap = isolate->heap();
618 Handle<Object> receiver = args.receiver(); 642 Handle<Object> receiver = args.receiver();
619 MaybeHandle<FixedArrayBase> maybe_elms_obj = 643 MaybeHandle<FixedArrayBase> maybe_elms_obj =
620 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); 644 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3);
621 Handle<FixedArrayBase> elms_obj; 645 Handle<FixedArrayBase> elms_obj;
622 if (!maybe_elms_obj.ToHandle(&elms_obj)) { 646 if (!maybe_elms_obj.ToHandle(&elms_obj)) {
623 return CallJsIntrinsic(isolate, isolate->array_splice(), args); 647 return CallJsIntrinsic(isolate, isolate->array_splice(), args);
624 } 648 }
625 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 649 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
626 DCHECK(!array->map()->is_observed()); 650 DCHECK(!array->map()->is_observed());
627 651
628 int len = Smi::cast(array->length())->value(); 652 int argument_count = args.length() - 1;
629
630 int n_arguments = args.length() - 1;
631
632 int relative_start = 0; 653 int relative_start = 0;
633 if (n_arguments > 0) { 654 if (argument_count > 0) {
634 DisallowHeapAllocation no_gc; 655 DisallowHeapAllocation no_gc;
635 Object* arg1 = args[1]; 656 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; 657 AllowHeapAllocation allow_allocation;
647 return CallJsIntrinsic(isolate, isolate->array_splice(), args); 658 return CallJsIntrinsic(isolate, isolate->array_splice(), args);
648 } 659 }
649 } 660 }
661 int len = Smi::cast(array->length())->value();
662 // clip relative start to [0, len]
650 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) 663 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
651 : Min(relative_start, len); 664 : Min(relative_start, len);
652 665
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; 666 int actual_delete_count;
659 if (n_arguments == 1) { 667 if (argument_count == 1) {
668 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
669 // given as a request to delete all the elements from the start.
670 // And it differs from the case of undefined delete count.
671 // This does not follow ECMA-262, but we do the same for compatibility.
660 DCHECK(len - actual_start >= 0); 672 DCHECK(len - actual_start >= 0);
661 actual_delete_count = len - actual_start; 673 actual_delete_count = len - actual_start;
662 } else { 674 } else {
663 int value = 0; // ToInteger(undefined) == 0 675 int delete_count = 0;
664 if (n_arguments > 1) { 676 DisallowHeapAllocation no_gc;
665 DisallowHeapAllocation no_gc; 677 if (argument_count > 1) {
666 Object* arg2 = args[2]; 678 if (!ClampedToInteger(args[2], &delete_count)) {
667 if (arg2->IsSmi()) {
668 value = Smi::cast(arg2)->value();
669 } else {
670 AllowHeapAllocation allow_allocation; 679 AllowHeapAllocation allow_allocation;
671 return CallJsIntrinsic(isolate, isolate->array_splice(), args); 680 return CallJsIntrinsic(isolate, isolate->array_splice(), args);
672 } 681 }
673 } 682 }
674 actual_delete_count = Min(Max(value, 0), len - actual_start); 683 actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
675 } 684 }
676 685
677 ElementsKind elements_kind = array->GetElementsKind(); 686 int add_count = (argument_count > 1) ? (argument_count - 2) : 0;
678 687 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 688
687 if (new_length != len && JSArray::HasReadOnlyLength(array)) { 689 if (new_length != len && JSArray::HasReadOnlyLength(array)) {
688 AllowHeapAllocation allow_allocation; 690 AllowHeapAllocation allow_allocation;
689 return CallJsIntrinsic(isolate, isolate->array_splice(), args); 691 return CallJsIntrinsic(isolate, isolate->array_splice(), args);
690 } 692 }
691 693 ElementsAccessor* accessor = array->GetElementsAccessor();
692 if (new_length == 0) { 694 Handle<JSArray> result = accessor->Splice(
693 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements( 695 array, elms_obj, actual_start, actual_delete_count, args, add_count);
694 elms_obj, elements_kind, actual_delete_count); 696 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 } 697 }
832 698
833 699
834 BUILTIN(ArrayConcat) { 700 BUILTIN(ArrayConcat) {
835 HandleScope scope(isolate); 701 HandleScope scope(isolate);
836 702
837 int n_arguments = args.length(); 703 int n_arguments = args.length();
838 int result_len = 0; 704 int result_len = 0;
839 ElementsKind elements_kind = GetInitialFastElementsKind(); 705 ElementsKind elements_kind = GetInitialFastElementsKind();
840 bool has_double = false; 706 bool has_double = false;
(...skipping 686 matching lines...) Expand 10 before | Expand all | Expand 10 after
1527 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) 1393 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1528 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) 1394 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1529 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) 1395 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H)
1530 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) 1396 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1531 #undef DEFINE_BUILTIN_ACCESSOR_C 1397 #undef DEFINE_BUILTIN_ACCESSOR_C
1532 #undef DEFINE_BUILTIN_ACCESSOR_A 1398 #undef DEFINE_BUILTIN_ACCESSOR_A
1533 1399
1534 1400
1535 } // namespace internal 1401 } // namespace internal
1536 } // namespace v8 1402 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | src/elements.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698