testSortedArenaList.cpp (4778B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 */ 4 /* This Source Code Form is subject to the terms of the Mozilla Public 5 * License, v. 2.0. If a copy of the MPL was not distributed with this 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 7 8 #include "mozilla/Attributes.h" 9 10 #include "gc/GCLock.h" 11 #include "jsapi-tests/tests.h" 12 13 #include "gc/ArenaList-inl.h" 14 #include "gc/Heap-inl.h" 15 16 using namespace js; 17 using namespace js::gc; 18 19 class TestArenaChunk : public ArenaChunk { 20 public: 21 static TestArenaChunk* init(void* ptr, GCRuntime* gc) { 22 auto* const arenaChunk = 23 static_cast<TestArenaChunk*>(ArenaChunk::init(ptr, gc, true)); 24 arenaChunk->initAsCommitted(); 25 return arenaChunk; 26 } 27 }; 28 29 // Automatically allocate and free an Arena for testing purposes. 30 class MOZ_RAII AutoTestArena { 31 TestArenaChunk* arenaChunk = nullptr; 32 Arena* arena = nullptr; 33 34 public: 35 explicit AutoTestArena(JSContext* cx, AllocKind kind, size_t nfree) { 36 // For testing purposes only. Don't do this in real code! 37 void* const arenaChunkPtr = 38 TestArenaChunk::allocate(&cx->runtime()->gc, StallAndRetry::No); 39 MOZ_RELEASE_ASSERT(arenaChunkPtr); 40 arenaChunk = TestArenaChunk::init(arenaChunkPtr, &cx->runtime()->gc); 41 42 arena = arenaChunk->fetchNextFreeArena(&cx->runtime()->gc); 43 MOZ_RELEASE_ASSERT(arena); 44 45 arena->init(&cx->runtime()->gc, cx->zone(), kind); 46 47 size_t nallocs = Arena::thingsPerArena(kind) - nfree; 48 size_t thingSize = Arena::thingSize(kind); 49 for (size_t i = 0; i < nallocs; i++) { 50 MOZ_RELEASE_ASSERT(arena->getFirstFreeSpan()->allocate(thingSize)); 51 } 52 MOZ_RELEASE_ASSERT(arena->countFreeCells() == nfree); 53 } 54 55 ~AutoTestArena() { UnmapPages(arenaChunk, ChunkSize); } 56 57 Arena* get() { return arena; } 58 operator Arena*() { return arena; } 59 Arena* operator->() { return arena; } 60 }; 61 62 BEGIN_TEST(testSortedArenaList) { 63 const AllocKind kind = AllocKind::OBJECT0; 64 65 // Test empty list. 66 67 SortedArenaList sortedList(kind); 68 CHECK(sortedList.thingsPerArena() == Arena::thingsPerArena(kind)); 69 70 CHECK(ConvertToArenaList(kind, sortedList, 0)); 71 72 // Test with single non-empty arena. 73 74 size_t thingsPerArena = Arena::thingsPerArena(kind); 75 for (size_t i = 0; i != thingsPerArena; i++) { 76 AutoTestArena arena(cx, kind, i); 77 sortedList.insertAt(arena.get(), i); 78 79 CHECK(ConvertToArenaList(kind, sortedList, 1, nullptr, arena.get())); 80 } 81 82 // Test with single empty arena. 83 84 AutoTestArena arena(cx, kind, thingsPerArena); 85 sortedList.insertAt(arena.get(), thingsPerArena); 86 87 CHECK(ConvertToArenaList(kind, sortedList, 0, arena.get())); 88 89 // Test with full and non-full arenas. 90 91 AutoTestArena fullArena(cx, kind, 0); 92 AutoTestArena nonFullArena(cx, kind, 1); 93 sortedList.insertAt(fullArena.get(), 0); 94 sortedList.insertAt(nonFullArena.get(), 1); 95 96 CHECK(ConvertToArenaList(kind, sortedList, 2, nullptr, nonFullArena.get(), 97 fullArena.get())); 98 99 return true; 100 } 101 102 bool ConvertToArenaList(AllocKind kind, SortedArenaList& sortedList, 103 size_t expectedBucketCount, 104 Arena* expectedEmpty = nullptr, 105 Arena* expectedFirst = nullptr, 106 Arena* expectedLast = nullptr) { 107 CHECK(ConvertToArenaListOnce(sortedList, expectedBucketCount, expectedEmpty, 108 expectedFirst, expectedLast)); 109 110 // Check again to test restoreFromArenaList restored the original state 111 // (except for the empty arenas which are not restored). 112 CHECK(ConvertToArenaListOnce(sortedList, expectedBucketCount, nullptr, 113 expectedFirst, expectedLast)); 114 115 // Clear the list on exit. 116 new (&sortedList) SortedArenaList(kind); 117 118 return true; 119 } 120 121 bool ConvertToArenaListOnce(SortedArenaList& sortedList, 122 size_t expectedBucketCount, Arena* expectedEmpty, 123 Arena* expectedFirst, Arena* expectedLast) { 124 Arena* emptyArenas = nullptr; 125 sortedList.extractEmptyTo(&emptyArenas); 126 CHECK(emptyArenas == expectedEmpty); 127 128 Arena* bucketLast[SortedArenaList::BucketCount]; 129 ArenaList list = sortedList.convertToArenaList(bucketLast); 130 CHECK(list.isEmpty() == (expectedBucketCount == 0)); 131 if (expectedFirst) { 132 CHECK(list.getFirst() == expectedFirst); 133 } 134 if (expectedLast) { 135 CHECK(list.getLast() == expectedLast); 136 } 137 138 size_t count = 0; 139 for (size_t j = 0; j < SortedArenaList::BucketCount; j++) { 140 if (bucketLast[j]) { 141 count++; 142 } 143 } 144 CHECK(count == expectedBucketCount); 145 146 sortedList.restoreFromArenaList(list, bucketLast); 147 CHECK(list.isEmpty()); 148 149 return true; 150 } 151 END_TEST(testSortedArenaList)