GCC Code Coverage Report


Directory: ../
File: src/util/BlockAllocator.h
Date: 2025-02-05 01:09:36
Exec Total Coverage
Lines: 33 39 84.6%
Functions: 89 91 97.8%
Branches: 19 48 39.6%

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #pragma once
4
5 #include <vector>
6
7 #include <exception/CompilerError.h>
8 #include <util/CommonUtil.h>
9 #include <util/Memory.h>
10
11 namespace spice::compiler {
12
13 template <typename Base> class BlockAllocator {
14 public:
15 // Constructors
16 404 explicit BlockAllocator(const MemoryManager &memoryManager, size_t blockSize = CommonUtil::getSystemPageSize())
17 404 : memoryManager(memoryManager), blockSize(blockSize) {
18
1/2
✓ Branch 0 (5→6) taken 404 times.
✗ Branch 1 (5→7) not taken.
404 allocateNewBlock();
19 404 }
20 404 ~BlockAllocator() {
21 // Destruct all objects
22
2/2
✓ Branch 0 (8→4) taken 1369402 times.
✓ Branch 1 (8→9) taken 404 times.
1369806 for (Base *ptr : allocatedObjects)
23 1369402 ptr->~Base();
24 404 allocatedObjects.clear();
25
26 // Free memory
27
2/2
✓ Branch 0 (16→12) taken 66337 times.
✓ Branch 1 (16→17) taken 404 times.
66741 for (byte *ptr : memoryBlocks)
28 66337 memoryManager.deallocate(ptr);
29 404 memoryBlocks.clear();
30 404 }
31
32 // Public methods
33 1369403 template <typename T, typename... Args> T *allocate(Args &&...args) {
34 static_assert(std::is_base_of_v<Base, T>, "T must be derived from Base");
35 1369403 constexpr size_t objSize = sizeof(T);
36
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 1369403 times.
1369403 assert(objSize <= blockSize && "Object size exceeds block size");
37
38 // Check if we need a new block
39
2/2
✓ Branch 0 (4→5) taken 65934 times.
✓ Branch 1 (4→6) taken 1303469 times.
1369403 if (offsetInBlock + objSize >= blockSize)
40 65934 allocateNewBlock();
41
42 // Construct object at the offset address
43 1369402 byte *destAddr = memoryBlocks.back() + offsetInBlock;
44
1/4
✓ Branch 0 (9→10) taken 249709 times.
✗ Branch 1 (9→15) not taken.
✗ Branch 2 (15→16) not taken.
✗ Branch 3 (15→17) not taken.
1369402 T *ptr = new (destAddr) T(std::forward<Args>(args)...);
45
1/2
✓ Branch 0 (10→11) taken 1369402 times.
✗ Branch 1 (10→15) not taken.
1369402 allocatedObjects.push_back(ptr);
46
47 #ifndef NDEBUG
48
1/2
✓ Branch 0 (12→13) taken 1369402 times.
✗ Branch 1 (12→16) not taken.
1369402 ++allocatedClassStatistic[typeid(T).name()];
49 #endif
50
51 // Update offset to be ready to store the next object
52 1369402 offsetInBlock += objSize;
53 1369402 return ptr;
54 }
55
56 2 [[nodiscard]] size_t getTotalAllocatedSize() const { return memoryBlocks.size() * blockSize; }
57 2 [[nodiscard]] size_t getAllocationCount() const { return allocatedObjects.size(); }
58 #ifndef NDEBUG
59 void printAllocatedClassStatistic() const {
60 std::vector<std::pair<const char *, size_t>> elements(allocatedClassStatistic.begin(), allocatedClassStatistic.end());
61 std::sort(elements.begin(), elements.end(), [](const auto &left, const auto &right) { return left.second > right.second; });
62 for (const auto &[mangledName, count] : elements)
63 std::cout << CommonUtil::demangleTypeName(mangledName) << ": " << count << std::endl;
64 }
65 #endif
66
67 private:
68 // Private members
69 const MemoryManager &memoryManager;
70 std::vector<byte *> memoryBlocks;
71 std::vector<Base *> allocatedObjects;
72 #ifndef NDEBUG
73 std::unordered_map<const char *, size_t> allocatedClassStatistic;
74 #endif
75 size_t blockSize;
76 size_t offsetInBlock = 0;
77
78 // Private methods
79 66338 void allocateNewBlock() {
80 // Allocate new block
81
1/2
✓ Branch 0 (2→3) taken 66338 times.
✗ Branch 1 (2→28) not taken.
66338 byte *ptr = memoryManager.allocate(blockSize);
82
2/2
✓ Branch 0 (3→4) taken 1 times.
✓ Branch 1 (3→14) taken 66337 times.
66338 if (!ptr)
83
2/4
✓ Branch 0 (7→8) taken 1 times.
✗ Branch 1 (7→21) not taken.
✓ Branch 2 (9→10) taken 1 times.
✗ Branch 3 (9→16) not taken.
4 throw CompilerError(OOM, "Could not allocate memory for BlockAllocator. Already allocated " +
84
2/4
✓ Branch 0 (6→7) taken 1 times.
✗ Branch 1 (6→23) not taken.
✓ Branch 2 (8→9) taken 1 times.
✗ Branch 3 (8→19) not taken.
4 std::to_string(memoryBlocks.size()) + " blocks.");
85
86 // Store pointer and reset offset
87
1/2
✓ Branch 0 (14→15) taken 66337 times.
✗ Branch 1 (14→28) not taken.
66337 memoryBlocks.push_back(ptr);
88 66337 offsetInBlock = 0;
89 66337 }
90 };
91
92 } // namespace spice::compiler
93