| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 private: | 530 private: |
| 531 void ScavengePointer(Object** p) { | 531 void ScavengePointer(Object** p) { |
| 532 Object* object = *p; | 532 Object* object = *p; |
| 533 if (!Heap::InNewSpace(object)) return; | 533 if (!Heap::InNewSpace(object)) return; |
| 534 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), | 534 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), |
| 535 reinterpret_cast<HeapObject*>(object)); | 535 reinterpret_cast<HeapObject*>(object)); |
| 536 } | 536 } |
| 537 }; | 537 }; |
| 538 | 538 |
| 539 | 539 |
| 540 // A queue of pointers and maps of to-be-promoted objects during a |
| 541 // scavenge collection. |
| 542 class PromotionQueue { |
| 543 public: |
| 544 void Initialize(Address start_address) { |
| 545 front_ = rear_ = reinterpret_cast<HeapObject**>(start_address); |
| 546 } |
| 547 |
| 548 bool is_empty() { return front_ <= rear_; } |
| 549 |
| 550 void insert(HeapObject* object, Map* map) { |
| 551 *(--rear_) = object; |
| 552 *(--rear_) = map; |
| 553 // Assert no overflow into live objects. |
| 554 ASSERT(rear_ >= Heap::new_space()->top()); |
| 555 } |
| 556 |
| 557 void remove(HeapObject** object, Map** map) { |
| 558 *object = *(--front_); |
| 559 *map = Map::cast(*(--front_)); |
| 560 // Assert no underflow. |
| 561 ASSERT(front_ >= rear_); |
| 562 } |
| 563 |
| 564 private: |
| 565 // The front of the queue is higher in memory than the rear. |
| 566 HeapObject** front_; |
| 567 HeapObject** rear_; |
| 568 }; |
| 569 |
| 570 |
| 540 // Shared state read by the scavenge collector and set by ScavengeObject. | 571 // Shared state read by the scavenge collector and set by ScavengeObject. |
| 541 static Address promoted_rear = NULL; | 572 static PromotionQueue promotion_queue; |
| 542 | 573 |
| 543 | 574 |
| 544 #ifdef DEBUG | 575 #ifdef DEBUG |
| 545 // Visitor class to verify pointers in code or data space do not point into | 576 // Visitor class to verify pointers in code or data space do not point into |
| 546 // new space. | 577 // new space. |
| 547 class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor { | 578 class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor { |
| 548 public: | 579 public: |
| 549 void VisitPointers(Object** start, Object**end) { | 580 void VisitPointers(Object** start, Object**end) { |
| 550 for (Object** current = start; current < end; current++) { | 581 for (Object** current = start; current < end; current++) { |
| 551 if ((*current)->IsHeapObject()) { | 582 if ((*current)->IsHeapObject()) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 617 // We treat the top of the to space as a queue of addresses of | 648 // We treat the top of the to space as a queue of addresses of |
| 618 // promoted objects. The addresses of newly promoted and unswept | 649 // promoted objects. The addresses of newly promoted and unswept |
| 619 // objects lie between a 'front' mark and a 'rear' mark that is | 650 // objects lie between a 'front' mark and a 'rear' mark that is |
| 620 // updated as a side effect of promoting an object. | 651 // updated as a side effect of promoting an object. |
| 621 // | 652 // |
| 622 // There is guaranteed to be enough room at the top of the to space | 653 // There is guaranteed to be enough room at the top of the to space |
| 623 // for the addresses of promoted objects: every object promoted | 654 // for the addresses of promoted objects: every object promoted |
| 624 // frees up its size in bytes from the top of the new space, and | 655 // frees up its size in bytes from the top of the new space, and |
| 625 // objects are at least one pointer in size. | 656 // objects are at least one pointer in size. |
| 626 Address new_space_front = new_space_.ToSpaceLow(); | 657 Address new_space_front = new_space_.ToSpaceLow(); |
| 627 Address promoted_front = new_space_.ToSpaceHigh(); | 658 promotion_queue.Initialize(new_space_.ToSpaceHigh()); |
| 628 promoted_rear = new_space_.ToSpaceHigh(); | |
| 629 | 659 |
| 630 ScavengeVisitor scavenge_visitor; | 660 ScavengeVisitor scavenge_visitor; |
| 631 // Copy roots. | 661 // Copy roots. |
| 632 IterateRoots(&scavenge_visitor); | 662 IterateRoots(&scavenge_visitor); |
| 633 | 663 |
| 634 // Copy objects reachable from weak pointers. | 664 // Copy objects reachable from weak pointers. |
| 635 GlobalHandles::IterateWeakRoots(&scavenge_visitor); | 665 GlobalHandles::IterateWeakRoots(&scavenge_visitor); |
| 636 | 666 |
| 637 // Copy objects reachable from the old generation. By definition, | 667 // Copy objects reachable from the old generation. By definition, |
| 638 // there are no intergenerational pointers in code or data spaces. | 668 // there are no intergenerational pointers in code or data spaces. |
| 639 IterateRSet(old_pointer_space_, &ScavengePointer); | 669 IterateRSet(old_pointer_space_, &ScavengePointer); |
| 640 IterateRSet(map_space_, &ScavengePointer); | 670 IterateRSet(map_space_, &ScavengePointer); |
| 641 lo_space_->IterateRSet(&ScavengePointer); | 671 lo_space_->IterateRSet(&ScavengePointer); |
| 642 | 672 |
| 643 do { | 673 do { |
| 644 ASSERT(new_space_front <= new_space_.top()); | 674 ASSERT(new_space_front <= new_space_.top()); |
| 645 ASSERT(promoted_front >= promoted_rear); | |
| 646 | 675 |
| 647 // The addresses new_space_front and new_space_.top() define a | 676 // The addresses new_space_front and new_space_.top() define a |
| 648 // queue of unprocessed copied objects. Process them until the | 677 // queue of unprocessed copied objects. Process them until the |
| 649 // queue is empty. | 678 // queue is empty. |
| 650 while (new_space_front < new_space_.top()) { | 679 while (new_space_front < new_space_.top()) { |
| 651 HeapObject* object = HeapObject::FromAddress(new_space_front); | 680 HeapObject* object = HeapObject::FromAddress(new_space_front); |
| 652 object->Iterate(&scavenge_visitor); | 681 object->Iterate(&scavenge_visitor); |
| 653 new_space_front += object->Size(); | 682 new_space_front += object->Size(); |
| 654 } | 683 } |
| 655 | 684 |
| 656 // The addresses promoted_front and promoted_rear define a queue | 685 // Promote and process all the to-be-promoted objects. |
| 657 // of unprocessed addresses of promoted objects. Process them | 686 while (!promotion_queue.is_empty()) { |
| 658 // until the queue is empty. | 687 HeapObject* source; |
| 659 while (promoted_front > promoted_rear) { | 688 Map* map; |
| 660 promoted_front -= kPointerSize; | 689 promotion_queue.remove(&source, &map); |
| 661 HeapObject* object = | 690 // Copy the from-space object to its new location (given by the |
| 662 HeapObject::cast(Memory::Object_at(promoted_front)); | 691 // forwarding address) and fix its map. |
| 663 object->Iterate(&scavenge_visitor); | 692 HeapObject* target = source->map_word().ToForwardingAddress(); |
| 664 UpdateRSet(object); | 693 CopyBlock(reinterpret_cast<Object**>(target->address()), |
| 694 reinterpret_cast<Object**>(source->address()), |
| 695 source->SizeFromMap(map)); |
| 696 target->set_map(map); |
| 697 |
| 698 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
| 699 // Update NewSpace stats if necessary. |
| 700 RecordCopiedObject(target); |
| 701 #endif |
| 702 // Visit the newly copied object for pointers to new space. |
| 703 target->Iterate(&scavenge_visitor); |
| 704 UpdateRSet(target); |
| 665 } | 705 } |
| 666 | 706 |
| 667 // Take another spin if there are now unswept objects in new space | 707 // Take another spin if there are now unswept objects in new space |
| 668 // (there are currently no more unswept promoted objects). | 708 // (there are currently no more unswept promoted objects). |
| 669 } while (new_space_front < new_space_.top()); | 709 } while (new_space_front < new_space_.top()); |
| 670 | 710 |
| 671 // Set age mark. | 711 // Set age mark. |
| 672 new_space_.set_age_mark(new_space_.top()); | 712 new_space_.set_age_mark(new_space_.top()); |
| 673 | 713 |
| 674 LOG(ResourceEvent("scavenge", "end")); | 714 LOG(ResourceEvent("scavenge", "end")); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 811 HeapObject* target, | 851 HeapObject* target, |
| 812 int size) { | 852 int size) { |
| 813 // Copy the content of source to target. | 853 // Copy the content of source to target. |
| 814 CopyBlock(reinterpret_cast<Object**>(target->address()), | 854 CopyBlock(reinterpret_cast<Object**>(target->address()), |
| 815 reinterpret_cast<Object**>(source->address()), | 855 reinterpret_cast<Object**>(source->address()), |
| 816 size); | 856 size); |
| 817 | 857 |
| 818 // Set the forwarding address. | 858 // Set the forwarding address. |
| 819 source->set_map_word(MapWord::FromForwardingAddress(target)); | 859 source->set_map_word(MapWord::FromForwardingAddress(target)); |
| 820 | 860 |
| 861 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
| 821 // Update NewSpace stats if necessary. | 862 // Update NewSpace stats if necessary. |
| 822 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) | |
| 823 RecordCopiedObject(target); | 863 RecordCopiedObject(target); |
| 824 #endif | 864 #endif |
| 825 | 865 |
| 826 return target; | 866 return target; |
| 827 } | 867 } |
| 828 | 868 |
| 829 | 869 |
| 830 // Inlined function. | |
| 831 void Heap::ScavengeObject(HeapObject** p, HeapObject* object) { | |
| 832 ASSERT(InFromSpace(object)); | |
| 833 | |
| 834 // We use the first word (where the map pointer usually is) of a heap | |
| 835 // object to record the forwarding pointer. A forwarding pointer can | |
| 836 // point to an old space, the code space, or the to space of the new | |
| 837 // generation. | |
| 838 MapWord first_word = object->map_word(); | |
| 839 | |
| 840 // If the first word is a forwarding address, the object has already been | |
| 841 // copied. | |
| 842 if (first_word.IsForwardingAddress()) { | |
| 843 *p = first_word.ToForwardingAddress(); | |
| 844 return; | |
| 845 } | |
| 846 | |
| 847 // Call the slow part of scavenge object. | |
| 848 return ScavengeObjectSlow(p, object); | |
| 849 } | |
| 850 | |
| 851 | |
| 852 static inline bool IsShortcutCandidate(HeapObject* object, Map* map) { | 870 static inline bool IsShortcutCandidate(HeapObject* object, Map* map) { |
| 853 STATIC_ASSERT(kNotStringTag != 0 && kSymbolTag != 0); | 871 STATIC_ASSERT(kNotStringTag != 0 && kSymbolTag != 0); |
| 854 ASSERT(object->map() == map); | 872 ASSERT(object->map() == map); |
| 855 InstanceType type = map->instance_type(); | 873 InstanceType type = map->instance_type(); |
| 856 if ((type & kShortcutTypeMask) != kShortcutTypeTag) return false; | 874 if ((type & kShortcutTypeMask) != kShortcutTypeTag) return false; |
| 857 ASSERT(object->IsString() && !object->IsSymbol()); | 875 ASSERT(object->IsString() && !object->IsSymbol()); |
| 858 return ConsString::cast(object)->unchecked_second() == Heap::empty_string(); | 876 return ConsString::cast(object)->unchecked_second() == Heap::empty_string(); |
| 859 } | 877 } |
| 860 | 878 |
| 861 | 879 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 872 // active semispace of the young generation and not already copied. | 890 // active semispace of the young generation and not already copied. |
| 873 if (!InNewSpace(object)) return; | 891 if (!InNewSpace(object)) return; |
| 874 first_word = object->map_word(); | 892 first_word = object->map_word(); |
| 875 if (first_word.IsForwardingAddress()) { | 893 if (first_word.IsForwardingAddress()) { |
| 876 *p = first_word.ToForwardingAddress(); | 894 *p = first_word.ToForwardingAddress(); |
| 877 return; | 895 return; |
| 878 } | 896 } |
| 879 } | 897 } |
| 880 | 898 |
| 881 int object_size = object->SizeFromMap(first_word.ToMap()); | 899 int object_size = object->SizeFromMap(first_word.ToMap()); |
| 900 // We rely on live objects in new space to be at least two pointers, |
| 901 // so we can store the from-space address and map pointer of promoted |
| 902 // objects in the to space. |
| 903 ASSERT(object_size >= 2 * kPointerSize); |
| 904 |
| 882 // If the object should be promoted, we try to copy it to old space. | 905 // If the object should be promoted, we try to copy it to old space. |
| 883 if (ShouldBePromoted(object->address(), object_size)) { | 906 if (ShouldBePromoted(object->address(), object_size)) { |
| 884 OldSpace* target_space = Heap::TargetSpace(object); | 907 OldSpace* target_space = Heap::TargetSpace(object); |
| 885 ASSERT(target_space == Heap::old_pointer_space_ || | 908 ASSERT(target_space == Heap::old_pointer_space_ || |
| 886 target_space == Heap::old_data_space_); | 909 target_space == Heap::old_data_space_); |
| 887 Object* result = target_space->AllocateRaw(object_size); | 910 Object* result = target_space->AllocateRaw(object_size); |
| 888 if (!result->IsFailure()) { | 911 if (!result->IsFailure()) { |
| 889 *p = MigrateObject(object, HeapObject::cast(result), object_size); | 912 HeapObject* target = HeapObject::cast(result); |
| 890 if (target_space == Heap::old_pointer_space_) { | 913 if (target_space == Heap::old_pointer_space_) { |
| 891 // Record the object's address at the top of the to space, to allow | 914 // Save the from-space object pointer and its map pointer at the |
| 892 // it to be swept by the scavenger. | 915 // top of the to space to be swept and copied later. Write the |
| 893 promoted_rear -= kPointerSize; | 916 // forwarding address over the map word of the from-space |
| 894 Memory::Object_at(promoted_rear) = *p; | 917 // object. |
| 918 promotion_queue.insert(object, first_word.ToMap()); |
| 919 object->set_map_word(MapWord::FromForwardingAddress(target)); |
| 920 |
| 921 // Give the space allocated for the result a proper map by |
| 922 // treating it as a free list node (not linked into the free |
| 923 // list). |
| 924 FreeListNode* node = FreeListNode::FromAddress(target->address()); |
| 925 node->set_size(object_size); |
| 926 |
| 927 *p = target; |
| 895 } else { | 928 } else { |
| 929 // Objects promoted to the data space can be copied immediately |
| 930 // and not revisited---we will never sweep that space for |
| 931 // pointers and the copied objects do not contain pointers to |
| 932 // new space objects. |
| 933 *p = MigrateObject(object, target, object_size); |
| 896 #ifdef DEBUG | 934 #ifdef DEBUG |
| 897 // Objects promoted to the data space should not have pointers to | |
| 898 // new space. | |
| 899 VerifyNonPointerSpacePointersVisitor v; | 935 VerifyNonPointerSpacePointersVisitor v; |
| 900 (*p)->Iterate(&v); | 936 (*p)->Iterate(&v); |
| 901 #endif | 937 #endif |
| 902 } | 938 } |
| 903 return; | 939 return; |
| 904 } | 940 } |
| 905 } | 941 } |
| 906 | 942 |
| 907 // The object should remain in new space or the old space allocation failed. | 943 // The object should remain in new space or the old space allocation failed. |
| 908 Object* result = new_space_.AllocateRaw(object_size); | 944 Object* result = new_space_.AllocateRaw(object_size); |
| (...skipping 2486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3395 #ifdef DEBUG | 3431 #ifdef DEBUG |
| 3396 bool Heap::GarbageCollectionGreedyCheck() { | 3432 bool Heap::GarbageCollectionGreedyCheck() { |
| 3397 ASSERT(FLAG_gc_greedy); | 3433 ASSERT(FLAG_gc_greedy); |
| 3398 if (Bootstrapper::IsActive()) return true; | 3434 if (Bootstrapper::IsActive()) return true; |
| 3399 if (disallow_allocation_failure()) return true; | 3435 if (disallow_allocation_failure()) return true; |
| 3400 return CollectGarbage(0, NEW_SPACE); | 3436 return CollectGarbage(0, NEW_SPACE); |
| 3401 } | 3437 } |
| 3402 #endif | 3438 #endif |
| 3403 | 3439 |
| 3404 } } // namespace v8::internal | 3440 } } // namespace v8::internal |
| OLD | NEW |