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;
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;
100 static constexpr u32 NumFreeLists = 29;
101 static constexpr u32 FirstPartOff = offsetof(ValueAssignment, parts);
104 static constexpr u32 NumPartsIncluded =
105 (
sizeof(ValueAssignment) - FirstPartOff) /
sizeof(ValueAssignment::Part);
110 util::BumpAllocator<SlabSize> alloc;
112 std::array<ValueAssignment *, NumFreeLists> fixed_free_lists{};
115 AssignmentAllocator() =
default;
117 ValueAssignment *allocate(u32 part_count) {
118 if (part_count > NumPartsIncluded) [[unlikely]] {
119 return allocate_slow(part_count);
121 if (
auto *res = fixed_free_lists[0]) {
122 util::unpoison_memory_region(res,
sizeof(ValueAssignment));
123 fixed_free_lists[0] = res->next_free_list_entry;
126 return new (alloc) ValueAssignment;
129 ValueAssignment *allocate_slow(u32 part_count,
bool skip_free_list =
false);
131 void deallocate(ValueAssignment *assignment) {
132 if (assignment->part_count > NumPartsIncluded) [[unlikely]] {
133 deallocate_slow(assignment);
136 assignment->next_free_list_entry = fixed_free_lists[0];
137 fixed_free_lists[0] = assignment;
138 util::poison_memory_region(assignment,
sizeof(ValueAssignment));
141 void deallocate_slow(ValueAssignment *);
145 fixed_free_lists = {};