Branch data Line data Source code
1 : : // Copyright 2026 HPActor Contributors
2 : : //
3 : : // Licensed under the Apache License, Version 2.0 (the "License");
4 : : // you may not use this file except in compliance with the License.
5 : : // You may obtain a copy of the License at
6 : : //
7 : : // http://www.apache.org/licenses/LICENSE-2.0
8 : : //
9 : : // Unless required by applicable law or agreed to in writing, software
10 : : // distributed under the License is distributed on an "AS IS" BASIS,
11 : : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : // See the License for the specific language governing permissions and
13 : : // limitations under the License.
14 : :
15 : : #pragma once
16 : :
17 : : #include <hpactor/mem/size_class.hpp>
18 : : #include <hpactor/types/types.hpp>
19 : :
20 : : #include <cstddef>
21 : : #include <cstdint>
22 : :
23 : : namespace hpactor::mem {
24 : :
25 : : inline constexpr uint32_t kAllocMagic = 0xAC70AC70;
26 : : inline constexpr uint32_t kFreedMagic = 0xDEADDEAD;
27 : :
28 : : // Forward declaration
29 : : struct AllocHeader;
30 : :
31 : : // ---------------------------------------------------------------------------
32 : : // CanaryFooter: 8-byte canary at the end of every block
33 : : // ---------------------------------------------------------------------------
34 : : // Defined before AllocHeader to avoid circular dependency.
35 : : // from_header() takes the block size explicitly rather than computing it from
36 : : // AllocHeader::block_size(), which would require the complete type.
37 : : struct alignas(8) CanaryFooter {
38 : : uint32_t magic{0};
39 : : uint32_t checksum{0};
40 : :
41 : : static void stamp(AllocHeader* header, size_t block_sz) noexcept;
42 : :
43 : : // block_sz: the total block size (user_size + overhead), from size_for_class()
44 : 1155171 : static CanaryFooter* from_header(AllocHeader* header, size_t block_sz) noexcept {
45 : : return reinterpret_cast<CanaryFooter*>(
46 : 1155171 : reinterpret_cast<std::byte*>(header) + block_sz - sizeof(CanaryFooter));
47 : : }
48 : :
49 : 2 : static bool verify(const AllocHeader* header, size_t block_sz) noexcept {
50 : 2 : auto* f = from_header(const_cast<AllocHeader*>(header), block_sz);
51 : 2 : return f->magic == kAllocMagic;
52 : : }
53 : : };
54 : :
55 : : // ---------------------------------------------------------------------------
56 : : // AllocHeader: 32-byte metadata prefix on every block
57 : : // ---------------------------------------------------------------------------
58 : : struct alignas(32) AllocHeader {
59 : : // owner_id when live; next when freed (freelist linkage via union)
60 : : union {
61 : : uint64_t owner_id;
62 : : AllocHeader* next;
63 : : };
64 : : uint32_t incarnation{0};
65 : : uint32_t magic{kAllocMagic};
66 : : uint8_t size_class{0};
67 : : uint8_t generation{0};
68 : : uint16_t flags{0};
69 : : uint32_t _padding{0};
70 : : uint64_t timestamp{0};
71 : :
72 : 1155168 : static AllocHeader* stamp(void* block, SizeClass sc, ActorId owner) noexcept {
73 : 1155168 : auto* h = static_cast<AllocHeader*>(block);
74 : 1155168 : h->owner_id = owner.value();
75 : 1155168 : h->incarnation = 0;
76 : 1155168 : h->magic = kAllocMagic;
77 : 1155168 : h->size_class = static_cast<uint8_t>(sc);
78 : 1155168 : h->generation = 0;
79 : 1155168 : h->flags = 0;
80 : 1155168 : h->_padding = 0;
81 : 1155168 : h->timestamp = 0;
82 : 1155168 : return h;
83 : : }
84 : :
85 : 1255282 : void* user_data() noexcept {
86 : 1255282 : return reinterpret_cast<std::byte*>(this) + sizeof(AllocHeader);
87 : : }
88 : :
89 : 2309206 : static AllocHeader* from_user_data(void* user_ptr) noexcept {
90 : : return reinterpret_cast<AllocHeader*>(
91 : 2309206 : static_cast<std::byte*>(user_ptr) - sizeof(AllocHeader));
92 : : }
93 : :
94 : 1 : static std::byte* user_ptr(std::byte* block) noexcept {
95 : 1 : return block + sizeof(AllocHeader);
96 : : }
97 : :
98 : : // Returns pointer to the CanaryFooter for this block
99 : 1 : std::byte* footer_ptr() const noexcept {
100 : : return reinterpret_cast<std::byte*>(const_cast<AllocHeader*>(this))
101 : 1 : + block_size() - sizeof(CanaryFooter);
102 : : }
103 : :
104 : 1 : bool is_live() const noexcept { return magic == kAllocMagic; }
105 : 1 : bool is_freed() const noexcept { return magic == kFreedMagic; }
106 : :
107 : 1 : size_t block_size() const noexcept {
108 : 1 : return mem::block_size(static_cast<SizeClass>(size_class));
109 : : }
110 : :
111 : : size_t user_size() const noexcept {
112 : : return mem::size_for_class(static_cast<SizeClass>(size_class));
113 : : }
114 : : };
115 : :
116 : : // Out-of-line because it needs AllocHeader complete type
117 : 1155168 : inline void CanaryFooter::stamp(AllocHeader* header, size_t block_sz) noexcept {
118 : 1155168 : auto* f = from_header(header, block_sz);
119 : 1155168 : f->magic = kAllocMagic;
120 : 1155168 : f->checksum = 0;
121 : 1155168 : }
122 : :
123 : : } // namespace hpactor::mem
|