5#include "tpde/ValLocalIdx.hpp"
6#include "tpde/base.hpp"
7#include "tpde/util/AddressSanitizer.hpp"
8#include "tpde/util/BumpAllocator.hpp"
17#pragma GCC diagnostic push
18#pragma GCC diagnostic ignored "-Wpedantic"
22#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 15
31struct ValueAssignment {
40 u32 var_ref_custom_idx;
48 ValueAssignment *next_free_list_entry;
52 ValLocalIdx next_delayed_free_entry;
59 bool pending_free : 1;
62 bool variable_ref : 1;
66 bool stack_variable : 1;
80 u32 size() const noexcept {
81 assert(!variable_ref &&
"variable-ref has no allocation size");
82 return part_count * max_part_size;
87#pragma GCC diagnostic pop
89class AssignmentAllocator {
94 static constexpr size_t SlabSize = 16 * 1024;
96 static constexpr u32 NumFreeLists = 2;
97 static constexpr u32 FirstPartOff = offsetof(ValueAssignment, parts);
100 static constexpr u32 NumPartsIncluded =
101 (
sizeof(ValueAssignment) - FirstPartOff) /
sizeof(ValueAssignment::Part);
106 util::BumpAllocator<SlabSize> alloc;
108 std::array<ValueAssignment *, NumFreeLists> fixed_free_lists{};
111 AssignmentAllocator() noexcept = default;
113 ValueAssignment *allocate(u32 part_count) noexcept {
114 if (part_count > NumPartsIncluded) [[unlikely]] {
115 return allocate_slow(part_count);
117 if (
auto *res = fixed_free_lists[0]) {
118 util::unpoison_memory_region(res,
sizeof(ValueAssignment));
119 fixed_free_lists[0] = res->next_free_list_entry;
122 return new (alloc) ValueAssignment;
125 ValueAssignment *allocate_slow(u32 part_count,
126 bool skip_free_list =
false) noexcept;
128 void deallocate(ValueAssignment *assignment) noexcept {
129 if (assignment->part_count > NumPartsIncluded) [[unlikely]] {
130 deallocate_slow(assignment);
133 assignment->next_free_list_entry = fixed_free_lists[0];
134 fixed_free_lists[0] = assignment;
135 util::poison_memory_region(assignment,
sizeof(ValueAssignment));
138 void deallocate_slow(ValueAssignment *)
noexcept;
140 void reset() noexcept {
142 fixed_free_lists = {};