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/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/base/atomicops.h" | 7 #include "src/base/atomicops.h" |
8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
9 #include "src/compilation-cache.h" | 9 #include "src/compilation-cache.h" |
10 #include "src/cpu-profiler.h" | 10 #include "src/cpu-profiler.h" |
(...skipping 2562 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2573 MarkBit map_mark) { | 2573 MarkBit map_mark) { |
2574 Object* potential_parent = map->GetBackPointer(); | 2574 Object* potential_parent = map->GetBackPointer(); |
2575 if (!potential_parent->IsMap()) return; | 2575 if (!potential_parent->IsMap()) return; |
2576 Map* parent = Map::cast(potential_parent); | 2576 Map* parent = Map::cast(potential_parent); |
2577 | 2577 |
2578 // Follow back pointer, check whether we are dealing with a map transition | 2578 // Follow back pointer, check whether we are dealing with a map transition |
2579 // from a live map to a dead path and in case clear transitions of parent. | 2579 // from a live map to a dead path and in case clear transitions of parent. |
2580 bool current_is_alive = map_mark.Get(); | 2580 bool current_is_alive = map_mark.Get(); |
2581 bool parent_is_alive = Marking::MarkBitFrom(parent).Get(); | 2581 bool parent_is_alive = Marking::MarkBitFrom(parent).Get(); |
2582 if (!current_is_alive && parent_is_alive) { | 2582 if (!current_is_alive && parent_is_alive) { |
2583 parent->ClearNonLiveTransitions(heap()); | 2583 ClearMapTransitions(parent); |
2584 } | 2584 } |
2585 } | 2585 } |
2586 | 2586 |
2587 | 2587 |
| 2588 // Clear a possible back pointer in case the transition leads to a dead map. |
| 2589 // Return true in case a back pointer has been cleared and false otherwise. |
| 2590 bool MarkCompactCollector::ClearMapBackPointer(Map* target) { |
| 2591 if (Marking::MarkBitFrom(target).Get()) return false; |
| 2592 target->SetBackPointer(heap_->undefined_value(), SKIP_WRITE_BARRIER); |
| 2593 return true; |
| 2594 } |
| 2595 |
| 2596 |
| 2597 void MarkCompactCollector::ClearMapTransitions(Map* map) { |
| 2598 // If there are no transitions to be cleared, return. |
| 2599 // TODO(verwaest) Should be an assert, otherwise back pointers are not |
| 2600 // properly cleared. |
| 2601 if (!map->HasTransitionArray()) return; |
| 2602 |
| 2603 TransitionArray* t = map->transitions(); |
| 2604 |
| 2605 int transition_index = 0; |
| 2606 |
| 2607 DescriptorArray* descriptors = map->instance_descriptors(); |
| 2608 bool descriptors_owner_died = false; |
| 2609 |
| 2610 // Compact all live descriptors to the left. |
| 2611 for (int i = 0; i < t->number_of_transitions(); ++i) { |
| 2612 Map* target = t->GetTarget(i); |
| 2613 if (ClearMapBackPointer(target)) { |
| 2614 if (target->instance_descriptors() == descriptors) { |
| 2615 descriptors_owner_died = true; |
| 2616 } |
| 2617 } else { |
| 2618 if (i != transition_index) { |
| 2619 Name* key = t->GetKey(i); |
| 2620 t->SetKey(transition_index, key); |
| 2621 Object** key_slot = t->GetKeySlot(transition_index); |
| 2622 RecordSlot(key_slot, key_slot, key); |
| 2623 // Target slots do not need to be recorded since maps are not compacted. |
| 2624 t->SetTarget(transition_index, t->GetTarget(i)); |
| 2625 } |
| 2626 transition_index++; |
| 2627 } |
| 2628 } |
| 2629 |
| 2630 // If there are no transitions to be cleared, return. |
| 2631 // TODO(verwaest) Should be an assert, otherwise back pointers are not |
| 2632 // properly cleared. |
| 2633 if (transition_index == t->number_of_transitions()) return; |
| 2634 |
| 2635 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); |
| 2636 |
| 2637 if (descriptors_owner_died) { |
| 2638 if (number_of_own_descriptors > 0) { |
| 2639 TrimDescriptorArray(map, descriptors, number_of_own_descriptors); |
| 2640 DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors); |
| 2641 map->set_owns_descriptors(true); |
| 2642 } else { |
| 2643 DCHECK(descriptors == heap_->empty_descriptor_array()); |
| 2644 } |
| 2645 } |
| 2646 |
| 2647 // Note that we never eliminate a transition array, though we might right-trim |
| 2648 // such that number_of_transitions() == 0. If this assumption changes, |
| 2649 // TransitionArray::CopyInsert() will need to deal with the case that a |
| 2650 // transition array disappeared during GC. |
| 2651 int trim = t->number_of_transitions() - transition_index; |
| 2652 if (trim > 0) { |
| 2653 heap_->RightTrimFixedArray<Heap::FROM_GC>( |
| 2654 t, t->IsSimpleTransition() ? trim |
| 2655 : trim * TransitionArray::kTransitionSize); |
| 2656 } |
| 2657 DCHECK(map->HasTransitionArray()); |
| 2658 } |
| 2659 |
| 2660 |
| 2661 void MarkCompactCollector::TrimDescriptorArray(Map* map, |
| 2662 DescriptorArray* descriptors, |
| 2663 int number_of_own_descriptors) { |
| 2664 int number_of_descriptors = descriptors->number_of_descriptors_storage(); |
| 2665 int to_trim = number_of_descriptors - number_of_own_descriptors; |
| 2666 if (to_trim == 0) return; |
| 2667 |
| 2668 heap_->RightTrimFixedArray<Heap::FROM_GC>( |
| 2669 descriptors, to_trim * DescriptorArray::kDescriptorSize); |
| 2670 descriptors->SetNumberOfDescriptors(number_of_own_descriptors); |
| 2671 |
| 2672 if (descriptors->HasEnumCache()) TrimEnumCache(map, descriptors); |
| 2673 descriptors->Sort(); |
| 2674 } |
| 2675 |
| 2676 |
| 2677 void MarkCompactCollector::TrimEnumCache(Map* map, |
| 2678 DescriptorArray* descriptors) { |
| 2679 int live_enum = map->EnumLength(); |
| 2680 if (live_enum == kInvalidEnumCacheSentinel) { |
| 2681 live_enum = map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM); |
| 2682 } |
| 2683 if (live_enum == 0) return descriptors->ClearEnumCache(); |
| 2684 |
| 2685 FixedArray* enum_cache = descriptors->GetEnumCache(); |
| 2686 |
| 2687 int to_trim = enum_cache->length() - live_enum; |
| 2688 if (to_trim <= 0) return; |
| 2689 heap_->RightTrimFixedArray<Heap::FROM_GC>(descriptors->GetEnumCache(), |
| 2690 to_trim); |
| 2691 |
| 2692 if (!descriptors->HasEnumIndicesCache()) return; |
| 2693 FixedArray* enum_indices_cache = descriptors->GetEnumIndicesCache(); |
| 2694 heap_->RightTrimFixedArray<Heap::FROM_GC>(enum_indices_cache, to_trim); |
| 2695 } |
| 2696 |
| 2697 |
2588 void MarkCompactCollector::ClearDependentICList(Object* head) { | 2698 void MarkCompactCollector::ClearDependentICList(Object* head) { |
2589 Object* current = head; | 2699 Object* current = head; |
2590 Object* undefined = heap()->undefined_value(); | 2700 Object* undefined = heap()->undefined_value(); |
2591 while (current != undefined) { | 2701 while (current != undefined) { |
2592 Code* code = Code::cast(current); | 2702 Code* code = Code::cast(current); |
2593 if (IsMarked(code)) { | 2703 if (IsMarked(code)) { |
2594 DCHECK(code->is_weak_stub()); | 2704 DCHECK(code->is_weak_stub()); |
2595 IC::InvalidateMaps(code); | 2705 IC::InvalidateMaps(code); |
2596 } | 2706 } |
2597 current = code->next_code_link(); | 2707 current = code->next_code_link(); |
(...skipping 2084 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4682 SlotsBuffer* buffer = *buffer_address; | 4792 SlotsBuffer* buffer = *buffer_address; |
4683 while (buffer != NULL) { | 4793 while (buffer != NULL) { |
4684 SlotsBuffer* next_buffer = buffer->next(); | 4794 SlotsBuffer* next_buffer = buffer->next(); |
4685 DeallocateBuffer(buffer); | 4795 DeallocateBuffer(buffer); |
4686 buffer = next_buffer; | 4796 buffer = next_buffer; |
4687 } | 4797 } |
4688 *buffer_address = NULL; | 4798 *buffer_address = NULL; |
4689 } | 4799 } |
4690 } | 4800 } |
4691 } // namespace v8::internal | 4801 } // namespace v8::internal |
OLD | NEW |