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

Side by Side Diff: test/cctest/test-spaces.cc

Issue 1512553002: [cctest] Move most heap related tests to test/cctest/heap and clean wrt IWYU (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fixed compile time error due to missing header file Created 5 years 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
« no previous file with comments | « test/cctest/test-slots-buffer.cc ('k') | test/cctest/test-unboxed-doubles.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 // TODO(mythria): Remove this define after this flag is turned on globally
29 #define V8_IMMINENT_DEPRECATION_WARNINGS
30
31 #include <stdlib.h>
32
33 #include "src/base/platform/platform.h"
34 #include "src/snapshot/snapshot.h"
35 #include "src/v8.h"
36 #include "test/cctest/cctest.h"
37 #include "test/cctest/heap-tester.h"
38
39 namespace v8 {
40 namespace internal {
41
42 #if 0
43 static void VerifyRegionMarking(Address page_start) {
44 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER
45 Page* p = Page::FromAddress(page_start);
46
47 p->SetRegionMarks(Page::kAllRegionsCleanMarks);
48
49 for (Address addr = p->ObjectAreaStart();
50 addr < p->ObjectAreaEnd();
51 addr += kPointerSize) {
52 CHECK(!Page::FromAddress(addr)->IsRegionDirty(addr));
53 }
54
55 for (Address addr = p->ObjectAreaStart();
56 addr < p->ObjectAreaEnd();
57 addr += kPointerSize) {
58 Page::FromAddress(addr)->MarkRegionDirty(addr);
59 }
60
61 for (Address addr = p->ObjectAreaStart();
62 addr < p->ObjectAreaEnd();
63 addr += kPointerSize) {
64 CHECK(Page::FromAddress(addr)->IsRegionDirty(addr));
65 }
66 #endif
67 }
68 #endif
69
70
71 // TODO(gc) you can no longer allocate pages like this. Details are hidden.
72 #if 0
73 TEST(Page) {
74 byte* mem = NewArray<byte>(2*Page::kPageSize);
75 CHECK(mem != NULL);
76
77 Address start = reinterpret_cast<Address>(mem);
78 Address page_start = RoundUp(start, Page::kPageSize);
79
80 Page* p = Page::FromAddress(page_start);
81 // Initialized Page has heap pointer, normally set by memory_allocator.
82 p->heap_ = CcTest::heap();
83 CHECK(p->address() == page_start);
84 CHECK(p->is_valid());
85
86 p->opaque_header = 0;
87 p->SetIsLargeObjectPage(false);
88 CHECK(!p->next_page()->is_valid());
89
90 CHECK(p->ObjectAreaStart() == page_start + Page::kObjectStartOffset);
91 CHECK(p->ObjectAreaEnd() == page_start + Page::kPageSize);
92
93 CHECK(p->Offset(page_start + Page::kObjectStartOffset) ==
94 Page::kObjectStartOffset);
95 CHECK(p->Offset(page_start + Page::kPageSize) == Page::kPageSize);
96
97 CHECK(p->OffsetToAddress(Page::kObjectStartOffset) == p->ObjectAreaStart());
98 CHECK(p->OffsetToAddress(Page::kPageSize) == p->ObjectAreaEnd());
99
100 // test region marking
101 VerifyRegionMarking(page_start);
102
103 DeleteArray(mem);
104 }
105 #endif
106
107
108 // Temporarily sets a given allocator in an isolate.
109 class TestMemoryAllocatorScope {
110 public:
111 TestMemoryAllocatorScope(Isolate* isolate, MemoryAllocator* allocator)
112 : isolate_(isolate),
113 old_allocator_(isolate->memory_allocator_) {
114 isolate->memory_allocator_ = allocator;
115 }
116
117 ~TestMemoryAllocatorScope() {
118 isolate_->memory_allocator_ = old_allocator_;
119 }
120
121 private:
122 Isolate* isolate_;
123 MemoryAllocator* old_allocator_;
124
125 DISALLOW_COPY_AND_ASSIGN(TestMemoryAllocatorScope);
126 };
127
128
129 // Temporarily sets a given code range in an isolate.
130 class TestCodeRangeScope {
131 public:
132 TestCodeRangeScope(Isolate* isolate, CodeRange* code_range)
133 : isolate_(isolate),
134 old_code_range_(isolate->code_range_) {
135 isolate->code_range_ = code_range;
136 }
137
138 ~TestCodeRangeScope() {
139 isolate_->code_range_ = old_code_range_;
140 }
141
142 private:
143 Isolate* isolate_;
144 CodeRange* old_code_range_;
145
146 DISALLOW_COPY_AND_ASSIGN(TestCodeRangeScope);
147 };
148
149
150 static void VerifyMemoryChunk(Isolate* isolate,
151 Heap* heap,
152 CodeRange* code_range,
153 size_t reserve_area_size,
154 size_t commit_area_size,
155 size_t second_commit_area_size,
156 Executability executable) {
157 MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
158 CHECK(memory_allocator->SetUp(heap->MaxReserved(),
159 heap->MaxExecutableSize()));
160 TestMemoryAllocatorScope test_allocator_scope(isolate, memory_allocator);
161 TestCodeRangeScope test_code_range_scope(isolate, code_range);
162
163 size_t header_size = (executable == EXECUTABLE)
164 ? MemoryAllocator::CodePageGuardStartOffset()
165 : MemoryChunk::kObjectStartOffset;
166 size_t guard_size = (executable == EXECUTABLE)
167 ? MemoryAllocator::CodePageGuardSize()
168 : 0;
169
170 MemoryChunk* memory_chunk = memory_allocator->AllocateChunk(reserve_area_size,
171 commit_area_size,
172 executable,
173 NULL);
174 size_t alignment = code_range != NULL && code_range->valid()
175 ? MemoryChunk::kAlignment
176 : base::OS::CommitPageSize();
177 size_t reserved_size =
178 ((executable == EXECUTABLE))
179 ? RoundUp(header_size + guard_size + reserve_area_size + guard_size,
180 alignment)
181 : RoundUp(header_size + reserve_area_size,
182 base::OS::CommitPageSize());
183 CHECK(memory_chunk->size() == reserved_size);
184 CHECK(memory_chunk->area_start() < memory_chunk->address() +
185 memory_chunk->size());
186 CHECK(memory_chunk->area_end() <= memory_chunk->address() +
187 memory_chunk->size());
188 CHECK(static_cast<size_t>(memory_chunk->area_size()) == commit_area_size);
189
190 Address area_start = memory_chunk->area_start();
191
192 memory_chunk->CommitArea(second_commit_area_size);
193 CHECK(area_start == memory_chunk->area_start());
194 CHECK(memory_chunk->area_start() < memory_chunk->address() +
195 memory_chunk->size());
196 CHECK(memory_chunk->area_end() <= memory_chunk->address() +
197 memory_chunk->size());
198 CHECK(static_cast<size_t>(memory_chunk->area_size()) ==
199 second_commit_area_size);
200
201 memory_allocator->Free(memory_chunk);
202 memory_allocator->TearDown();
203 delete memory_allocator;
204 }
205
206
207 TEST(Regress3540) {
208 Isolate* isolate = CcTest::i_isolate();
209 Heap* heap = isolate->heap();
210 const int pageSize = Page::kPageSize;
211 MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
212 CHECK(
213 memory_allocator->SetUp(heap->MaxReserved(), heap->MaxExecutableSize()));
214 TestMemoryAllocatorScope test_allocator_scope(isolate, memory_allocator);
215 CodeRange* code_range = new CodeRange(isolate);
216 const size_t code_range_size = 4 * pageSize;
217 if (!code_range->SetUp(
218 code_range_size +
219 RoundUp(v8::base::OS::CommitPageSize() * kReservedCodeRangePages,
220 MemoryChunk::kAlignment) +
221 v8::internal::MemoryAllocator::CodePageAreaSize())) {
222 return;
223 }
224
225 Address address;
226 size_t size;
227 size_t request_size = code_range_size - 2 * pageSize;
228 address = code_range->AllocateRawMemory(
229 request_size, request_size - (2 * MemoryAllocator::CodePageGuardSize()),
230 &size);
231 CHECK(address != NULL);
232
233 Address null_address;
234 size_t null_size;
235 request_size = code_range_size - pageSize;
236 null_address = code_range->AllocateRawMemory(
237 request_size, request_size - (2 * MemoryAllocator::CodePageGuardSize()),
238 &null_size);
239 CHECK(null_address == NULL);
240
241 code_range->FreeRawMemory(address, size);
242 delete code_range;
243 memory_allocator->TearDown();
244 delete memory_allocator;
245 }
246
247
248 static unsigned int Pseudorandom() {
249 static uint32_t lo = 2345;
250 lo = 18273 * (lo & 0xFFFFF) + (lo >> 16);
251 return lo & 0xFFFFF;
252 }
253
254
255 TEST(MemoryChunk) {
256 Isolate* isolate = CcTest::i_isolate();
257 Heap* heap = isolate->heap();
258
259 size_t reserve_area_size = 1 * MB;
260 size_t initial_commit_area_size, second_commit_area_size;
261
262 for (int i = 0; i < 100; i++) {
263 initial_commit_area_size = Pseudorandom();
264 second_commit_area_size = Pseudorandom();
265
266 // With CodeRange.
267 CodeRange* code_range = new CodeRange(isolate);
268 const size_t code_range_size = 32 * MB;
269 if (!code_range->SetUp(code_range_size)) return;
270
271 VerifyMemoryChunk(isolate,
272 heap,
273 code_range,
274 reserve_area_size,
275 initial_commit_area_size,
276 second_commit_area_size,
277 EXECUTABLE);
278
279 VerifyMemoryChunk(isolate,
280 heap,
281 code_range,
282 reserve_area_size,
283 initial_commit_area_size,
284 second_commit_area_size,
285 NOT_EXECUTABLE);
286 delete code_range;
287
288 // Without CodeRange.
289 code_range = NULL;
290 VerifyMemoryChunk(isolate,
291 heap,
292 code_range,
293 reserve_area_size,
294 initial_commit_area_size,
295 second_commit_area_size,
296 EXECUTABLE);
297
298 VerifyMemoryChunk(isolate,
299 heap,
300 code_range,
301 reserve_area_size,
302 initial_commit_area_size,
303 second_commit_area_size,
304 NOT_EXECUTABLE);
305 }
306 }
307
308
309 TEST(MemoryAllocator) {
310 Isolate* isolate = CcTest::i_isolate();
311 Heap* heap = isolate->heap();
312
313 MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
314 CHECK(memory_allocator != nullptr);
315 CHECK(memory_allocator->SetUp(heap->MaxReserved(),
316 heap->MaxExecutableSize()));
317 TestMemoryAllocatorScope test_scope(isolate, memory_allocator);
318
319 {
320 int total_pages = 0;
321 OldSpace faked_space(heap, OLD_SPACE, NOT_EXECUTABLE);
322 Page* first_page = memory_allocator->AllocatePage(
323 faked_space.AreaSize(), &faked_space, NOT_EXECUTABLE);
324
325 first_page->InsertAfter(faked_space.anchor()->prev_page());
326 CHECK(first_page->is_valid());
327 CHECK(first_page->next_page() == faked_space.anchor());
328 total_pages++;
329
330 for (Page* p = first_page; p != faked_space.anchor(); p = p->next_page()) {
331 CHECK(p->owner() == &faked_space);
332 }
333
334 // Again, we should get n or n - 1 pages.
335 Page* other = memory_allocator->AllocatePage(faked_space.AreaSize(),
336 &faked_space, NOT_EXECUTABLE);
337 CHECK(other->is_valid());
338 total_pages++;
339 other->InsertAfter(first_page);
340 int page_count = 0;
341 for (Page* p = first_page; p != faked_space.anchor(); p = p->next_page()) {
342 CHECK(p->owner() == &faked_space);
343 page_count++;
344 }
345 CHECK(total_pages == page_count);
346
347 Page* second_page = first_page->next_page();
348 CHECK(second_page->is_valid());
349
350 // OldSpace's destructor will tear down the space and free up all pages.
351 }
352 memory_allocator->TearDown();
353 delete memory_allocator;
354 }
355
356
357 TEST(NewSpace) {
358 Isolate* isolate = CcTest::i_isolate();
359 Heap* heap = isolate->heap();
360 MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
361 CHECK(memory_allocator->SetUp(heap->MaxReserved(),
362 heap->MaxExecutableSize()));
363 TestMemoryAllocatorScope test_scope(isolate, memory_allocator);
364
365 NewSpace new_space(heap);
366
367 CHECK(new_space.SetUp(CcTest::heap()->ReservedSemiSpaceSize(),
368 CcTest::heap()->ReservedSemiSpaceSize()));
369 CHECK(new_space.HasBeenSetUp());
370
371 while (new_space.Available() >= Page::kMaxRegularHeapObjectSize) {
372 Object* obj =
373 new_space.AllocateRawUnaligned(Page::kMaxRegularHeapObjectSize)
374 .ToObjectChecked();
375 CHECK(new_space.Contains(HeapObject::cast(obj)));
376 }
377
378 new_space.TearDown();
379 memory_allocator->TearDown();
380 delete memory_allocator;
381 }
382
383
384 TEST(OldSpace) {
385 Isolate* isolate = CcTest::i_isolate();
386 Heap* heap = isolate->heap();
387 MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
388 CHECK(memory_allocator->SetUp(heap->MaxReserved(),
389 heap->MaxExecutableSize()));
390 TestMemoryAllocatorScope test_scope(isolate, memory_allocator);
391
392 OldSpace* s = new OldSpace(heap, OLD_SPACE, NOT_EXECUTABLE);
393 CHECK(s != NULL);
394
395 CHECK(s->SetUp());
396
397 while (s->Available() > 0) {
398 s->AllocateRawUnaligned(Page::kMaxRegularHeapObjectSize).ToObjectChecked();
399 }
400
401 delete s;
402 memory_allocator->TearDown();
403 delete memory_allocator;
404 }
405
406
407 TEST(CompactionSpace) {
408 Isolate* isolate = CcTest::i_isolate();
409 Heap* heap = isolate->heap();
410 MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
411 CHECK(memory_allocator != nullptr);
412 CHECK(
413 memory_allocator->SetUp(heap->MaxReserved(), heap->MaxExecutableSize()));
414 TestMemoryAllocatorScope test_scope(isolate, memory_allocator);
415
416 CompactionSpace* compaction_space =
417 new CompactionSpace(heap, OLD_SPACE, NOT_EXECUTABLE);
418 CHECK(compaction_space != NULL);
419 CHECK(compaction_space->SetUp());
420
421 OldSpace* old_space = new OldSpace(heap, OLD_SPACE, NOT_EXECUTABLE);
422 CHECK(old_space != NULL);
423 CHECK(old_space->SetUp());
424
425 // Cannot loop until "Available()" since we initially have 0 bytes available
426 // and would thus neither grow, nor be able to allocate an object.
427 const int kNumObjects = 100;
428 const int kNumObjectsPerPage =
429 compaction_space->AreaSize() / Page::kMaxRegularHeapObjectSize;
430 const int kExpectedPages =
431 (kNumObjects + kNumObjectsPerPage - 1) / kNumObjectsPerPage;
432 for (int i = 0; i < kNumObjects; i++) {
433 compaction_space->AllocateRawUnaligned(Page::kMaxRegularHeapObjectSize)
434 .ToObjectChecked();
435 }
436 int pages_in_old_space = old_space->CountTotalPages();
437 int pages_in_compaction_space = compaction_space->CountTotalPages();
438 CHECK_EQ(pages_in_compaction_space, kExpectedPages);
439 CHECK_LE(pages_in_old_space, 1);
440
441 old_space->MergeCompactionSpace(compaction_space);
442 CHECK_EQ(old_space->CountTotalPages(),
443 pages_in_old_space + pages_in_compaction_space);
444
445 delete compaction_space;
446 delete old_space;
447
448 memory_allocator->TearDown();
449 delete memory_allocator;
450 }
451
452
453 TEST(CompactionSpaceUsingExternalMemory) {
454 const int kObjectSize = 512;
455
456 Isolate* isolate = CcTest::i_isolate();
457 Heap* heap = isolate->heap();
458 MemoryAllocator* allocator = new MemoryAllocator(isolate);
459 CHECK(allocator != nullptr);
460 CHECK(allocator->SetUp(heap->MaxReserved(), heap->MaxExecutableSize()));
461 TestMemoryAllocatorScope test_scope(isolate, allocator);
462
463 CompactionSpaceCollection* collection = new CompactionSpaceCollection(heap);
464 CompactionSpace* compaction_space = collection->Get(OLD_SPACE);
465 CHECK(compaction_space != NULL);
466 CHECK(compaction_space->SetUp());
467
468 OldSpace* old_space = new OldSpace(heap, OLD_SPACE, NOT_EXECUTABLE);
469 CHECK(old_space != NULL);
470 CHECK(old_space->SetUp());
471
472 // The linear allocation area already counts as used bytes, making
473 // exact testing impossible.
474 heap->DisableInlineAllocation();
475
476 // Test:
477 // * Allocate a backing store in old_space.
478 // * Compute the number num_rest_objects of kObjectSize objects that fit into
479 // of available memory.
480 // kNumRestObjects.
481 // * Add the rest of available memory to the compaction space.
482 // * Allocate kNumRestObjects in the compaction space.
483 // * Allocate one object more.
484 // * Merge the compaction space and compare the expected number of pages.
485
486 // Allocate a single object in old_space to initialize a backing page.
487 old_space->AllocateRawUnaligned(kObjectSize).ToObjectChecked();
488 // Compute the number of objects that fit into the rest in old_space.
489 intptr_t rest = static_cast<int>(old_space->Available());
490 CHECK_GT(rest, 0);
491 intptr_t num_rest_objects = rest / kObjectSize;
492 // After allocating num_rest_objects in compaction_space we allocate a bit
493 // more.
494 const intptr_t kAdditionalCompactionMemory = kObjectSize;
495 // We expect a single old_space page.
496 const intptr_t kExpectedInitialOldSpacePages = 1;
497 // We expect a single additional page in compaction space because we mostly
498 // use external memory.
499 const intptr_t kExpectedCompactionPages = 1;
500 // We expect two pages to be reachable from old_space in the end.
501 const intptr_t kExpectedOldSpacePagesAfterMerge = 2;
502
503 CHECK_EQ(old_space->CountTotalPages(), kExpectedInitialOldSpacePages);
504 CHECK_EQ(compaction_space->CountTotalPages(), 0);
505 CHECK_EQ(compaction_space->Capacity(), 0);
506 // Make the rest of memory available for compaction.
507 old_space->DivideUponCompactionSpaces(&collection, 1, rest);
508 CHECK_EQ(compaction_space->CountTotalPages(), 0);
509 CHECK_EQ(compaction_space->Capacity(), rest);
510 while (num_rest_objects-- > 0) {
511 compaction_space->AllocateRawUnaligned(kObjectSize).ToObjectChecked();
512 }
513 // We only used external memory so far.
514 CHECK_EQ(compaction_space->CountTotalPages(), 0);
515 // Additional allocation.
516 compaction_space->AllocateRawUnaligned(kAdditionalCompactionMemory)
517 .ToObjectChecked();
518 // Now the compaction space shouldve also acquired a page.
519 CHECK_EQ(compaction_space->CountTotalPages(), kExpectedCompactionPages);
520
521 old_space->MergeCompactionSpace(compaction_space);
522 CHECK_EQ(old_space->CountTotalPages(), kExpectedOldSpacePagesAfterMerge);
523
524 delete collection;
525 delete old_space;
526
527 allocator->TearDown();
528 delete allocator;
529 }
530
531
532 CompactionSpaceCollection** HeapTester::InitializeCompactionSpaces(
533 Heap* heap, int num_spaces) {
534 CompactionSpaceCollection** spaces =
535 new CompactionSpaceCollection*[num_spaces];
536 for (int i = 0; i < num_spaces; i++) {
537 spaces[i] = new CompactionSpaceCollection(heap);
538 }
539 return spaces;
540 }
541
542
543 void HeapTester::DestroyCompactionSpaces(CompactionSpaceCollection** spaces,
544 int num_spaces) {
545 for (int i = 0; i < num_spaces; i++) {
546 delete spaces[i];
547 }
548 delete[] spaces;
549 }
550
551
552 void HeapTester::MergeCompactionSpaces(PagedSpace* space,
553 CompactionSpaceCollection** spaces,
554 int num_spaces) {
555 AllocationSpace id = space->identity();
556 for (int i = 0; i < num_spaces; i++) {
557 space->MergeCompactionSpace(spaces[i]->Get(id));
558 CHECK_EQ(spaces[i]->Get(id)->accounting_stats_.Size(), 0);
559 CHECK_EQ(spaces[i]->Get(id)->accounting_stats_.Capacity(), 0);
560 CHECK_EQ(spaces[i]->Get(id)->Waste(), 0);
561 }
562 }
563
564
565 void HeapTester::AllocateInCompactionSpaces(CompactionSpaceCollection** spaces,
566 AllocationSpace id, int num_spaces,
567 int num_objects, int object_size) {
568 for (int i = 0; i < num_spaces; i++) {
569 for (int j = 0; j < num_objects; j++) {
570 spaces[i]->Get(id)->AllocateRawUnaligned(object_size).ToObjectChecked();
571 }
572 spaces[i]->Get(id)->EmptyAllocationInfo();
573 CHECK_EQ(spaces[i]->Get(id)->accounting_stats_.Size(),
574 num_objects * object_size);
575 CHECK_GE(spaces[i]->Get(id)->accounting_stats_.Capacity(),
576 spaces[i]->Get(id)->accounting_stats_.Size());
577 }
578 }
579
580
581 void HeapTester::CompactionStats(CompactionSpaceCollection** spaces,
582 AllocationSpace id, int num_spaces,
583 intptr_t* capacity, intptr_t* size) {
584 *capacity = 0;
585 *size = 0;
586 for (int i = 0; i < num_spaces; i++) {
587 *capacity += spaces[i]->Get(id)->accounting_stats_.Capacity();
588 *size += spaces[i]->Get(id)->accounting_stats_.Size();
589 }
590 }
591
592
593 void HeapTester::TestCompactionSpaceDivide(int num_additional_objects,
594 int object_size,
595 int num_compaction_spaces,
596 int additional_capacity_in_bytes) {
597 Isolate* isolate = CcTest::i_isolate();
598 Heap* heap = isolate->heap();
599 OldSpace* old_space = new OldSpace(heap, OLD_SPACE, NOT_EXECUTABLE);
600 CHECK(old_space != nullptr);
601 CHECK(old_space->SetUp());
602 old_space->AllocateRawUnaligned(object_size).ToObjectChecked();
603 old_space->EmptyAllocationInfo();
604
605 intptr_t rest_capacity = old_space->accounting_stats_.Capacity() -
606 old_space->accounting_stats_.Size();
607 intptr_t capacity_for_compaction_space =
608 rest_capacity / num_compaction_spaces;
609 int num_objects_in_compaction_space =
610 static_cast<int>(capacity_for_compaction_space) / object_size +
611 num_additional_objects;
612 CHECK_GT(num_objects_in_compaction_space, 0);
613 intptr_t initial_old_space_capacity = old_space->accounting_stats_.Capacity();
614
615 CompactionSpaceCollection** spaces =
616 InitializeCompactionSpaces(heap, num_compaction_spaces);
617 old_space->DivideUponCompactionSpaces(spaces, num_compaction_spaces,
618 capacity_for_compaction_space);
619
620 intptr_t compaction_capacity = 0;
621 intptr_t compaction_size = 0;
622 CompactionStats(spaces, OLD_SPACE, num_compaction_spaces,
623 &compaction_capacity, &compaction_size);
624
625 intptr_t old_space_capacity = old_space->accounting_stats_.Capacity();
626 intptr_t old_space_size = old_space->accounting_stats_.Size();
627 // Compaction space memory is subtracted from the original space's capacity.
628 CHECK_EQ(old_space_capacity,
629 initial_old_space_capacity - compaction_capacity);
630 CHECK_EQ(compaction_size, 0);
631
632 AllocateInCompactionSpaces(spaces, OLD_SPACE, num_compaction_spaces,
633 num_objects_in_compaction_space, object_size);
634
635 // Old space size and capacity should be the same as after dividing.
636 CHECK_EQ(old_space->accounting_stats_.Size(), old_space_size);
637 CHECK_EQ(old_space->accounting_stats_.Capacity(), old_space_capacity);
638
639 CompactionStats(spaces, OLD_SPACE, num_compaction_spaces,
640 &compaction_capacity, &compaction_size);
641 MergeCompactionSpaces(old_space, spaces, num_compaction_spaces);
642
643 CHECK_EQ(old_space->accounting_stats_.Capacity(),
644 old_space_capacity + compaction_capacity);
645 CHECK_EQ(old_space->accounting_stats_.Size(),
646 old_space_size + compaction_size);
647 // We check against the expected end capacity.
648 CHECK_EQ(old_space->accounting_stats_.Capacity(),
649 initial_old_space_capacity + additional_capacity_in_bytes);
650
651 DestroyCompactionSpaces(spaces, num_compaction_spaces);
652 delete old_space;
653 }
654
655
656 HEAP_TEST(CompactionSpaceDivideSinglePage) {
657 const int kObjectSize = KB;
658 const int kCompactionSpaces = 4;
659 // Since the bound for objects is tight and the dividing is best effort, we
660 // subtract some objects to make sure we still fit in the initial page.
661 // A CHECK makes sure that the overall number of allocated objects stays
662 // > 0.
663 const int kAdditionalObjects = -10;
664 const int kAdditionalCapacityRequired = 0;
665 TestCompactionSpaceDivide(kAdditionalObjects, kObjectSize, kCompactionSpaces,
666 kAdditionalCapacityRequired);
667 }
668
669
670 HEAP_TEST(CompactionSpaceDivideMultiplePages) {
671 const int kObjectSize = KB;
672 const int kCompactionSpaces = 4;
673 // Allocate half a page of objects to ensure that we need one more page per
674 // compaction space.
675 const int kAdditionalObjects = (Page::kPageSize / kObjectSize / 2);
676 const int kAdditionalCapacityRequired =
677 Page::kAllocatableMemory * kCompactionSpaces;
678 TestCompactionSpaceDivide(kAdditionalObjects, kObjectSize, kCompactionSpaces,
679 kAdditionalCapacityRequired);
680 }
681
682
683 TEST(LargeObjectSpace) {
684 v8::V8::Initialize();
685
686 LargeObjectSpace* lo = CcTest::heap()->lo_space();
687 CHECK(lo != NULL);
688
689 int lo_size = Page::kPageSize;
690
691 Object* obj = lo->AllocateRaw(lo_size, NOT_EXECUTABLE).ToObjectChecked();
692 CHECK(obj->IsHeapObject());
693
694 HeapObject* ho = HeapObject::cast(obj);
695
696 CHECK(lo->Contains(HeapObject::cast(obj)));
697
698 CHECK(lo->FindObject(ho->address()) == obj);
699
700 CHECK(lo->Contains(ho));
701
702 while (true) {
703 intptr_t available = lo->Available();
704 { AllocationResult allocation = lo->AllocateRaw(lo_size, NOT_EXECUTABLE);
705 if (allocation.IsRetry()) break;
706 }
707 // The available value is conservative such that it may report
708 // zero prior to heap exhaustion.
709 CHECK(lo->Available() < available || available == 0);
710 }
711
712 CHECK(!lo->IsEmpty());
713
714 CHECK(lo->AllocateRaw(lo_size, NOT_EXECUTABLE).IsRetry());
715 }
716
717
718 TEST(SizeOfFirstPageIsLargeEnough) {
719 if (i::FLAG_always_opt) return;
720 // Bootstrapping without a snapshot causes more allocations.
721 CcTest::InitializeVM();
722 Isolate* isolate = CcTest::i_isolate();
723 if (!isolate->snapshot_available()) return;
724 if (Snapshot::EmbedsScript(isolate)) return;
725
726 // If this test fails due to enabling experimental natives that are not part
727 // of the snapshot, we may need to adjust CalculateFirstPageSizes.
728
729 // Freshly initialized VM gets by with one page per space.
730 for (int i = FIRST_PAGED_SPACE; i <= LAST_PAGED_SPACE; i++) {
731 // Debug code can be very large, so skip CODE_SPACE if we are generating it.
732 if (i == CODE_SPACE && i::FLAG_debug_code) continue;
733 CHECK_EQ(1, isolate->heap()->paged_space(i)->CountTotalPages());
734 }
735
736 // Executing the empty script gets by with one page per space.
737 HandleScope scope(isolate);
738 CompileRun("/*empty*/");
739 for (int i = FIRST_PAGED_SPACE; i <= LAST_PAGED_SPACE; i++) {
740 // Debug code can be very large, so skip CODE_SPACE if we are generating it.
741 if (i == CODE_SPACE && i::FLAG_debug_code) continue;
742 CHECK_EQ(1, isolate->heap()->paged_space(i)->CountTotalPages());
743 }
744
745 // No large objects required to perform the above steps.
746 CHECK(isolate->heap()->lo_space()->IsEmpty());
747 }
748
749
750 UNINITIALIZED_TEST(NewSpaceGrowsToTargetCapacity) {
751 FLAG_target_semi_space_size = 2 * (Page::kPageSize / MB);
752 if (FLAG_optimize_for_size) return;
753
754 v8::Isolate::CreateParams create_params;
755 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
756 v8::Isolate* isolate = v8::Isolate::New(create_params);
757 {
758 v8::Isolate::Scope isolate_scope(isolate);
759 v8::HandleScope handle_scope(isolate);
760 v8::Context::New(isolate)->Enter();
761
762 Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
763
764 NewSpace* new_space = i_isolate->heap()->new_space();
765
766 // This test doesn't work if we start with a non-default new space
767 // configuration.
768 if (new_space->InitialTotalCapacity() == Page::kPageSize) {
769 CHECK_EQ(new_space->CommittedMemory(), new_space->InitialTotalCapacity());
770
771 // Fill up the first (and only) page of the semi space.
772 FillCurrentPage(new_space);
773
774 // Try to allocate out of the new space. A new page should be added and
775 // the
776 // allocation should succeed.
777 v8::internal::AllocationResult allocation =
778 new_space->AllocateRawUnaligned(80);
779 CHECK(!allocation.IsRetry());
780 CHECK_EQ(new_space->CommittedMemory(), 2 * Page::kPageSize);
781
782 // Turn the allocation into a proper object so isolate teardown won't
783 // crash.
784 HeapObject* free_space = NULL;
785 CHECK(allocation.To(&free_space));
786 new_space->heap()->CreateFillerObjectAt(free_space->address(), 80);
787 }
788 }
789 isolate->Dispose();
790 }
791
792
793 static HeapObject* AllocateUnaligned(NewSpace* space, int size) {
794 AllocationResult allocation = space->AllocateRawUnaligned(size);
795 CHECK(!allocation.IsRetry());
796 HeapObject* filler = NULL;
797 CHECK(allocation.To(&filler));
798 space->heap()->CreateFillerObjectAt(filler->address(), size);
799 return filler;
800 }
801
802 class Observer : public InlineAllocationObserver {
803 public:
804 explicit Observer(intptr_t step_size)
805 : InlineAllocationObserver(step_size), count_(0) {}
806
807 void Step(int bytes_allocated, Address, size_t) override { count_++; }
808
809 int count() const { return count_; }
810
811 private:
812 int count_;
813 };
814
815
816 UNINITIALIZED_TEST(InlineAllocationObserver) {
817 v8::Isolate::CreateParams create_params;
818 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
819 v8::Isolate* isolate = v8::Isolate::New(create_params);
820 {
821 v8::Isolate::Scope isolate_scope(isolate);
822 v8::HandleScope handle_scope(isolate);
823 v8::Context::New(isolate)->Enter();
824
825 Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
826
827 NewSpace* new_space = i_isolate->heap()->new_space();
828
829 Observer observer1(128);
830 new_space->AddInlineAllocationObserver(&observer1);
831
832 // The observer should not get notified if we have only allocated less than
833 // 128 bytes.
834 AllocateUnaligned(new_space, 64);
835 CHECK_EQ(observer1.count(), 0);
836
837 // The observer should get called when we have allocated exactly 128 bytes.
838 AllocateUnaligned(new_space, 64);
839 CHECK_EQ(observer1.count(), 1);
840
841 // Another >128 bytes should get another notification.
842 AllocateUnaligned(new_space, 136);
843 CHECK_EQ(observer1.count(), 2);
844
845 // Allocating a large object should get only one notification.
846 AllocateUnaligned(new_space, 1024);
847 CHECK_EQ(observer1.count(), 3);
848
849 // Allocating another 2048 bytes in small objects should get 16
850 // notifications.
851 for (int i = 0; i < 64; ++i) {
852 AllocateUnaligned(new_space, 32);
853 }
854 CHECK_EQ(observer1.count(), 19);
855
856 // Multiple observers should work.
857 Observer observer2(96);
858 new_space->AddInlineAllocationObserver(&observer2);
859
860 AllocateUnaligned(new_space, 2048);
861 CHECK_EQ(observer1.count(), 20);
862 CHECK_EQ(observer2.count(), 1);
863
864 AllocateUnaligned(new_space, 104);
865 CHECK_EQ(observer1.count(), 20);
866 CHECK_EQ(observer2.count(), 2);
867
868 // Callback should stop getting called after an observer is removed.
869 new_space->RemoveInlineAllocationObserver(&observer1);
870
871 AllocateUnaligned(new_space, 384);
872 CHECK_EQ(observer1.count(), 20); // no more notifications.
873 CHECK_EQ(observer2.count(), 3); // this one is still active.
874
875 // Ensure that PauseInlineAllocationObserversScope work correctly.
876 AllocateUnaligned(new_space, 48);
877 CHECK_EQ(observer2.count(), 3);
878 {
879 PauseInlineAllocationObserversScope pause_observers(new_space);
880 CHECK_EQ(observer2.count(), 3);
881 AllocateUnaligned(new_space, 384);
882 CHECK_EQ(observer2.count(), 3);
883 }
884 CHECK_EQ(observer2.count(), 3);
885 // Coupled with the 48 bytes allocated before the pause, another 48 bytes
886 // allocated here should trigger a notification.
887 AllocateUnaligned(new_space, 48);
888 CHECK_EQ(observer2.count(), 4);
889
890 new_space->RemoveInlineAllocationObserver(&observer2);
891 AllocateUnaligned(new_space, 384);
892 CHECK_EQ(observer1.count(), 20);
893 CHECK_EQ(observer2.count(), 4);
894 }
895 isolate->Dispose();
896 }
897
898
899 UNINITIALIZED_TEST(InlineAllocationObserverCadence) {
900 v8::Isolate::CreateParams create_params;
901 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
902 v8::Isolate* isolate = v8::Isolate::New(create_params);
903 {
904 v8::Isolate::Scope isolate_scope(isolate);
905 v8::HandleScope handle_scope(isolate);
906 v8::Context::New(isolate)->Enter();
907
908 Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
909
910 NewSpace* new_space = i_isolate->heap()->new_space();
911
912 Observer observer1(512);
913 new_space->AddInlineAllocationObserver(&observer1);
914 Observer observer2(576);
915 new_space->AddInlineAllocationObserver(&observer2);
916
917 for (int i = 0; i < 512; ++i) {
918 AllocateUnaligned(new_space, 32);
919 }
920
921 new_space->RemoveInlineAllocationObserver(&observer1);
922 new_space->RemoveInlineAllocationObserver(&observer2);
923
924 CHECK_EQ(observer1.count(), 32);
925 CHECK_EQ(observer2.count(), 28);
926 }
927 isolate->Dispose();
928 }
929
930 } // namespace internal
931 } // namespace v8
OLDNEW
« no previous file with comments | « test/cctest/test-slots-buffer.cc ('k') | test/cctest/test-unboxed-doubles.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698