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

Side by Side Diff: src/builtins.cc

Issue 223413002: Partial recover from performance degradation after handlification of ElementsAccessor::CopyElements… (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressing review comments Created 6 years, 8 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 | Annotate | Revision Log
« 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 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 MUST_USE_RESULT 295 MUST_USE_RESULT
296 static inline Handle<FixedArrayBase> EnsureJSArrayWithWritableFastElements( 296 static inline Handle<FixedArrayBase> EnsureJSArrayWithWritableFastElements(
297 Isolate* isolate, 297 Isolate* isolate,
298 Handle<Object> receiver, 298 Handle<Object> receiver,
299 Arguments* args, 299 Arguments* args,
300 int first_added_arg) { 300 int first_added_arg) {
301 if (!receiver->IsJSArray()) return Handle<FixedArrayBase>::null(); 301 if (!receiver->IsJSArray()) return Handle<FixedArrayBase>::null();
302 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 302 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
303 if (array->map()->is_observed()) return Handle<FixedArrayBase>::null(); 303 if (array->map()->is_observed()) return Handle<FixedArrayBase>::null();
304 if (!array->map()->is_extensible()) return Handle<FixedArrayBase>::null(); 304 if (!array->map()->is_extensible()) return Handle<FixedArrayBase>::null();
305 Handle<FixedArrayBase> elms(array->elements()); 305 Handle<FixedArrayBase> elms(array->elements(), isolate);
306 Heap* heap = isolate->heap(); 306 Heap* heap = isolate->heap();
307 Map* map = elms->map(); 307 Map* map = elms->map();
308 if (map == heap->fixed_array_map()) { 308 if (map == heap->fixed_array_map()) {
309 if (args == NULL || array->HasFastObjectElements()) return elms; 309 if (args == NULL || array->HasFastObjectElements()) return elms;
310 } else if (map == heap->fixed_cow_array_map()) { 310 } else if (map == heap->fixed_cow_array_map()) {
311 elms = JSObject::EnsureWritableFastElements(array); 311 elms = JSObject::EnsureWritableFastElements(array);
312 if (args == NULL || array->HasFastObjectElements()) return elms; 312 if (args == NULL || array->HasFastObjectElements()) return elms;
313 } else if (map == heap->fixed_double_array_map()) { 313 } else if (map == heap->fixed_double_array_map()) {
314 if (args == NULL) return elms; 314 if (args == NULL) return elms;
315 } else { 315 } else {
316 return Handle<FixedArrayBase>::null(); 316 return Handle<FixedArrayBase>::null();
317 } 317 }
318 318
319 // Need to ensure that the arguments passed in args can be contained in 319 // Need to ensure that the arguments passed in args can be contained in
320 // the array. 320 // the array.
321 int args_length = args->length(); 321 int args_length = args->length();
322 if (first_added_arg >= args_length) return handle(array->elements()); 322 if (first_added_arg >= args_length) return handle(array->elements(), isolate);
323 323
324 ElementsKind origin_kind = array->map()->elements_kind(); 324 ElementsKind origin_kind = array->map()->elements_kind();
325 ASSERT(!IsFastObjectElementsKind(origin_kind)); 325 ASSERT(!IsFastObjectElementsKind(origin_kind));
326 ElementsKind target_kind = origin_kind; 326 ElementsKind target_kind = origin_kind;
327 int arg_count = args->length() - first_added_arg; 327 int arg_count = args->length() - first_added_arg;
328 Object** arguments = args->arguments() - first_added_arg - (arg_count - 1); 328 Object** arguments = args->arguments() - first_added_arg - (arg_count - 1);
329 for (int i = 0; i < arg_count; i++) { 329 for (int i = 0; i < arg_count; i++) {
330 Object* arg = arguments[i]; 330 Object* arg = arguments[i];
331 if (arg->IsHeapObject()) { 331 if (arg->IsHeapObject()) {
332 if (arg->IsHeapNumber()) { 332 if (arg->IsHeapNumber()) {
333 target_kind = FAST_DOUBLE_ELEMENTS; 333 target_kind = FAST_DOUBLE_ELEMENTS;
334 } else { 334 } else {
335 target_kind = FAST_ELEMENTS; 335 target_kind = FAST_ELEMENTS;
336 break; 336 break;
337 } 337 }
338 } 338 }
339 } 339 }
340 if (target_kind != origin_kind) { 340 if (target_kind != origin_kind) {
341 JSObject::TransitionElementsKind(array, target_kind); 341 JSObject::TransitionElementsKind(array, target_kind);
342 return handle(array->elements()); 342 return handle(array->elements(), isolate);
343 } 343 }
344 return elms; 344 return elms;
345 } 345 }
346 346
347 347
348 // TODO(ishell): Handlify when all Array* builtins are handlified. 348 // TODO(ishell): Handlify when all Array* builtins are handlified.
349 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap, 349 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
350 JSArray* receiver) { 350 JSArray* receiver) {
351 if (!FLAG_clever_optimizations) return false; 351 if (!FLAG_clever_optimizations) return false;
352 Context* native_context = heap->isolate()->context()->native_context(); 352 Context* native_context = heap->isolate()->context()->native_context();
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 int new_length = len + to_add; 411 int new_length = len + to_add;
412 412
413 if (new_length > elms->length()) { 413 if (new_length > elms->length()) {
414 // New backing storage is needed. 414 // New backing storage is needed.
415 int capacity = new_length + (new_length >> 1) + 16; 415 int capacity = new_length + (new_length >> 1) + 16;
416 Handle<FixedArray> new_elms = 416 Handle<FixedArray> new_elms =
417 isolate->factory()->NewUninitializedFixedArray(capacity); 417 isolate->factory()->NewUninitializedFixedArray(capacity);
418 418
419 ElementsAccessor* accessor = array->GetElementsAccessor(); 419 ElementsAccessor* accessor = array->GetElementsAccessor();
420 accessor->CopyElements( 420 accessor->CopyElements(
421 Handle<JSObject>::null(), 0, kind, new_elms, 0, 421 elms_obj, 0, kind, new_elms, 0,
422 ElementsAccessor::kCopyToEndAndInitializeToHole, elms_obj); 422 ElementsAccessor::kCopyToEndAndInitializeToHole);
423 423
424 elms = new_elms; 424 elms = new_elms;
425 } 425 }
426 426
427 // Add the provided values. 427 // Add the provided values.
428 DisallowHeapAllocation no_gc; 428 DisallowHeapAllocation no_gc;
429 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 429 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
430 for (int index = 0; index < to_add; index++) { 430 for (int index = 0; index < to_add; index++) {
431 elms->set(index + len, args[index + 1], mode); 431 elms->set(index + len, args[index + 1], mode);
432 } 432 }
(...skipping 21 matching lines...) Expand all
454 454
455 Handle<FixedDoubleArray> new_elms; 455 Handle<FixedDoubleArray> new_elms;
456 456
457 if (new_length > elms_len) { 457 if (new_length > elms_len) {
458 // New backing storage is needed. 458 // New backing storage is needed.
459 int capacity = new_length + (new_length >> 1) + 16; 459 int capacity = new_length + (new_length >> 1) + 16;
460 new_elms = isolate->factory()->NewFixedDoubleArray(capacity); 460 new_elms = isolate->factory()->NewFixedDoubleArray(capacity);
461 461
462 ElementsAccessor* accessor = array->GetElementsAccessor(); 462 ElementsAccessor* accessor = array->GetElementsAccessor();
463 accessor->CopyElements( 463 accessor->CopyElements(
464 Handle<JSObject>::null(), 0, kind, new_elms, 0, 464 elms_obj, 0, kind, new_elms, 0,
465 ElementsAccessor::kCopyToEndAndInitializeToHole, elms_obj); 465 ElementsAccessor::kCopyToEndAndInitializeToHole);
466 466
467 } else { 467 } else {
468 // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the 468 // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the
469 // empty_fixed_array. 469 // empty_fixed_array.
470 new_elms = Handle<FixedDoubleArray>::cast(elms_obj); 470 new_elms = Handle<FixedDoubleArray>::cast(elms_obj);
471 } 471 }
472 472
473 // Add the provided values. 473 // Add the provided values.
474 DisallowHeapAllocation no_gc; 474 DisallowHeapAllocation no_gc;
475 int index; 475 int index;
476 for (index = 0; index < to_add; index++) { 476 for (index = 0; index < to_add; index++) {
477 Object* arg = args[index + 1]; 477 Object* arg = args[index + 1];
478 new_elms->set(index + len, arg->Number()); 478 new_elms->set(index + len, arg->Number());
479 } 479 }
480 480
481 if (*new_elms != array->elements()) { 481 if (*new_elms != array->elements()) {
482 array->set_elements(*new_elms); 482 array->set_elements(*new_elms);
483 } 483 }
484 484
485 // Set the length. 485 // Set the length.
486 array->set_length(Smi::FromInt(new_length)); 486 array->set_length(Smi::FromInt(new_length));
487 return Smi::FromInt(new_length); 487 return Smi::FromInt(new_length);
488 } 488 }
489 } 489 }
490 490
491 491
492 // TODO(ishell): Temporary wrapper until handlified.
493 static bool ElementsAccessorHasElementWrapper(
494 ElementsAccessor* accessor,
495 Handle<Object> receiver,
496 Handle<JSObject> holder,
497 uint32_t key,
498 Handle<FixedArrayBase> backing_store = Handle<FixedArrayBase>::null()) {
499 return accessor->HasElement(*receiver, *holder, key,
500 backing_store.is_null() ? NULL : *backing_store);
501 }
502
503
504 BUILTIN(ArrayPop) { 492 BUILTIN(ArrayPop) {
505 HandleScope scope(isolate); 493 HandleScope scope(isolate);
506 Handle<Object> receiver = args.receiver(); 494 Handle<Object> receiver = args.receiver();
507 Handle<FixedArrayBase> elms_obj = 495 Handle<FixedArrayBase> elms_obj =
508 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); 496 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
509 if (elms_obj.is_null()) return CallJsBuiltin(isolate, "ArrayPop", args); 497 if (elms_obj.is_null()) return CallJsBuiltin(isolate, "ArrayPop", args);
510 498
511 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 499 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
512 ASSERT(!array->map()->is_observed()); 500 ASSERT(!array->map()->is_observed());
513 501
514 int len = Smi::cast(array->length())->value(); 502 int len = Smi::cast(array->length())->value();
515 if (len == 0) return isolate->heap()->undefined_value(); 503 if (len == 0) return isolate->heap()->undefined_value();
516 504
517 ElementsAccessor* accessor = array->GetElementsAccessor(); 505 ElementsAccessor* accessor = array->GetElementsAccessor();
518 int new_length = len - 1; 506 int new_length = len - 1;
519 Handle<Object> element; 507 Handle<Object> element;
520 if (ElementsAccessorHasElementWrapper( 508 if (accessor->HasElement(*array, *array, new_length, *elms_obj)) {
521 accessor, array, array, new_length, elms_obj)) {
522 element = accessor->Get( 509 element = accessor->Get(
523 array, array, new_length, elms_obj); 510 array, array, new_length, elms_obj);
524 } else { 511 } else {
525 Handle<Object> proto(array->GetPrototype(), isolate); 512 Handle<Object> proto(array->GetPrototype(), isolate);
526 element = Object::GetElement(isolate, proto, len - 1); 513 element = Object::GetElement(isolate, proto, len - 1);
527 } 514 }
528 RETURN_IF_EMPTY_HANDLE(isolate, element); 515 RETURN_IF_EMPTY_HANDLE(isolate, element);
529 RETURN_IF_EMPTY_HANDLE(isolate, 516 RETURN_IF_EMPTY_HANDLE(isolate,
530 accessor->SetLength( 517 accessor->SetLength(
531 array, handle(Smi::FromInt(new_length), isolate))); 518 array, handle(Smi::FromInt(new_length), isolate)));
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
611 598
612 if (new_length > elms->length()) { 599 if (new_length > elms->length()) {
613 // New backing storage is needed. 600 // New backing storage is needed.
614 int capacity = new_length + (new_length >> 1) + 16; 601 int capacity = new_length + (new_length >> 1) + 16;
615 Handle<FixedArray> new_elms = 602 Handle<FixedArray> new_elms =
616 isolate->factory()->NewUninitializedFixedArray(capacity); 603 isolate->factory()->NewUninitializedFixedArray(capacity);
617 604
618 ElementsKind kind = array->GetElementsKind(); 605 ElementsKind kind = array->GetElementsKind();
619 ElementsAccessor* accessor = array->GetElementsAccessor(); 606 ElementsAccessor* accessor = array->GetElementsAccessor();
620 accessor->CopyElements( 607 accessor->CopyElements(
621 Handle<JSObject>::null(), 0, kind, new_elms, to_add, 608 elms, 0, kind, new_elms, to_add,
622 ElementsAccessor::kCopyToEndAndInitializeToHole, elms); 609 ElementsAccessor::kCopyToEndAndInitializeToHole);
623 610
624 elms = new_elms; 611 elms = new_elms;
625 array->set_elements(*elms); 612 array->set_elements(*elms);
626 } else { 613 } else {
627 DisallowHeapAllocation no_gc; 614 DisallowHeapAllocation no_gc;
628 heap->MoveElements(*elms, to_add, 0, len); 615 heap->MoveElements(*elms, to_add, 0, len);
629 } 616 }
630 617
631 // Add the provided values. 618 // Add the provided values.
632 DisallowHeapAllocation no_gc; 619 DisallowHeapAllocation no_gc;
633 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 620 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
634 for (int i = 0; i < to_add; i++) { 621 for (int i = 0; i < to_add; i++) {
635 elms->set(i, args[i + 1], mode); 622 elms->set(i, args[i + 1], mode);
636 } 623 }
637 624
638 // Set the length. 625 // Set the length.
639 array->set_length(Smi::FromInt(new_length)); 626 array->set_length(Smi::FromInt(new_length));
640 return Smi::FromInt(new_length); 627 return Smi::FromInt(new_length);
641 } 628 }
642 629
643 630
644 BUILTIN(ArraySlice) { 631 BUILTIN(ArraySlice) {
645 HandleScope scope(isolate); 632 HandleScope scope(isolate);
646 Heap* heap = isolate->heap(); 633 Heap* heap = isolate->heap();
647 Handle<Object> receiver = args.receiver(); 634 Handle<Object> receiver = args.receiver();
648 Handle<FixedArrayBase> elms;
649 int len = -1; 635 int len = -1;
650 if (receiver->IsJSArray()) { 636 int relative_start = 0;
651 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 637 int relative_end = 0;
652 if (!IsJSArrayFastElementMovingAllowed(heap, *array)) { 638 {
653 return CallJsBuiltin(isolate, "ArraySlice", args); 639 DisallowHeapAllocation no_gc;
640 if (receiver->IsJSArray()) {
641 JSArray* array = JSArray::cast(*receiver);
642 if (!IsJSArrayFastElementMovingAllowed(heap, array)) {
643 AllowHeapAllocation allow_allocation;
644 return CallJsBuiltin(isolate, "ArraySlice", args);
645 }
646
647 if (!array->HasFastElements()) {
648 AllowHeapAllocation allow_allocation;
649 return CallJsBuiltin(isolate, "ArraySlice", args);
650 }
651
652 len = Smi::cast(array->length())->value();
653 } else {
654 // Array.slice(arguments, ...) is quite a common idiom (notably more
655 // than 50% of invocations in Web apps). Treat it in C++ as well.
656 Map* arguments_map = isolate->context()->native_context()->
657 sloppy_arguments_boilerplate()->map();
658
659 bool is_arguments_object_with_fast_elements =
660 receiver->IsJSObject() &&
661 JSObject::cast(*receiver)->map() == arguments_map;
662 if (!is_arguments_object_with_fast_elements) {
663 AllowHeapAllocation allow_allocation;
664 return CallJsBuiltin(isolate, "ArraySlice", args);
665 }
666 JSObject* object = JSObject::cast(*receiver);
667
668 if (!object->HasFastElements()) {
669 AllowHeapAllocation allow_allocation;
670 return CallJsBuiltin(isolate, "ArraySlice", args);
671 }
672
673 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
674 if (!len_obj->IsSmi()) {
675 AllowHeapAllocation allow_allocation;
676 return CallJsBuiltin(isolate, "ArraySlice", args);
677 }
678 len = Smi::cast(len_obj)->value();
679 if (len > object->elements()->length()) {
680 AllowHeapAllocation allow_allocation;
681 return CallJsBuiltin(isolate, "ArraySlice", args);
682 }
654 } 683 }
655 684
656 if (array->HasFastElements()) { 685 ASSERT(len >= 0);
657 elms = handle(array->elements()); 686 int n_arguments = args.length() - 1;
658 } else {
659 return CallJsBuiltin(isolate, "ArraySlice", args);
660 }
661 687
662 len = Smi::cast(array->length())->value(); 688 // Note carefully choosen defaults---if argument is missing,
663 } else { 689 // it's undefined which gets converted to 0 for relative_start
664 // Array.slice(arguments, ...) is quite a common idiom (notably more 690 // and to len for relative_end.
665 // than 50% of invocations in Web apps). Treat it in C++ as well. 691 relative_start = 0;
666 Handle<Map> arguments_map(isolate->context()->native_context()-> 692 relative_end = len;
667 sloppy_arguments_boilerplate()->map()); 693 if (n_arguments > 0) {
668 694 Object* arg1 = args[1];
669 bool is_arguments_object_with_fast_elements = 695 if (arg1->IsSmi()) {
670 receiver->IsJSObject() && 696 relative_start = Smi::cast(arg1)->value();
671 Handle<JSObject>::cast(receiver)->map() == *arguments_map; 697 } else if (arg1->IsHeapNumber()) {
672 if (!is_arguments_object_with_fast_elements) { 698 double start = HeapNumber::cast(arg1)->value();
673 return CallJsBuiltin(isolate, "ArraySlice", args); 699 if (start < kMinInt || start > kMaxInt) {
674 } 700 AllowHeapAllocation allow_allocation;
675 Handle<JSObject> object = Handle<JSObject>::cast(receiver); 701 return CallJsBuiltin(isolate, "ArraySlice", args);
676 702 }
677 if (object->HasFastElements()) { 703 relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
678 elms = handle(object->elements()); 704 } else if (!arg1->IsUndefined()) {
679 } else { 705 AllowHeapAllocation allow_allocation;
680 return CallJsBuiltin(isolate, "ArraySlice", args);
681 }
682 Handle<Object> len_obj(
683 object->InObjectPropertyAt(Heap::kArgumentsLengthIndex), isolate);
684 if (!len_obj->IsSmi()) {
685 return CallJsBuiltin(isolate, "ArraySlice", args);
686 }
687 len = Handle<Smi>::cast(len_obj)->value();
688 if (len > elms->length()) {
689 return CallJsBuiltin(isolate, "ArraySlice", args);
690 }
691 }
692
693 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
694
695 ASSERT(len >= 0);
696 int n_arguments = args.length() - 1;
697
698 // Note carefully choosen defaults---if argument is missing,
699 // it's undefined which gets converted to 0 for relative_start
700 // and to len for relative_end.
701 int relative_start = 0;
702 int relative_end = len;
703 if (n_arguments > 0) {
704 Handle<Object> arg1 = args.at<Object>(1);
705 if (arg1->IsSmi()) {
706 relative_start = Handle<Smi>::cast(arg1)->value();
707 } else if (arg1->IsHeapNumber()) {
708 double start = Handle<HeapNumber>::cast(arg1)->value();
709 if (start < kMinInt || start > kMaxInt) {
710 return CallJsBuiltin(isolate, "ArraySlice", args); 706 return CallJsBuiltin(isolate, "ArraySlice", args);
711 } 707 }
712 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); 708 if (n_arguments > 1) {
713 } else if (!arg1->IsUndefined()) { 709 Object* arg2 = args[2];
714 return CallJsBuiltin(isolate, "ArraySlice", args); 710 if (arg2->IsSmi()) {
715 } 711 relative_end = Smi::cast(arg2)->value();
716 if (n_arguments > 1) { 712 } else if (arg2->IsHeapNumber()) {
717 Handle<Object> arg2 = args.at<Object>(2); 713 double end = HeapNumber::cast(arg2)->value();
718 if (arg2->IsSmi()) { 714 if (end < kMinInt || end > kMaxInt) {
719 relative_end = Handle<Smi>::cast(arg2)->value(); 715 AllowHeapAllocation allow_allocation;
720 } else if (arg2->IsHeapNumber()) { 716 return CallJsBuiltin(isolate, "ArraySlice", args);
721 double end = Handle<HeapNumber>::cast(arg2)->value(); 717 }
722 if (end < kMinInt || end > kMaxInt) { 718 relative_end = std::isnan(end) ? 0 : static_cast<int>(end);
719 } else if (!arg2->IsUndefined()) {
720 AllowHeapAllocation allow_allocation;
723 return CallJsBuiltin(isolate, "ArraySlice", args); 721 return CallJsBuiltin(isolate, "ArraySlice", args);
724 } 722 }
725 relative_end = std::isnan(end) ? 0 : static_cast<int>(end);
726 } else if (!arg2->IsUndefined()) {
727 return CallJsBuiltin(isolate, "ArraySlice", args);
728 } 723 }
729 } 724 }
730 } 725 }
731 726
732 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. 727 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
733 int k = (relative_start < 0) ? Max(len + relative_start, 0) 728 int k = (relative_start < 0) ? Max(len + relative_start, 0)
734 : Min(relative_start, len); 729 : Min(relative_start, len);
735 730
736 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. 731 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
737 int final = (relative_end < 0) ? Max(len + relative_end, 0) 732 int final = (relative_end < 0) ? Max(len + relative_end, 0)
738 : Min(relative_end, len); 733 : Min(relative_end, len);
739 734
740 // Calculate the length of result array. 735 // Calculate the length of result array.
741 int result_len = Max(final - k, 0); 736 int result_len = Max(final - k, 0);
742 737
738 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
739 Handle<FixedArrayBase> elms(object->elements(), isolate);
740
743 ElementsKind kind = object->GetElementsKind(); 741 ElementsKind kind = object->GetElementsKind();
744 if (IsHoleyElementsKind(kind)) { 742 if (IsHoleyElementsKind(kind)) {
743 DisallowHeapAllocation no_gc;
745 bool packed = true; 744 bool packed = true;
746 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); 745 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
747 for (int i = k; i < final; i++) { 746 for (int i = k; i < final; i++) {
748 if (!ElementsAccessorHasElementWrapper( 747 if (!accessor->HasElement(*object, *object, i, *elms)) {
749 accessor, object, object, i, elms)) {
750 packed = false; 748 packed = false;
751 break; 749 break;
752 } 750 }
753 } 751 }
754 if (packed) { 752 if (packed) {
755 kind = GetPackedElementsKind(kind); 753 kind = GetPackedElementsKind(kind);
756 } else if (!receiver->IsJSArray()) { 754 } else if (!receiver->IsJSArray()) {
755 AllowHeapAllocation allow_allocation;
757 return CallJsBuiltin(isolate, "ArraySlice", args); 756 return CallJsBuiltin(isolate, "ArraySlice", args);
758 } 757 }
759 } 758 }
760 759
761 Handle<JSArray> result_array = 760 Handle<JSArray> result_array =
762 isolate->factory()->NewJSArray(kind, result_len, result_len); 761 isolate->factory()->NewJSArray(kind, result_len, result_len);
763 762
764 DisallowHeapAllocation no_gc; 763 DisallowHeapAllocation no_gc;
765 if (result_len == 0) return *result_array; 764 if (result_len == 0) return *result_array;
766 765
767 ElementsAccessor* accessor = object->GetElementsAccessor(); 766 ElementsAccessor* accessor = object->GetElementsAccessor();
768 accessor->CopyElements(Handle<JSObject>::null(), k, kind, 767 accessor->CopyElements(
769 handle(result_array->elements()), 0, result_len, elms); 768 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len);
770 return *result_array; 769 return *result_array;
771 } 770 }
772 771
773 772
774 BUILTIN(ArraySplice) { 773 BUILTIN(ArraySplice) {
775 HandleScope scope(isolate); 774 HandleScope scope(isolate);
776 Heap* heap = isolate->heap(); 775 Heap* heap = isolate->heap();
777 Handle<Object> receiver = args.receiver(); 776 Handle<Object> receiver = args.receiver();
778 Handle<FixedArrayBase> elms_obj = 777 Handle<FixedArrayBase> elms_obj =
779 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); 778 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3);
780 if (elms_obj.is_null() || 779 if (elms_obj.is_null() ||
781 !IsJSArrayFastElementMovingAllowed(heap, 780 !IsJSArrayFastElementMovingAllowed(heap,
782 *Handle<JSArray>::cast(receiver))) { 781 *Handle<JSArray>::cast(receiver))) {
783 return CallJsBuiltin(isolate, "ArraySplice", args); 782 return CallJsBuiltin(isolate, "ArraySplice", args);
784 } 783 }
785 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 784 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
786 ASSERT(!array->map()->is_observed()); 785 ASSERT(!array->map()->is_observed());
787 786
788 int len = Smi::cast(array->length())->value(); 787 int len = Smi::cast(array->length())->value();
789 788
790 int n_arguments = args.length() - 1; 789 int n_arguments = args.length() - 1;
791 790
792 int relative_start = 0; 791 int relative_start = 0;
793 if (n_arguments > 0) { 792 if (n_arguments > 0) {
794 Handle<Object> arg1 = args.at<Object>(1); 793 DisallowHeapAllocation no_gc;
794 Object* arg1 = args[1];
795 if (arg1->IsSmi()) { 795 if (arg1->IsSmi()) {
796 relative_start = Handle<Smi>::cast(arg1)->value(); 796 relative_start = Smi::cast(arg1)->value();
797 } else if (arg1->IsHeapNumber()) { 797 } else if (arg1->IsHeapNumber()) {
798 double start = Handle<HeapNumber>::cast(arg1)->value(); 798 double start = HeapNumber::cast(arg1)->value();
799 if (start < kMinInt || start > kMaxInt) { 799 if (start < kMinInt || start > kMaxInt) {
800 AllowHeapAllocation allow_allocation;
800 return CallJsBuiltin(isolate, "ArraySplice", args); 801 return CallJsBuiltin(isolate, "ArraySplice", args);
801 } 802 }
802 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); 803 relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
803 } else if (!arg1->IsUndefined()) { 804 } else if (!arg1->IsUndefined()) {
805 AllowHeapAllocation allow_allocation;
804 return CallJsBuiltin(isolate, "ArraySplice", args); 806 return CallJsBuiltin(isolate, "ArraySplice", args);
805 } 807 }
806 } 808 }
807 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) 809 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
808 : Min(relative_start, len); 810 : Min(relative_start, len);
809 811
810 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is 812 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
811 // given as a request to delete all the elements from the start. 813 // given as a request to delete all the elements from the start.
812 // And it differs from the case of undefined delete count. 814 // And it differs from the case of undefined delete count.
813 // This does not follow ECMA-262, but we do the same for 815 // This does not follow ECMA-262, but we do the same for
814 // compatibility. 816 // compatibility.
815 int actual_delete_count; 817 int actual_delete_count;
816 if (n_arguments == 1) { 818 if (n_arguments == 1) {
817 ASSERT(len - actual_start >= 0); 819 ASSERT(len - actual_start >= 0);
818 actual_delete_count = len - actual_start; 820 actual_delete_count = len - actual_start;
819 } else { 821 } else {
820 int value = 0; // ToInteger(undefined) == 0 822 int value = 0; // ToInteger(undefined) == 0
821 if (n_arguments > 1) { 823 if (n_arguments > 1) {
824 DisallowHeapAllocation no_gc;
822 Object* arg2 = args[2]; 825 Object* arg2 = args[2];
823 if (arg2->IsSmi()) { 826 if (arg2->IsSmi()) {
824 value = Smi::cast(arg2)->value(); 827 value = Smi::cast(arg2)->value();
825 } else { 828 } else {
829 AllowHeapAllocation allow_allocation;
826 return CallJsBuiltin(isolate, "ArraySplice", args); 830 return CallJsBuiltin(isolate, "ArraySplice", args);
827 } 831 }
828 } 832 }
829 actual_delete_count = Min(Max(value, 0), len - actual_start); 833 actual_delete_count = Min(Max(value, 0), len - actual_start);
830 } 834 }
831 835
832 ElementsKind elements_kind = array->GetElementsKind(); 836 ElementsKind elements_kind = array->GetElementsKind();
833 837
834 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; 838 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
835 int new_length = len - actual_delete_count + item_count; 839 int new_length = len - actual_delete_count + item_count;
(...skipping 13 matching lines...) Expand all
849 853
850 Handle<JSArray> result_array = 854 Handle<JSArray> result_array =
851 isolate->factory()->NewJSArray(elements_kind, 855 isolate->factory()->NewJSArray(elements_kind,
852 actual_delete_count, 856 actual_delete_count,
853 actual_delete_count); 857 actual_delete_count);
854 858
855 if (actual_delete_count > 0) { 859 if (actual_delete_count > 0) {
856 DisallowHeapAllocation no_gc; 860 DisallowHeapAllocation no_gc;
857 ElementsAccessor* accessor = array->GetElementsAccessor(); 861 ElementsAccessor* accessor = array->GetElementsAccessor();
858 accessor->CopyElements( 862 accessor->CopyElements(
859 Handle<JSObject>::null(), actual_start, elements_kind, 863 elms_obj, actual_start, elements_kind,
860 handle(result_array->elements()), 0, actual_delete_count, elms_obj); 864 handle(result_array->elements(), isolate), 0, actual_delete_count);
861 } 865 }
862 866
863 bool elms_changed = false; 867 bool elms_changed = false;
864 if (item_count < actual_delete_count) { 868 if (item_count < actual_delete_count) {
865 // Shrink the array. 869 // Shrink the array.
866 const bool trim_array = !heap->lo_space()->Contains(*elms_obj) && 870 const bool trim_array = !heap->lo_space()->Contains(*elms_obj) &&
867 ((actual_start + item_count) < 871 ((actual_start + item_count) <
868 (len - actual_delete_count - actual_start)); 872 (len - actual_delete_count - actual_start));
869 if (trim_array) { 873 if (trim_array) {
870 const int delta = actual_delete_count - item_count; 874 const int delta = actual_delete_count - item_count;
871 875
872 if (elms_obj->IsFixedDoubleArray()) { 876 if (elms_obj->IsFixedDoubleArray()) {
873 Handle<FixedDoubleArray> elms = 877 Handle<FixedDoubleArray> elms =
874 Handle<FixedDoubleArray>::cast(elms_obj); 878 Handle<FixedDoubleArray>::cast(elms_obj);
875 MoveDoubleElements(*elms, delta, *elms, 0, actual_start); 879 MoveDoubleElements(*elms, delta, *elms, 0, actual_start);
876 } else { 880 } else {
877 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); 881 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
878 DisallowHeapAllocation no_gc; 882 DisallowHeapAllocation no_gc;
879 heap->MoveElements(*elms, delta, 0, actual_start); 883 heap->MoveElements(*elms, delta, 0, actual_start);
880 } 884 }
881 885
882 if (heap->CanMoveObjectStart(*elms_obj)) { 886 if (heap->CanMoveObjectStart(*elms_obj)) {
883 // On the fast path we move the start of the object in memory. 887 // On the fast path we move the start of the object in memory.
884 elms_obj = handle(LeftTrimFixedArray(heap, *elms_obj, delta)); 888 elms_obj = handle(LeftTrimFixedArray(heap, *elms_obj, delta), isolate);
885 } else { 889 } else {
886 // This is the slow path. We are going to move the elements to the left 890 // This is the slow path. We are going to move the elements to the left
887 // by copying them. For trimmed values we store the hole. 891 // by copying them. For trimmed values we store the hole.
888 if (elms_obj->IsFixedDoubleArray()) { 892 if (elms_obj->IsFixedDoubleArray()) {
889 Handle<FixedDoubleArray> elms = 893 Handle<FixedDoubleArray> elms =
890 Handle<FixedDoubleArray>::cast(elms_obj); 894 Handle<FixedDoubleArray>::cast(elms_obj);
891 MoveDoubleElements(*elms, 0, *elms, delta, len - delta); 895 MoveDoubleElements(*elms, 0, *elms, delta, len - delta);
892 elms->FillWithHoles(len - delta, len); 896 elms->FillWithHoles(len - delta, len);
893 } else { 897 } else {
894 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); 898 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
928 Handle<FixedArray> new_elms = 932 Handle<FixedArray> new_elms =
929 isolate->factory()->NewUninitializedFixedArray(capacity); 933 isolate->factory()->NewUninitializedFixedArray(capacity);
930 934
931 DisallowHeapAllocation no_gc; 935 DisallowHeapAllocation no_gc;
932 936
933 ElementsKind kind = array->GetElementsKind(); 937 ElementsKind kind = array->GetElementsKind();
934 ElementsAccessor* accessor = array->GetElementsAccessor(); 938 ElementsAccessor* accessor = array->GetElementsAccessor();
935 if (actual_start > 0) { 939 if (actual_start > 0) {
936 // Copy the part before actual_start as is. 940 // Copy the part before actual_start as is.
937 accessor->CopyElements( 941 accessor->CopyElements(
938 Handle<JSObject>::null(), 0, kind, new_elms, 0, actual_start, elms); 942 elms, 0, kind, new_elms, 0, actual_start);
939 } 943 }
940 accessor->CopyElements( 944 accessor->CopyElements(
941 Handle<JSObject>::null(), actual_start + actual_delete_count, kind, 945 elms, actual_start + actual_delete_count, kind,
942 new_elms, actual_start + item_count, 946 new_elms, actual_start + item_count,
943 ElementsAccessor::kCopyToEndAndInitializeToHole, elms); 947 ElementsAccessor::kCopyToEndAndInitializeToHole);
944 948
945 elms_obj = new_elms; 949 elms_obj = new_elms;
946 elms_changed = true; 950 elms_changed = true;
947 } else { 951 } else {
948 DisallowHeapAllocation no_gc; 952 DisallowHeapAllocation no_gc;
949 heap->MoveElements(*elms, actual_start + item_count, 953 heap->MoveElements(*elms, actual_start + item_count,
950 actual_start + actual_delete_count, 954 actual_start + actual_delete_count,
951 (len - actual_delete_count - actual_start)); 955 (len - actual_delete_count - actual_start));
952 } 956 }
953 } 957 }
(...skipping 23 matching lines...) Expand all
977 // Set the length. 981 // Set the length.
978 array->set_length(Smi::FromInt(new_length)); 982 array->set_length(Smi::FromInt(new_length));
979 983
980 return *result_array; 984 return *result_array;
981 } 985 }
982 986
983 987
984 BUILTIN(ArrayConcat) { 988 BUILTIN(ArrayConcat) {
985 HandleScope scope(isolate); 989 HandleScope scope(isolate);
986 Heap* heap = isolate->heap(); 990 Heap* heap = isolate->heap();
987 Handle<Context> native_context(isolate->context()->native_context()); 991 Handle<Context> native_context(isolate->context()->native_context(), isolate);
988 Handle<JSObject> array_proto( 992 Handle<JSObject> array_proto(
989 JSObject::cast(native_context->array_function()->prototype())); 993 JSObject::cast(native_context->array_function()->prototype()), isolate);
990 if (!ArrayPrototypeHasNoElements(heap, *native_context, *array_proto)) { 994 if (!ArrayPrototypeHasNoElements(heap, *native_context, *array_proto)) {
991 return CallJsBuiltin(isolate, "ArrayConcat", args); 995 return CallJsBuiltin(isolate, "ArrayConcat", args);
992 } 996 }
993 997
994 // Iterate through all the arguments performing checks 998 // Iterate through all the arguments performing checks
995 // and calculating total length. 999 // and calculating total length.
996 int n_arguments = args.length(); 1000 int n_arguments = args.length();
997 int result_len = 0; 1001 int result_len = 0;
998 ElementsKind elements_kind = GetInitialFastElementsKind(); 1002 ElementsKind elements_kind = GetInitialFastElementsKind();
999 bool has_double = false; 1003 bool has_double = false;
1000 bool is_holey = false; 1004 bool is_holey = false;
1001 for (int i = 0; i < n_arguments; i++) { 1005 for (int i = 0; i < n_arguments; i++) {
1002 Handle<Object> arg = args.at<Object>(i); 1006 DisallowHeapAllocation no_gc;
1007 Object* arg = args[i];
1003 if (!arg->IsJSArray() || 1008 if (!arg->IsJSArray() ||
1004 !Handle<JSArray>::cast(arg)->HasFastElements() || 1009 !JSArray::cast(arg)->HasFastElements() ||
1005 Handle<JSArray>::cast(arg)->GetPrototype() != *array_proto) { 1010 JSArray::cast(arg)->GetPrototype() != *array_proto) {
1011 AllowHeapAllocation allow_allocation;
1006 return CallJsBuiltin(isolate, "ArrayConcat", args); 1012 return CallJsBuiltin(isolate, "ArrayConcat", args);
1007 } 1013 }
1008 int len = Smi::cast(Handle<JSArray>::cast(arg)->length())->value(); 1014 int len = Smi::cast(JSArray::cast(arg)->length())->value();
1009 1015
1010 // We shouldn't overflow when adding another len. 1016 // We shouldn't overflow when adding another len.
1011 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); 1017 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
1012 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); 1018 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
1013 USE(kHalfOfMaxInt); 1019 USE(kHalfOfMaxInt);
1014 result_len += len; 1020 result_len += len;
1015 ASSERT(result_len >= 0); 1021 ASSERT(result_len >= 0);
1016 1022
1017 if (result_len > FixedDoubleArray::kMaxLength) { 1023 if (result_len > FixedDoubleArray::kMaxLength) {
1024 AllowHeapAllocation allow_allocation;
1018 return CallJsBuiltin(isolate, "ArrayConcat", args); 1025 return CallJsBuiltin(isolate, "ArrayConcat", args);
1019 } 1026 }
1020 1027
1021 ElementsKind arg_kind = Handle<JSArray>::cast(arg)->map()->elements_kind(); 1028 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
1022 has_double = has_double || IsFastDoubleElementsKind(arg_kind); 1029 has_double = has_double || IsFastDoubleElementsKind(arg_kind);
1023 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind); 1030 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
1024 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) { 1031 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) {
1025 elements_kind = arg_kind; 1032 elements_kind = arg_kind;
1026 } 1033 }
1027 } 1034 }
1028 1035
1029 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind); 1036 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind);
1030 1037
1031 // If a double array is concatted into a fast elements array, the fast 1038 // If a double array is concatted into a fast elements array, the fast
1032 // elements array needs to be initialized to contain proper holes, since 1039 // elements array needs to be initialized to contain proper holes, since
1033 // boxing doubles may cause incremental marking. 1040 // boxing doubles may cause incremental marking.
1034 ArrayStorageAllocationMode mode = 1041 ArrayStorageAllocationMode mode =
1035 has_double && IsFastObjectElementsKind(elements_kind) 1042 has_double && IsFastObjectElementsKind(elements_kind)
1036 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE : DONT_INITIALIZE_ARRAY_ELEMENTS; 1043 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE : DONT_INITIALIZE_ARRAY_ELEMENTS;
1037 Handle<JSArray> result_array = 1044 Handle<JSArray> result_array =
1038 isolate->factory()->NewJSArray(elements_kind, 1045 isolate->factory()->NewJSArray(elements_kind,
1039 result_len, 1046 result_len,
1040 result_len, 1047 result_len,
1041 mode); 1048 mode);
1042 if (result_len == 0) return *result_array; 1049 if (result_len == 0) return *result_array;
1043 1050
1044 int j = 0; 1051 int j = 0;
1045 Handle<FixedArrayBase> storage(result_array->elements()); 1052 Handle<FixedArrayBase> storage(result_array->elements(), isolate);
1046 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind); 1053 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
1047 for (int i = 0; i < n_arguments; i++) { 1054 for (int i = 0; i < n_arguments; i++) {
1048 Handle<JSArray> array = args.at<JSArray>(i); 1055 // TODO(ishell): It is crucial to keep |array| as a raw pointer to avoid
1056 // performance degradation. Revisit this later.
1057 JSArray* array = JSArray::cast(args[i]);
1049 int len = Smi::cast(array->length())->value(); 1058 int len = Smi::cast(array->length())->value();
1050 ElementsKind from_kind = array->GetElementsKind(); 1059 ElementsKind from_kind = array->GetElementsKind();
1051 if (len > 0) { 1060 if (len > 0) {
1052 accessor->CopyElements(array, 0, from_kind, storage, j, len); 1061 accessor->CopyElements(array, 0, from_kind, storage, j, len);
1053 j += len; 1062 j += len;
1054 } 1063 }
1055 } 1064 }
1056 1065
1057 ASSERT(j == result_len); 1066 ASSERT(j == result_len);
1058 1067
(...skipping 660 matching lines...) Expand 10 before | Expand all | Expand 10 after
1719 } 1728 }
1720 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) 1729 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1721 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) 1730 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1722 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) 1731 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H)
1723 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) 1732 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1724 #undef DEFINE_BUILTIN_ACCESSOR_C 1733 #undef DEFINE_BUILTIN_ACCESSOR_C
1725 #undef DEFINE_BUILTIN_ACCESSOR_A 1734 #undef DEFINE_BUILTIN_ACCESSOR_A
1726 1735
1727 1736
1728 } } // namespace v8::internal 1737 } } // namespace v8::internal
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