tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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)