OLD | NEW |
| (Empty) |
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/heap/array-buffer-tracker-inl.h" | |
6 #include "src/heap/array-buffer-tracker.h" | |
7 #include "test/cctest/cctest.h" | |
8 #include "test/cctest/heap/heap-utils.h" | |
9 | |
10 namespace { | |
11 | |
12 typedef i::LocalArrayBufferTracker LocalTracker; | |
13 | |
14 void VerifyTrackedInNewSpace(i::JSArrayBuffer* buf) { | |
15 CHECK(i::Page::FromAddress(buf->address())->InNewSpace()); | |
16 CHECK(i::Page::FromAddress(buf->address()) | |
17 ->local_tracker<i::Page::kCreateIfNotPresent>() | |
18 ->IsTracked(buf)); | |
19 } | |
20 | |
21 void VerifyTrackedInOldSpace(i::JSArrayBuffer* buf) { | |
22 CHECK(!i::Page::FromAddress(buf->address())->InNewSpace()); | |
23 CHECK(i::Page::FromAddress(buf->address()) | |
24 ->local_tracker<i::Page::kCreateIfNotPresent>() | |
25 ->IsTracked(buf)); | |
26 } | |
27 | |
28 void VerifyUntracked(i::JSArrayBuffer* buf) { | |
29 CHECK(!i::Page::FromAddress(buf->address()) | |
30 ->local_tracker<i::Page::kCreateIfNotPresent>() | |
31 ->IsTracked(buf)); | |
32 } | |
33 | |
34 } // namespace | |
35 | |
36 namespace v8 { | |
37 namespace internal { | |
38 | |
39 // The following tests make sure that JSArrayBuffer tracking works expected when | |
40 // moving the objects through various spaces during GC phases. | |
41 | |
42 TEST(ArrayBuffer_OnlyMC) { | |
43 CcTest::InitializeVM(); | |
44 LocalContext env; | |
45 v8::Isolate* isolate = env->GetIsolate(); | |
46 Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); | |
47 | |
48 JSArrayBuffer* raw_ab = nullptr; | |
49 { | |
50 v8::HandleScope handle_scope(isolate); | |
51 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100); | |
52 Handle<JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab); | |
53 VerifyTrackedInNewSpace(*buf); | |
54 heap::GcAndSweep(heap, OLD_SPACE); | |
55 VerifyTrackedInNewSpace(*buf); | |
56 heap::GcAndSweep(heap, OLD_SPACE); | |
57 VerifyTrackedInOldSpace(*buf); | |
58 raw_ab = *buf; | |
59 // Prohibit page from being released. | |
60 Page::FromAddress(buf->address())->MarkNeverEvacuate(); | |
61 } | |
62 // 2 GCs are needed because we promote to old space as live, meaning that | |
63 // we will survive one GC. | |
64 heap::GcAndSweep(heap, OLD_SPACE); | |
65 heap::GcAndSweep(heap, OLD_SPACE); | |
66 VerifyUntracked(raw_ab); | |
67 } | |
68 | |
69 TEST(ArrayBuffer_OnlyScavenge) { | |
70 CcTest::InitializeVM(); | |
71 LocalContext env; | |
72 v8::Isolate* isolate = env->GetIsolate(); | |
73 Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); | |
74 | |
75 JSArrayBuffer* raw_ab = nullptr; | |
76 { | |
77 v8::HandleScope handle_scope(isolate); | |
78 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100); | |
79 Handle<JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab); | |
80 VerifyTrackedInNewSpace(*buf); | |
81 heap::GcAndSweep(heap, NEW_SPACE); | |
82 VerifyTrackedInNewSpace(*buf); | |
83 heap::GcAndSweep(heap, NEW_SPACE); | |
84 VerifyTrackedInOldSpace(*buf); | |
85 heap::GcAndSweep(heap, NEW_SPACE); | |
86 VerifyTrackedInOldSpace(*buf); | |
87 raw_ab = *buf; | |
88 // Prohibit page from being released. | |
89 Page::FromAddress(buf->address())->MarkNeverEvacuate(); | |
90 } | |
91 // 2 GCs are needed because we promote to old space as live, meaning that | |
92 // we will survive one GC. | |
93 heap::GcAndSweep(heap, OLD_SPACE); | |
94 heap::GcAndSweep(heap, OLD_SPACE); | |
95 VerifyUntracked(raw_ab); | |
96 } | |
97 | |
98 TEST(ArrayBuffer_ScavengeAndMC) { | |
99 CcTest::InitializeVM(); | |
100 LocalContext env; | |
101 v8::Isolate* isolate = env->GetIsolate(); | |
102 Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); | |
103 | |
104 JSArrayBuffer* raw_ab = nullptr; | |
105 { | |
106 v8::HandleScope handle_scope(isolate); | |
107 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100); | |
108 Handle<JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab); | |
109 VerifyTrackedInNewSpace(*buf); | |
110 heap::GcAndSweep(heap, NEW_SPACE); | |
111 VerifyTrackedInNewSpace(*buf); | |
112 heap::GcAndSweep(heap, NEW_SPACE); | |
113 VerifyTrackedInOldSpace(*buf); | |
114 heap::GcAndSweep(heap, OLD_SPACE); | |
115 VerifyTrackedInOldSpace(*buf); | |
116 heap::GcAndSweep(heap, NEW_SPACE); | |
117 VerifyTrackedInOldSpace(*buf); | |
118 raw_ab = *buf; | |
119 // Prohibit page from being released. | |
120 Page::FromAddress(buf->address())->MarkNeverEvacuate(); | |
121 } | |
122 // 2 GCs are needed because we promote to old space as live, meaning that | |
123 // we will survive one GC. | |
124 heap::GcAndSweep(heap, OLD_SPACE); | |
125 heap::GcAndSweep(heap, OLD_SPACE); | |
126 VerifyUntracked(raw_ab); | |
127 } | |
128 | |
129 TEST(ArrayBuffer_Compaction) { | |
130 FLAG_manual_evacuation_candidates_selection = true; | |
131 CcTest::InitializeVM(); | |
132 LocalContext env; | |
133 v8::Isolate* isolate = env->GetIsolate(); | |
134 Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); | |
135 heap::AbandonCurrentlyFreeMemory(heap->old_space()); | |
136 | |
137 v8::HandleScope handle_scope(isolate); | |
138 Local<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(isolate, 100); | |
139 Handle<JSArrayBuffer> buf1 = v8::Utils::OpenHandle(*ab1); | |
140 VerifyTrackedInNewSpace(*buf1); | |
141 heap::GcAndSweep(heap, NEW_SPACE); | |
142 heap::GcAndSweep(heap, NEW_SPACE); | |
143 | |
144 Page* page_before_gc = Page::FromAddress(buf1->address()); | |
145 page_before_gc->SetFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING); | |
146 VerifyTrackedInOldSpace(*buf1); | |
147 | |
148 heap->CollectAllGarbage(); | |
149 | |
150 Page* page_after_gc = Page::FromAddress(buf1->address()); | |
151 VerifyTrackedInOldSpace(*buf1); | |
152 | |
153 CHECK_NE(page_before_gc, page_after_gc); | |
154 } | |
155 | |
156 TEST(ArrayBuffer_UnregisterDuringSweep) { | |
157 // Regular pages in old space (without compaction) are processed concurrently | |
158 // in the sweeper. If we happen to unregister a buffer (either explicitly, or | |
159 // implicitly through e.g. |Externalize|) we need to sync with the sweeper | |
160 // task. | |
161 // | |
162 // Note: This test will will only fail on TSAN configurations. | |
163 | |
164 // Disable verify-heap since it forces sweeping to be completed in the | |
165 // epilogue of the GC. | |
166 #ifdef VERIFY_HEAP | |
167 i::FLAG_verify_heap = false; | |
168 #endif // VERIFY_HEAP | |
169 | |
170 CcTest::InitializeVM(); | |
171 LocalContext env; | |
172 v8::Isolate* isolate = env->GetIsolate(); | |
173 Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); | |
174 { | |
175 v8::HandleScope handle_scope(isolate); | |
176 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100); | |
177 Handle<JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab); | |
178 | |
179 { | |
180 v8::HandleScope handle_scope(isolate); | |
181 // Allocate another buffer on the same page to force processing a | |
182 // non-empty set of buffers in the last GC. | |
183 Local<v8::ArrayBuffer> ab2 = v8::ArrayBuffer::New(isolate, 100); | |
184 Handle<JSArrayBuffer> buf2 = v8::Utils::OpenHandle(*ab2); | |
185 VerifyTrackedInNewSpace(*buf); | |
186 VerifyTrackedInNewSpace(*buf2); | |
187 heap::GcAndSweep(heap, NEW_SPACE); | |
188 VerifyTrackedInNewSpace(*buf); | |
189 VerifyTrackedInNewSpace(*buf2); | |
190 heap::GcAndSweep(heap, NEW_SPACE); | |
191 VerifyTrackedInOldSpace(*buf); | |
192 VerifyTrackedInOldSpace(*buf2); | |
193 } | |
194 | |
195 heap->CollectGarbage(OLD_SPACE); | |
196 // |Externalize| will cause the buffer to be |Unregister|ed. Without | |
197 // barriers and proper synchronization this will trigger a data race on | |
198 // TSAN. | |
199 v8::ArrayBuffer::Contents contents = ab->Externalize(); | |
200 heap->isolate()->array_buffer_allocator()->Free(contents.Data(), | |
201 contents.ByteLength()); | |
202 } | |
203 } | |
204 | |
205 } // namespace internal | |
206 } // namespace v8 | |
OLD | NEW |