| Index: runtime/vm/freelist_test.cc
|
| diff --git a/runtime/vm/freelist_test.cc b/runtime/vm/freelist_test.cc
|
| index fc506d76d1c2220637e965b49d7421f8151fb5ab..b7cfbca18cfb4a0f91cf53671dd316d267d58eb7 100644
|
| --- a/runtime/vm/freelist_test.cc
|
| +++ b/runtime/vm/freelist_test.cc
|
| @@ -8,47 +8,189 @@
|
|
|
| namespace dart {
|
|
|
| -TEST_CASE(FreeList) {
|
| - FreeList* free_list = new FreeList();
|
| - intptr_t kBlobSize = 1 * MB;
|
| - intptr_t kSmallObjectSize = 4 * kWordSize;
|
| - intptr_t kMediumObjectSize = 16 * kWordSize;
|
| - intptr_t kLargeObjectSize = 8 * KB;
|
| - uword blob = reinterpret_cast<uword>(malloc(kBlobSize));
|
| +static uword Allocate(FreeList* free_list, intptr_t size, bool is_protected) {
|
| + uword result = free_list->TryAllocate(size, is_protected);
|
| + if (result && is_protected) {
|
| + bool status = VirtualMemory::Protect(reinterpret_cast<void*>(result),
|
| + size,
|
| + VirtualMemory::kReadExecute);
|
| + ASSERT(status);
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| +static void Free(FreeList* free_list,
|
| + uword address,
|
| + intptr_t size,
|
| + bool is_protected) {
|
| + if (is_protected) {
|
| + bool status = VirtualMemory::Protect(reinterpret_cast<void*>(address),
|
| + size,
|
| + VirtualMemory::kReadWrite);
|
| + ASSERT(status);
|
| + }
|
| + free_list->Free(address, size);
|
| + if (is_protected) {
|
| + bool status = VirtualMemory::Protect(reinterpret_cast<void*>(address),
|
| + size,
|
| + VirtualMemory::kReadExecute);
|
| + ASSERT(status);
|
| + }
|
| +}
|
| +
|
| +
|
| +static void TestFreeList(VirtualMemory* region,
|
| + FreeList* free_list,
|
| + bool is_protected) {
|
| + const intptr_t kSmallObjectSize = 4 * kWordSize;
|
| + const intptr_t kMediumObjectSize = 16 * kWordSize;
|
| + const intptr_t kLargeObjectSize = 8 * KB;
|
| + uword blob = region->start();
|
| // Enqueue the large blob as one free block.
|
| - free_list->Free(blob, kBlobSize);
|
| + free_list->Free(blob, region->size());
|
| +
|
| + if (is_protected) {
|
| + // Write protect the whole region.
|
| + region->Protect(VirtualMemory::kReadExecute);
|
| + }
|
| +
|
| // Allocate a small object. Expect it to be positioned as the first element.
|
| - uword small_object = free_list->TryAllocate(kSmallObjectSize, false);
|
| + uword small_object = Allocate(free_list, kSmallObjectSize, is_protected);
|
| EXPECT_EQ(blob, small_object);
|
| // Freeing and allocating should give us the same memory back.
|
| - free_list->Free(small_object, kSmallObjectSize);
|
| - small_object = free_list->TryAllocate(kSmallObjectSize, false);
|
| + Free(free_list, small_object, kSmallObjectSize, is_protected);
|
| + small_object = Allocate(free_list, kSmallObjectSize, is_protected);
|
| EXPECT_EQ(blob, small_object);
|
| // Splitting the remainder further with small and medium objects.
|
| - uword small_object2 = free_list->TryAllocate(kSmallObjectSize, false);
|
| + uword small_object2 = Allocate(free_list, kSmallObjectSize, is_protected);
|
| EXPECT_EQ(blob + kSmallObjectSize, small_object2);
|
| - uword med_object = free_list->TryAllocate(kMediumObjectSize, false);
|
| + uword med_object = Allocate(free_list, kMediumObjectSize, is_protected);
|
| EXPECT_EQ(small_object2 + kSmallObjectSize, med_object);
|
| // Allocate a large object.
|
| - uword large_object = free_list->TryAllocate(kLargeObjectSize, false);
|
| + uword large_object = Allocate(free_list, kLargeObjectSize, is_protected);
|
| EXPECT_EQ(med_object + kMediumObjectSize, large_object);
|
| // Make sure that small objects can still split the remainder.
|
| - uword small_object3 = free_list->TryAllocate(kSmallObjectSize, false);
|
| + uword small_object3 = Allocate(free_list, kSmallObjectSize, is_protected);
|
| EXPECT_EQ(large_object + kLargeObjectSize, small_object3);
|
| // Split the large object.
|
| - free_list->Free(large_object, kLargeObjectSize);
|
| - uword small_object4 = free_list->TryAllocate(kSmallObjectSize, false);
|
| + Free(free_list, large_object, kLargeObjectSize, is_protected);
|
| + uword small_object4 = Allocate(free_list, kSmallObjectSize, is_protected);
|
| EXPECT_EQ(large_object, small_object4);
|
| // Get the full remainder of the large object.
|
| large_object =
|
| - free_list->TryAllocate(kLargeObjectSize - kSmallObjectSize, false);
|
| + Allocate(free_list, kLargeObjectSize - kSmallObjectSize, is_protected);
|
| EXPECT_EQ(small_object4 + kSmallObjectSize, large_object);
|
| // Get another large object from the large unallocated remainder.
|
| - uword large_object2 = free_list->TryAllocate(kLargeObjectSize, false);
|
| + uword large_object2 = Allocate(free_list, kLargeObjectSize, is_protected);
|
| EXPECT_EQ(small_object3 + kSmallObjectSize, large_object2);
|
| +}
|
| +
|
| +TEST_CASE(FreeList) {
|
| + FreeList* free_list = new FreeList();
|
| + const intptr_t kBlobSize = 1 * MB;
|
| + VirtualMemory* region = VirtualMemory::Reserve(kBlobSize);
|
| + region->Commit(/* is_executable */ false);
|
| +
|
| + TestFreeList(region, free_list, false);
|
| +
|
| + // Delete the memory associated with the test.
|
| + delete region;
|
| + delete free_list;
|
| +}
|
| +
|
| +
|
| +TEST_CASE(FreeListProtected) {
|
| + FreeList* free_list = new FreeList();
|
| + const intptr_t kBlobSize = 1 * MB;
|
| + VirtualMemory* region = VirtualMemory::Reserve(kBlobSize);
|
| + region->Commit(/* is_executable */ false);
|
| +
|
| + TestFreeList(region, free_list, true);
|
| +
|
| + // Delete the memory associated with the test.
|
| + delete region;
|
| + delete free_list;
|
| +}
|
| +
|
| +
|
| +TEST_CASE(FreeListProtectedTinyObjects) {
|
| + FreeList* free_list = new FreeList();
|
| + const intptr_t kBlobSize = 1 * MB;
|
| + const intptr_t kObjectSize = 2 * kWordSize;
|
| + uword* objects = new uword[kBlobSize / kObjectSize];
|
| +
|
| + VirtualMemory* blob = VirtualMemory::ReserveAligned(kBlobSize, 4096);
|
| + blob->Commit(/* is_executable = */ false);
|
| + blob->Protect(VirtualMemory::kReadWrite);
|
| +
|
| + // Enqueue the large blob as one free block.
|
| + free_list->Free(blob->start(), blob->size());
|
| +
|
| + // Write protect the whole region.
|
| + blob->Protect(VirtualMemory::kReadExecute);
|
| +
|
| + // Allocate small objects.
|
| + for (intptr_t i = 0; i < blob->size() / kObjectSize; i++) {
|
| + objects[i] = Allocate(free_list,
|
| + kObjectSize,
|
| + true); // is_protected
|
| + }
|
| +
|
| + // All space is occupied. Expect failed allocation.
|
| + ASSERT(Allocate(free_list, kObjectSize, true) == 0);
|
| +
|
| + // Free all objects again. Make the whole region writable for this.
|
| + blob->Protect(VirtualMemory::kReadWrite);
|
| + for (intptr_t i = 0; i < blob->size() / kObjectSize; i++) {
|
| + free_list->Free(objects[i], kObjectSize);
|
| + }
|
| +
|
| + // Delete the memory associated with the test.
|
| + delete blob;
|
| + delete free_list;
|
| + delete[] objects;
|
| +}
|
| +
|
| +
|
| +TEST_CASE(FreeListProtectedVariableSizeObjects) {
|
| + FreeList* free_list = new FreeList();
|
| + const intptr_t kBlobSize = 8 * KB;
|
| + const intptr_t kMinSize = 2 * kWordSize;
|
| + uword* objects = new uword[kBlobSize / kMinSize];
|
| + for (intptr_t i = 0; i < kBlobSize / kMinSize; ++i) {
|
| + objects[i] = NULL;
|
| + }
|
| +
|
| + VirtualMemory* blob = VirtualMemory::ReserveAligned(kBlobSize, 4096);
|
| + blob->Commit(/* is_executable = */ false);
|
| + blob->Protect(VirtualMemory::kReadWrite);
|
| +
|
| + // Enqueue the large blob as one free block.
|
| + free_list->Free(blob->start(), blob->size());
|
| +
|
| + // Write protect the whole region.
|
| + blob->Protect(VirtualMemory::kReadExecute);
|
| +
|
| + // Allocate and free objects so that free list has > 1 elements.
|
| + uword e0 = Allocate(free_list, 1 * KB, true);
|
| + ASSERT(e0);
|
| + uword e1 = Allocate(free_list, 3 * KB, true);
|
| + ASSERT(e1);
|
| + uword e2 = Allocate(free_list, 2 * KB, true);
|
| + ASSERT(e2);
|
| + uword e3 = Allocate(free_list, 2 * KB, true);
|
| + ASSERT(e3);
|
| +
|
| + Free(free_list, e1, 3 * KB, true);
|
| + Free(free_list, e2, 2 * KB, true);
|
| + e0 = Allocate(free_list, 3 * KB - 2 * kWordSize, true);
|
| + ASSERT(e0);
|
| +
|
| // Delete the memory associated with the test.
|
| - free(reinterpret_cast<void*>(blob));
|
| + delete blob;
|
| delete free_list;
|
| + delete[] objects;
|
| }
|
|
|
| } // namespace dart
|
|
|