1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/execution/isolate.h"
6 #include "src/heap/factory.h"
7 #include "src/heap/spaces-inl.h"
8 #include "src/objects/objects-inl.h"
9 #include "test/cctest/cctest.h"
10 #include "test/cctest/heap/heap-tester.h"
11 #include "test/cctest/heap/heap-utils.h"
12
13 namespace v8 {
14 namespace internal {
15 namespace heap {
16
17 // Tests don't work when --optimize-for-size is set.
18 #ifndef V8_LITE_MODE
19
20 namespace {
21
NewIsolateForPagePromotion(int min_semi_space_size=8,int max_semi_space_size=8)22 v8::Isolate* NewIsolateForPagePromotion(int min_semi_space_size = 8,
23 int max_semi_space_size = 8) {
24 // Parallel evacuation messes with fragmentation in a way that objects that
25 // should be copied in semi space are promoted to old space because of
26 // fragmentation.
27 FLAG_parallel_compaction = false;
28 FLAG_page_promotion = true;
29 FLAG_page_promotion_threshold = 0;
30 // Parallel scavenge introduces too much fragmentation.
31 FLAG_parallel_scavenge = false;
32 FLAG_min_semi_space_size = min_semi_space_size;
33 // We cannot optimize for size as we require a new space with more than one
34 // page.
35 FLAG_optimize_for_size = false;
36 // Set max_semi_space_size because it could've been initialized by an
37 // implication of optimize_for_size.
38 FLAG_max_semi_space_size = max_semi_space_size;
39 v8::Isolate::CreateParams create_params;
40 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
41 v8::Isolate* isolate = v8::Isolate::New(create_params);
42 return isolate;
43 }
44
FindLastPageInNewSpace(const std::vector<Handle<FixedArray>> & handles)45 Page* FindLastPageInNewSpace(const std::vector<Handle<FixedArray>>& handles) {
46 for (auto rit = handles.rbegin(); rit != handles.rend(); ++rit) {
47 // One deref gets the Handle, the second deref gets the FixedArray.
48 Page* candidate = Page::FromHeapObject(**rit);
49 if (candidate->InNewSpace()) return candidate;
50 }
51 return nullptr;
52 }
53
54 } // namespace
55
UNINITIALIZED_TEST(PagePromotion_NewToOld)56 UNINITIALIZED_TEST(PagePromotion_NewToOld) {
57 if (i::FLAG_single_generation) return;
58 if (!i::FLAG_incremental_marking) return;
59 if (!i::FLAG_page_promotion) return;
60 ManualGCScope manual_gc_scope;
61
62 v8::Isolate* isolate = NewIsolateForPagePromotion();
63 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
64 {
65 v8::Isolate::Scope isolate_scope(isolate);
66 v8::HandleScope handle_scope(isolate);
67 v8::Context::New(isolate)->Enter();
68 Heap* heap = i_isolate->heap();
69
70 // Ensure that the new space is empty so that the page to be promoted
71 // does not contain the age mark.
72 heap->CollectGarbage(NEW_SPACE, i::GarbageCollectionReason::kTesting);
73 heap->CollectGarbage(NEW_SPACE, i::GarbageCollectionReason::kTesting);
74
75 std::vector<Handle<FixedArray>> handles;
76 heap::SimulateFullSpace(heap->new_space(), &handles);
77 heap->CollectGarbage(NEW_SPACE, i::GarbageCollectionReason::kTesting);
78 CHECK_GT(handles.size(), 0u);
79 Page* const to_be_promoted_page = FindLastPageInNewSpace(handles);
80 CHECK_NOT_NULL(to_be_promoted_page);
81 CHECK(!to_be_promoted_page->Contains(heap->new_space()->age_mark()));
82 // To perform a sanity check on live bytes we need to mark the heap.
83 heap::SimulateIncrementalMarking(heap, true);
84 // Sanity check that the page meets the requirements for promotion.
85 const int threshold_bytes = static_cast<int>(
86 FLAG_page_promotion_threshold *
87 MemoryChunkLayout::AllocatableMemoryInDataPage() / 100);
88 CHECK_GE(heap->incremental_marking()->marking_state()->live_bytes(
89 to_be_promoted_page),
90 threshold_bytes);
91
92 // Actual checks: The page is in new space first, but is moved to old space
93 // during a full GC.
94 CHECK(heap->new_space()->ContainsSlow(to_be_promoted_page->address()));
95 CHECK(!heap->old_space()->ContainsSlow(to_be_promoted_page->address()));
96 heap::GcAndSweep(heap, OLD_SPACE);
97 CHECK(!heap->new_space()->ContainsSlow(to_be_promoted_page->address()));
98 CHECK(heap->old_space()->ContainsSlow(to_be_promoted_page->address()));
99 }
100 isolate->Dispose();
101 }
102
UNINITIALIZED_TEST(PagePromotion_NewToNew)103 UNINITIALIZED_TEST(PagePromotion_NewToNew) {
104 if (!i::FLAG_page_promotion || FLAG_always_promote_young_mc) return;
105
106 v8::Isolate* isolate = NewIsolateForPagePromotion();
107 Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
108 {
109 v8::Isolate::Scope isolate_scope(isolate);
110 v8::HandleScope handle_scope(isolate);
111 v8::Context::New(isolate)->Enter();
112 Heap* heap = i_isolate->heap();
113
114 std::vector<Handle<FixedArray>> handles;
115 heap::SimulateFullSpace(heap->new_space(), &handles);
116 CHECK_GT(handles.size(), 0u);
117 // Last object in handles should definitely be on a page that does not
118 // contain the age mark, thus qualifying for moving.
119 Handle<FixedArray> last_object = handles.back();
120 Page* to_be_promoted_page = Page::FromHeapObject(*last_object);
121 CHECK(!to_be_promoted_page->Contains(heap->new_space()->age_mark()));
122 CHECK(to_be_promoted_page->Contains(last_object->address()));
123 CHECK(heap->new_space()->ToSpaceContainsSlow(last_object->address()));
124 heap::GcAndSweep(heap, OLD_SPACE);
125 CHECK(heap->new_space()->ToSpaceContainsSlow(last_object->address()));
126 CHECK(to_be_promoted_page->Contains(last_object->address()));
127 }
128 isolate->Dispose();
129 }
130
UNINITIALIZED_HEAP_TEST(Regress658718)131 UNINITIALIZED_HEAP_TEST(Regress658718) {
132 if (!i::FLAG_page_promotion || FLAG_always_promote_young_mc) return;
133
134 v8::Isolate* isolate = NewIsolateForPagePromotion(4, 8);
135 Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
136 {
137 v8::Isolate::Scope isolate_scope(isolate);
138 v8::HandleScope handle_scope(isolate);
139 v8::Context::New(isolate)->Enter();
140 Heap* heap = i_isolate->heap();
141 heap->delay_sweeper_tasks_for_testing_ = true;
142 GrowNewSpace(heap);
143 {
144 v8::HandleScope inner_handle_scope(isolate);
145 std::vector<Handle<FixedArray>> handles;
146 heap::SimulateFullSpace(heap->new_space(), &handles);
147 CHECK_GT(handles.size(), 0u);
148 // Last object in handles should definitely be on a page that does not
149 // contain the age mark, thus qualifying for moving.
150 Handle<FixedArray> last_object = handles.back();
151 Page* to_be_promoted_page = Page::FromHeapObject(*last_object);
152 CHECK(!to_be_promoted_page->Contains(heap->new_space()->age_mark()));
153 CHECK(to_be_promoted_page->Contains(last_object->address()));
154 CHECK(heap->new_space()->ToSpaceContainsSlow(last_object->address()));
155 heap->CollectGarbage(OLD_SPACE, i::GarbageCollectionReason::kTesting);
156 CHECK(heap->new_space()->ToSpaceContainsSlow(last_object->address()));
157 CHECK(to_be_promoted_page->Contains(last_object->address()));
158 }
159 heap->CollectGarbage(NEW_SPACE, i::GarbageCollectionReason::kTesting);
160 heap->new_space()->Shrink();
161 heap->memory_allocator()->unmapper()->EnsureUnmappingCompleted();
162 heap->delay_sweeper_tasks_for_testing_ = false;
163 heap->mark_compact_collector()->sweeper()->StartSweeperTasks();
164 heap->mark_compact_collector()->EnsureSweepingCompleted();
165 }
166 isolate->Dispose();
167 }
168
169 #endif // V8_LITE_MODE
170
171 } // namespace heap
172 } // namespace internal
173 } // namespace v8
174