2017-04-05 07:36:15 +00:00
|
|
|
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2019-05-22 07:55:37 +00:00
|
|
|
#include "src/execution/isolate.h"
|
2017-04-05 07:36:15 +00:00
|
|
|
#include "src/heap/heap-inl.h"
|
2018-07-24 20:13:40 +00:00
|
|
|
#include "src/heap/heap-write-barrier-inl.h"
|
2017-04-05 07:36:15 +00:00
|
|
|
#include "src/heap/spaces-inl.h"
|
|
|
|
#include "test/unittests/test-utils.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
|
2019-03-29 09:47:48 +00:00
|
|
|
using SpacesTest = TestWithIsolate;
|
2017-04-05 07:36:15 +00:00
|
|
|
|
|
|
|
TEST_F(SpacesTest, CompactionSpaceMerge) {
|
|
|
|
Heap* heap = i_isolate()->heap();
|
|
|
|
OldSpace* old_space = heap->old_space();
|
2018-09-13 14:55:18 +00:00
|
|
|
EXPECT_TRUE(old_space != nullptr);
|
2017-04-05 07:36:15 +00:00
|
|
|
|
|
|
|
CompactionSpace* compaction_space =
|
|
|
|
new CompactionSpace(heap, OLD_SPACE, NOT_EXECUTABLE);
|
2018-09-13 14:55:18 +00:00
|
|
|
EXPECT_TRUE(compaction_space != nullptr);
|
2017-04-05 07:36:15 +00:00
|
|
|
|
2017-05-03 21:31:06 +00:00
|
|
|
for (Page* p : *old_space) {
|
|
|
|
// Unlink free lists from the main space to avoid reusing the memory for
|
|
|
|
// compaction spaces.
|
|
|
|
old_space->UnlinkFreeListCategories(p);
|
|
|
|
}
|
|
|
|
|
2017-04-05 07:36:15 +00:00
|
|
|
// Cannot loop until "Available()" since we initially have 0 bytes available
|
|
|
|
// and would thus neither grow, nor be able to allocate an object.
|
|
|
|
const int kNumObjects = 10;
|
|
|
|
const int kNumObjectsPerPage =
|
|
|
|
compaction_space->AreaSize() / kMaxRegularHeapObjectSize;
|
|
|
|
const int kExpectedPages =
|
|
|
|
(kNumObjects + kNumObjectsPerPage - 1) / kNumObjectsPerPage;
|
|
|
|
for (int i = 0; i < kNumObjects; i++) {
|
2018-12-20 15:47:47 +00:00
|
|
|
HeapObject object =
|
2017-04-05 07:36:15 +00:00
|
|
|
compaction_space->AllocateRawUnaligned(kMaxRegularHeapObjectSize)
|
|
|
|
.ToObjectChecked();
|
2019-08-19 16:22:01 +00:00
|
|
|
heap->CreateFillerObjectAt(object.address(), kMaxRegularHeapObjectSize,
|
|
|
|
ClearRecordedSlots::kNo);
|
2017-04-05 07:36:15 +00:00
|
|
|
}
|
|
|
|
int pages_in_old_space = old_space->CountTotalPages();
|
|
|
|
int pages_in_compaction_space = compaction_space->CountTotalPages();
|
|
|
|
EXPECT_EQ(kExpectedPages, pages_in_compaction_space);
|
|
|
|
old_space->MergeCompactionSpace(compaction_space);
|
|
|
|
EXPECT_EQ(pages_in_old_space + pages_in_compaction_space,
|
|
|
|
old_space->CountTotalPages());
|
|
|
|
|
|
|
|
delete compaction_space;
|
|
|
|
}
|
|
|
|
|
2018-07-24 20:13:40 +00:00
|
|
|
TEST_F(SpacesTest, WriteBarrierFromHeapObject) {
|
2018-07-26 09:53:35 +00:00
|
|
|
constexpr Address address1 = Page::kPageSize;
|
2019-01-07 12:28:05 +00:00
|
|
|
HeapObject object1 = HeapObject::unchecked_cast(Object(address1));
|
2018-07-26 09:53:35 +00:00
|
|
|
MemoryChunk* chunk1 = MemoryChunk::FromHeapObject(object1);
|
|
|
|
heap_internals::MemoryChunk* slim_chunk1 =
|
|
|
|
heap_internals::MemoryChunk::FromHeapObject(object1);
|
|
|
|
EXPECT_EQ(static_cast<void*>(chunk1), static_cast<void*>(slim_chunk1));
|
|
|
|
constexpr Address address2 = 2 * Page::kPageSize - 1;
|
2019-01-07 12:28:05 +00:00
|
|
|
HeapObject object2 = HeapObject::unchecked_cast(Object(address2));
|
2018-07-26 09:53:35 +00:00
|
|
|
MemoryChunk* chunk2 = MemoryChunk::FromHeapObject(object2);
|
|
|
|
heap_internals::MemoryChunk* slim_chunk2 =
|
|
|
|
heap_internals::MemoryChunk::FromHeapObject(object2);
|
|
|
|
EXPECT_EQ(static_cast<void*>(chunk2), static_cast<void*>(slim_chunk2));
|
2018-07-24 20:13:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(SpacesTest, WriteBarrierIsMarking) {
|
2019-01-10 13:09:28 +00:00
|
|
|
const size_t kSizeOfMemoryChunk = sizeof(MemoryChunk);
|
|
|
|
char memory[kSizeOfMemoryChunk];
|
|
|
|
memset(&memory, 0, kSizeOfMemoryChunk);
|
2018-07-24 20:13:40 +00:00
|
|
|
MemoryChunk* chunk = reinterpret_cast<MemoryChunk*>(&memory);
|
|
|
|
heap_internals::MemoryChunk* slim_chunk =
|
|
|
|
reinterpret_cast<heap_internals::MemoryChunk*>(&memory);
|
|
|
|
EXPECT_FALSE(chunk->IsFlagSet(MemoryChunk::INCREMENTAL_MARKING));
|
|
|
|
EXPECT_FALSE(slim_chunk->IsMarking());
|
|
|
|
chunk->SetFlag(MemoryChunk::INCREMENTAL_MARKING);
|
|
|
|
EXPECT_TRUE(chunk->IsFlagSet(MemoryChunk::INCREMENTAL_MARKING));
|
|
|
|
EXPECT_TRUE(slim_chunk->IsMarking());
|
|
|
|
chunk->ClearFlag(MemoryChunk::INCREMENTAL_MARKING);
|
|
|
|
EXPECT_FALSE(chunk->IsFlagSet(MemoryChunk::INCREMENTAL_MARKING));
|
|
|
|
EXPECT_FALSE(slim_chunk->IsMarking());
|
|
|
|
}
|
|
|
|
|
2019-01-28 13:13:10 +00:00
|
|
|
TEST_F(SpacesTest, WriteBarrierInYoungGenerationToSpace) {
|
2019-01-10 13:09:28 +00:00
|
|
|
const size_t kSizeOfMemoryChunk = sizeof(MemoryChunk);
|
|
|
|
char memory[kSizeOfMemoryChunk];
|
|
|
|
memset(&memory, 0, kSizeOfMemoryChunk);
|
2018-07-24 20:13:40 +00:00
|
|
|
MemoryChunk* chunk = reinterpret_cast<MemoryChunk*>(&memory);
|
|
|
|
heap_internals::MemoryChunk* slim_chunk =
|
|
|
|
reinterpret_cast<heap_internals::MemoryChunk*>(&memory);
|
2019-01-28 13:13:10 +00:00
|
|
|
EXPECT_FALSE(chunk->InYoungGeneration());
|
|
|
|
EXPECT_FALSE(slim_chunk->InYoungGeneration());
|
|
|
|
chunk->SetFlag(MemoryChunk::TO_PAGE);
|
|
|
|
EXPECT_TRUE(chunk->InYoungGeneration());
|
|
|
|
EXPECT_TRUE(slim_chunk->InYoungGeneration());
|
|
|
|
chunk->ClearFlag(MemoryChunk::TO_PAGE);
|
|
|
|
EXPECT_FALSE(chunk->InYoungGeneration());
|
|
|
|
EXPECT_FALSE(slim_chunk->InYoungGeneration());
|
2018-07-24 20:13:40 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 13:13:10 +00:00
|
|
|
TEST_F(SpacesTest, WriteBarrierInYoungGenerationFromSpace) {
|
2019-01-10 13:09:28 +00:00
|
|
|
const size_t kSizeOfMemoryChunk = sizeof(MemoryChunk);
|
|
|
|
char memory[kSizeOfMemoryChunk];
|
|
|
|
memset(&memory, 0, kSizeOfMemoryChunk);
|
2018-07-24 20:13:40 +00:00
|
|
|
MemoryChunk* chunk = reinterpret_cast<MemoryChunk*>(&memory);
|
|
|
|
heap_internals::MemoryChunk* slim_chunk =
|
|
|
|
reinterpret_cast<heap_internals::MemoryChunk*>(&memory);
|
2019-01-28 13:13:10 +00:00
|
|
|
EXPECT_FALSE(chunk->InYoungGeneration());
|
|
|
|
EXPECT_FALSE(slim_chunk->InYoungGeneration());
|
|
|
|
chunk->SetFlag(MemoryChunk::FROM_PAGE);
|
|
|
|
EXPECT_TRUE(chunk->InYoungGeneration());
|
|
|
|
EXPECT_TRUE(slim_chunk->InYoungGeneration());
|
|
|
|
chunk->ClearFlag(MemoryChunk::FROM_PAGE);
|
|
|
|
EXPECT_FALSE(chunk->InYoungGeneration());
|
|
|
|
EXPECT_FALSE(slim_chunk->InYoungGeneration());
|
2018-07-24 20:13:40 +00:00
|
|
|
}
|
|
|
|
|
2018-08-15 18:08:41 +00:00
|
|
|
TEST_F(SpacesTest, CodeRangeAddressReuse) {
|
|
|
|
CodeRangeAddressHint hint;
|
|
|
|
// Create code ranges.
|
2018-09-28 10:16:13 +00:00
|
|
|
Address code_range1 = hint.GetAddressHint(100);
|
|
|
|
Address code_range2 = hint.GetAddressHint(200);
|
|
|
|
Address code_range3 = hint.GetAddressHint(100);
|
2018-08-15 18:08:41 +00:00
|
|
|
|
|
|
|
// Since the addresses are random, we cannot check that they are different.
|
|
|
|
|
|
|
|
// Free two code ranges.
|
|
|
|
hint.NotifyFreedCodeRange(code_range1, 100);
|
|
|
|
hint.NotifyFreedCodeRange(code_range2, 200);
|
|
|
|
|
|
|
|
// The next two code ranges should reuse the freed addresses.
|
2018-09-28 10:16:13 +00:00
|
|
|
Address code_range4 = hint.GetAddressHint(100);
|
2018-08-15 18:08:41 +00:00
|
|
|
EXPECT_EQ(code_range4, code_range1);
|
2018-09-28 10:16:13 +00:00
|
|
|
Address code_range5 = hint.GetAddressHint(200);
|
2018-08-15 18:08:41 +00:00
|
|
|
EXPECT_EQ(code_range5, code_range2);
|
|
|
|
|
|
|
|
// Free the third code range and check address reuse.
|
|
|
|
hint.NotifyFreedCodeRange(code_range3, 100);
|
2018-09-28 10:16:13 +00:00
|
|
|
Address code_range6 = hint.GetAddressHint(100);
|
2018-08-15 18:08:41 +00:00
|
|
|
EXPECT_EQ(code_range6, code_range3);
|
|
|
|
}
|
|
|
|
|
2017-04-05 07:36:15 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|