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;
60 bool pending_free : 1;
63 bool variable_ref : 1;
67 bool stack_variable : 1;
81 u32 size() const noexcept {
82 assert(!variable_ref &&
"variable-ref has no allocation size");
83 return part_count * max_part_size;
88#pragma GCC diagnostic pop
90class AssignmentAllocator {
95 static constexpr size_t SlabSize = 16 * 1024;
97 static constexpr u32 NumFreeLists = 2;
98 static constexpr u32 FirstPartOff = offsetof(ValueAssignment, parts);
101 static constexpr u32 NumPartsIncluded =
102 (
sizeof(ValueAssignment) - FirstPartOff) /
sizeof(ValueAssignment::Part);
107 util::BumpAllocator<SlabSize> alloc;
109 std::array<ValueAssignment *, NumFreeLists> fixed_free_lists{};
112 AssignmentAllocator() noexcept = default;
114 ValueAssignment *allocate(u32 part_count) noexcept {
115 if (part_count > NumPartsIncluded) [[unlikely]] {
116 return allocate_slow(part_count);
118 if (
auto *res = fixed_free_lists[0]) {
119 util::unpoison_memory_region(res,
sizeof(ValueAssignment));
120 fixed_free_lists[0] = res->next_free_list_entry;
123 return new (alloc) ValueAssignment;
126 ValueAssignment *allocate_slow(u32 part_count,
127 bool skip_free_list =
false) noexcept;
129 void deallocate(ValueAssignment *assignment) noexcept {
130 if (assignment->part_count > NumPartsIncluded) [[unlikely]] {
131 deallocate_slow(assignment);
134 assignment->next_free_list_entry = fixed_free_lists[0];
135 fixed_free_lists[0] = assignment;
136 util::poison_memory_region(assignment,
sizeof(ValueAssignment));
139 void deallocate_slow(ValueAssignment *)
noexcept;
141 void reset() noexcept {
143 fixed_free_lists = {};