Coverage Report

Created: 2026-08-25 19:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/support/allocators/pool.h
Line
Count
Source
1
// Copyright (c) 2022-present The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#ifndef BITCOIN_SUPPORT_ALLOCATORS_POOL_H
6
#define BITCOIN_SUPPORT_ALLOCATORS_POOL_H
7
8
#include <array>
9
#include <cassert>
10
#include <cstddef>
11
#include <list>
12
#include <memory>
13
#include <new>
14
#include <type_traits>
15
#include <utility>
16
17
#include <util/check.h>
18
#include <util/overflow.h>
19
20
/**
21
 * A memory resource similar to std::pmr::unsynchronized_pool_resource, but
22
 * optimized for node-based containers. It has the following properties:
23
 *
24
 * * Owns the allocated memory and frees it on destruction, even when deallocate
25
 *   has not been called on the allocated blocks.
26
 *
27
 * * Consists of a number of pools, each one for a different block size.
28
 *   Each pool holds blocks of uniform size in a freelist.
29
 *
30
 * * Exhausting memory in a freelist causes a new allocation of a fixed size chunk.
31
 *   This chunk is used to carve out blocks.
32
 *
33
 * * Block sizes or alignments that can not be served by the pools are allocated
34
 *   and deallocated by operator new().
35
 *
36
 * PoolResource is not thread-safe. It is intended to be used by PoolAllocator.
37
 *
38
 * @tparam MAX_BLOCK_SIZE_BYTES Maximum size to allocate with the pool. If larger
39
 *         sizes are requested, allocation falls back to new().
40
 *
41
 * @tparam ALIGN_BYTES Required alignment for the allocations.
42
 *
43
 * An example: If you create a PoolResource<128, 8>(262144) and perform a bunch of
44
 * allocations and deallocate 2 blocks with size 8 bytes, and 3 blocks with size 16,
45
 * the members will look like this:
46
 *
47
 *     m_free_lists                         m_allocated_chunks
48
 *        ┌───┐                                ┌───┐  ┌────────────-------──────┐
49
 *        │   │  blocks                        │   ├─►│    262144 B             │
50
 *        │   │  ┌─────┐  ┌─────┐              └─┬─┘  └────────────-------──────┘
51
 *        │ 1 ├─►│ 8 B ├─►│ 8 B │                │
52
 *        │   │  └─────┘  └─────┘                :
53
 *        │   │                                  │
54
 *        │   │  ┌─────┐  ┌─────┐  ┌─────┐       ▼
55
 *        │ 2 ├─►│16 B ├─►│16 B ├─►│16 B │     ┌───┐  ┌─────────────────────────┐
56
 *        │   │  └─────┘  └─────┘  └─────┘     │   ├─►│          ▲              │ ▲
57
 *        │   │                                └───┘  └──────────┬──────────────┘ │
58
 *        │ . │                                                  │    m_available_memory_end
59
 *        │ . │                                         m_available_memory_it
60
 *        │ . │
61
 *        │   │
62
 *        │   │
63
 *        │16 │
64
 *        └───┘
65
 *
66
 * Here m_free_lists[1] holds the 2 blocks of size 8 bytes, and m_free_lists[2]
67
 * holds the 3 blocks of size 16. The blocks came from the data stored in the
68
 * m_allocated_chunks list. Each chunk has bytes 262144. The last chunk has still
69
 * some memory available for the blocks, and when m_available_memory_it is at the
70
 * end, a new chunk will be allocated and added to the list.
71
 */
72
template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
73
class PoolResource final
74
{
75
    static_assert(ALIGN_BYTES > 0, "ALIGN_BYTES must be nonzero");
76
    static_assert((ALIGN_BYTES & (ALIGN_BYTES - 1)) == 0, "ALIGN_BYTES must be a power of two");
77
78
    /**
79
     * In-place linked list of the allocations, used for the freelist.
80
     */
81
    struct ListNode {
82
        ListNode* m_next;
83
84
25.6M
        explicit ListNode(ListNode* next) : m_next(next) {}
_ZN12PoolResourceILm152ELm8EE8ListNodeC2EPS1_
Line
Count
Source
84
24.4M
        explicit ListNode(ListNode* next) : m_next(next) {}
_ZN12PoolResourceILm128ELm1EE8ListNodeC2EPS1_
Line
Count
Source
84
167k
        explicit ListNode(ListNode* next) : m_next(next) {}
_ZN12PoolResourceILm128ELm2EE8ListNodeC2EPS1_
Line
Count
Source
84
191k
        explicit ListNode(ListNode* next) : m_next(next) {}
_ZN12PoolResourceILm128ELm4EE8ListNodeC2EPS1_
Line
Count
Source
84
150k
        explicit ListNode(ListNode* next) : m_next(next) {}
_ZN12PoolResourceILm128ELm8EE8ListNodeC2EPS1_
Line
Count
Source
84
165k
        explicit ListNode(ListNode* next) : m_next(next) {}
_ZN12PoolResourceILm8ELm8EE8ListNodeC2EPS1_
Line
Count
Source
84
56.0k
        explicit ListNode(ListNode* next) : m_next(next) {}
_ZN12PoolResourceILm16ELm16EE8ListNodeC2EPS1_
Line
Count
Source
84
92.3k
        explicit ListNode(ListNode* next) : m_next(next) {}
_ZN12PoolResourceILm256ELm16EE8ListNodeC2EPS1_
Line
Count
Source
84
117k
        explicit ListNode(ListNode* next) : m_next(next) {}
_ZN12PoolResourceILm256ELm64EE8ListNodeC2EPS1_
Line
Count
Source
84
280k
        explicit ListNode(ListNode* next) : m_next(next) {}
85
    };
86
    static_assert(std::is_trivially_destructible_v<ListNode>, "Make sure we don't need to manually call a destructor");
87
88
    /**
89
     * Internal alignment value. The larger of the requested ALIGN_BYTES and alignof(FreeList).
90
     */
91
    static constexpr std::size_t ELEM_ALIGN_BYTES = std::max(alignof(ListNode), ALIGN_BYTES);
92
    static_assert((ELEM_ALIGN_BYTES & (ELEM_ALIGN_BYTES - 1)) == 0, "ELEM_ALIGN_BYTES must be a power of two");
93
    static_assert(sizeof(ListNode) <= ELEM_ALIGN_BYTES, "Units of size ELEM_SIZE_ALIGN need to be able to store a ListNode");
94
    static_assert((MAX_BLOCK_SIZE_BYTES & (ELEM_ALIGN_BYTES - 1)) == 0, "MAX_BLOCK_SIZE_BYTES needs to be a multiple of the alignment.");
95
96
    /**
97
     * Size in bytes to allocate per chunk
98
     */
99
    const size_t m_chunk_size_bytes;
100
101
    /**
102
     * Contains all allocated pools of memory, used to free the data in the destructor.
103
     */
104
    std::list<std::byte*> m_allocated_chunks{};
105
106
    /**
107
     * Single linked lists of all data that came from deallocating.
108
     * m_free_lists[n] will serve blocks of size n*ELEM_ALIGN_BYTES.
109
     */
110
    std::array<ListNode*, MAX_BLOCK_SIZE_BYTES / ELEM_ALIGN_BYTES + 1> m_free_lists{};
111
112
    /**
113
     * Points to the beginning of available memory for carving out allocations.
114
     */
115
    std::byte* m_available_memory_it = nullptr;
116
117
    /**
118
     * Points to the end of available memory for carving out allocations.
119
     *
120
     * That member variable is redundant, and is always equal to `m_allocated_chunks.back() + m_chunk_size_bytes`
121
     * whenever it is accessed, but `m_available_memory_end` caches this for clarity and efficiency.
122
     */
123
    std::byte* m_available_memory_end = nullptr;
124
125
    /**
126
     * How many multiple of ELEM_ALIGN_BYTES are necessary to fit bytes. We use that result directly as an index
127
     * into m_free_lists. Round up for the special case when bytes==0.
128
     */
129
    [[nodiscard]] static constexpr std::size_t NumElemAlignBytes(std::size_t bytes)
130
56.8M
    {
131
56.8M
        return CeilDiv(bytes, ELEM_ALIGN_BYTES) + (bytes == 0);
132
56.8M
    }
_ZN12PoolResourceILm152ELm8EE17NumElemAlignBytesEm
Line
Count
Source
130
55.1M
    {
131
55.1M
        return CeilDiv(bytes, ELEM_ALIGN_BYTES) + (bytes == 0);
132
55.1M
    }
_ZN12PoolResourceILm128ELm1EE17NumElemAlignBytesEm
Line
Count
Source
130
241k
    {
131
241k
        return CeilDiv(bytes, ELEM_ALIGN_BYTES) + (bytes == 0);
132
241k
    }
_ZN12PoolResourceILm128ELm2EE17NumElemAlignBytesEm
Line
Count
Source
130
270k
    {
131
270k
        return CeilDiv(bytes, ELEM_ALIGN_BYTES) + (bytes == 0);
132
270k
    }
_ZN12PoolResourceILm128ELm4EE17NumElemAlignBytesEm
Line
Count
Source
130
188k
    {
131
188k
        return CeilDiv(bytes, ELEM_ALIGN_BYTES) + (bytes == 0);
132
188k
    }
_ZN12PoolResourceILm128ELm8EE17NumElemAlignBytesEm
Line
Count
Source
130
220k
    {
131
220k
        return CeilDiv(bytes, ELEM_ALIGN_BYTES) + (bytes == 0);
132
220k
    }
_ZN12PoolResourceILm8ELm8EE17NumElemAlignBytesEm
Line
Count
Source
130
112k
    {
131
112k
        return CeilDiv(bytes, ELEM_ALIGN_BYTES) + (bytes == 0);
132
112k
    }
_ZN12PoolResourceILm16ELm16EE17NumElemAlignBytesEm
Line
Count
Source
130
184k
    {
131
184k
        return CeilDiv(bytes, ELEM_ALIGN_BYTES) + (bytes == 0);
132
184k
    }
_ZN12PoolResourceILm256ELm16EE17NumElemAlignBytesEm
Line
Count
Source
130
158k
    {
131
158k
        return CeilDiv(bytes, ELEM_ALIGN_BYTES) + (bytes == 0);
132
158k
    }
_ZN12PoolResourceILm256ELm64EE17NumElemAlignBytesEm
Line
Count
Source
130
347k
    {
131
347k
        return CeilDiv(bytes, ELEM_ALIGN_BYTES) + (bytes == 0);
132
347k
    }
133
134
    /**
135
     * True when it is possible to make use of the freelist
136
     */
137
    [[nodiscard]] static constexpr bool IsFreeListUsable(std::size_t bytes, std::size_t alignment)
138
51.1M
    {
139
51.1M
        return alignment <= ELEM_ALIGN_BYTES && bytes <= MAX_BLOCK_SIZE_BYTES;
  Branch (139:16): [True: 49.2M, False: 0]
  Branch (139:49): [True: 48.9M, False: 355k]
  Branch (139:16): [True: 252k, False: 4.49k]
  Branch (139:49): [True: 241k, False: 11.1k]
  Branch (139:16): [True: 283k, False: 5.86k]
  Branch (139:49): [True: 270k, False: 13.3k]
  Branch (139:16): [True: 210k, False: 6.80k]
  Branch (139:49): [True: 188k, False: 22.4k]
  Branch (139:16): [True: 230k, False: 2.93k]
  Branch (139:49): [True: 219k, False: 10.2k]
  Branch (139:16): [True: 125k, False: 3.13k]
  Branch (139:49): [True: 112k, False: 12.9k]
  Branch (139:16): [True: 203k, False: 4.03k]
  Branch (139:49): [True: 184k, False: 19.0k]
  Branch (139:16): [True: 163k, False: 2.12k]
  Branch (139:49): [True: 158k, False: 5.49k]
  Branch (139:16): [True: 354k, False: 1.28k]
  Branch (139:49): [True: 347k, False: 6.86k]
140
51.1M
    }
_ZN12PoolResourceILm152ELm8EE16IsFreeListUsableEmm
Line
Count
Source
138
49.2M
    {
139
49.2M
        return alignment <= ELEM_ALIGN_BYTES && bytes <= MAX_BLOCK_SIZE_BYTES;
  Branch (139:16): [True: 49.2M, False: 0]
  Branch (139:49): [True: 48.9M, False: 355k]
140
49.2M
    }
_ZN12PoolResourceILm128ELm1EE16IsFreeListUsableEmm
Line
Count
Source
138
257k
    {
139
257k
        return alignment <= ELEM_ALIGN_BYTES && bytes <= MAX_BLOCK_SIZE_BYTES;
  Branch (139:16): [True: 252k, False: 4.49k]
  Branch (139:49): [True: 241k, False: 11.1k]
140
257k
    }
_ZN12PoolResourceILm128ELm2EE16IsFreeListUsableEmm
Line
Count
Source
138
289k
    {
139
289k
        return alignment <= ELEM_ALIGN_BYTES && bytes <= MAX_BLOCK_SIZE_BYTES;
  Branch (139:16): [True: 283k, False: 5.86k]
  Branch (139:49): [True: 270k, False: 13.3k]
140
289k
    }
_ZN12PoolResourceILm128ELm4EE16IsFreeListUsableEmm
Line
Count
Source
138
217k
    {
139
217k
        return alignment <= ELEM_ALIGN_BYTES && bytes <= MAX_BLOCK_SIZE_BYTES;
  Branch (139:16): [True: 210k, False: 6.80k]
  Branch (139:49): [True: 188k, False: 22.4k]
140
217k
    }
_ZN12PoolResourceILm128ELm8EE16IsFreeListUsableEmm
Line
Count
Source
138
233k
    {
139
233k
        return alignment <= ELEM_ALIGN_BYTES && bytes <= MAX_BLOCK_SIZE_BYTES;
  Branch (139:16): [True: 230k, False: 2.93k]
  Branch (139:49): [True: 219k, False: 10.2k]
140
233k
    }
_ZN12PoolResourceILm8ELm8EE16IsFreeListUsableEmm
Line
Count
Source
138
128k
    {
139
128k
        return alignment <= ELEM_ALIGN_BYTES && bytes <= MAX_BLOCK_SIZE_BYTES;
  Branch (139:16): [True: 125k, False: 3.13k]
  Branch (139:49): [True: 112k, False: 12.9k]
140
128k
    }
_ZN12PoolResourceILm16ELm16EE16IsFreeListUsableEmm
Line
Count
Source
138
207k
    {
139
207k
        return alignment <= ELEM_ALIGN_BYTES && bytes <= MAX_BLOCK_SIZE_BYTES;
  Branch (139:16): [True: 203k, False: 4.03k]
  Branch (139:49): [True: 184k, False: 19.0k]
140
207k
    }
_ZN12PoolResourceILm256ELm16EE16IsFreeListUsableEmm
Line
Count
Source
138
165k
    {
139
165k
        return alignment <= ELEM_ALIGN_BYTES && bytes <= MAX_BLOCK_SIZE_BYTES;
  Branch (139:16): [True: 163k, False: 2.12k]
  Branch (139:49): [True: 158k, False: 5.49k]
140
165k
    }
_ZN12PoolResourceILm256ELm64EE16IsFreeListUsableEmm
Line
Count
Source
138
355k
    {
139
355k
        return alignment <= ELEM_ALIGN_BYTES && bytes <= MAX_BLOCK_SIZE_BYTES;
  Branch (139:16): [True: 354k, False: 1.28k]
  Branch (139:49): [True: 347k, False: 6.86k]
140
355k
    }
141
142
    /**
143
     * Replaces node with placement constructed ListNode that points to the previous node
144
     */
145
    void PlacementAddToList(void* p, ListNode*& node)
146
25.6M
    {
147
25.6M
        node = new (p) ListNode{node};
148
25.6M
    }
_ZN12PoolResourceILm152ELm8EE18PlacementAddToListEPvRPNS0_8ListNodeE
Line
Count
Source
146
24.4M
    {
147
24.4M
        node = new (p) ListNode{node};
148
24.4M
    }
_ZN12PoolResourceILm128ELm1EE18PlacementAddToListEPvRPNS0_8ListNodeE
Line
Count
Source
146
167k
    {
147
167k
        node = new (p) ListNode{node};
148
167k
    }
_ZN12PoolResourceILm128ELm2EE18PlacementAddToListEPvRPNS0_8ListNodeE
Line
Count
Source
146
191k
    {
147
191k
        node = new (p) ListNode{node};
148
191k
    }
_ZN12PoolResourceILm128ELm4EE18PlacementAddToListEPvRPNS0_8ListNodeE
Line
Count
Source
146
150k
    {
147
150k
        node = new (p) ListNode{node};
148
150k
    }
_ZN12PoolResourceILm128ELm8EE18PlacementAddToListEPvRPNS0_8ListNodeE
Line
Count
Source
146
165k
    {
147
165k
        node = new (p) ListNode{node};
148
165k
    }
_ZN12PoolResourceILm8ELm8EE18PlacementAddToListEPvRPNS0_8ListNodeE
Line
Count
Source
146
56.0k
    {
147
56.0k
        node = new (p) ListNode{node};
148
56.0k
    }
_ZN12PoolResourceILm16ELm16EE18PlacementAddToListEPvRPNS0_8ListNodeE
Line
Count
Source
146
92.3k
    {
147
92.3k
        node = new (p) ListNode{node};
148
92.3k
    }
_ZN12PoolResourceILm256ELm16EE18PlacementAddToListEPvRPNS0_8ListNodeE
Line
Count
Source
146
117k
    {
147
117k
        node = new (p) ListNode{node};
148
117k
    }
_ZN12PoolResourceILm256ELm64EE18PlacementAddToListEPvRPNS0_8ListNodeE
Line
Count
Source
146
280k
    {
147
280k
        node = new (p) ListNode{node};
148
280k
    }
149
150
    /**
151
     * Allocate one full memory chunk which will be used to carve out allocations.
152
     * Also puts any leftover bytes into the freelist.
153
     *
154
     * Precondition: leftover bytes are either 0 or few enough to fit into a place in the freelist
155
     */
156
    void AllocateChunk()
157
6.70M
    {
158
        // if there is still any available memory left, put it into the freelist.
159
6.70M
        size_t remaining_available_bytes = m_available_memory_end - m_available_memory_it;
160
6.70M
        if (0 != remaining_available_bytes) {
  Branch (160:13): [True: 449, False: 6.22M]
  Branch (160:13): [True: 47.2k, False: 4.29k]
  Branch (160:13): [True: 55.9k, False: 4.91k]
  Branch (160:13): [True: 56.1k, False: 2.43k]
  Branch (160:13): [True: 55.1k, False: 1.93k]
  Branch (160:13): [True: 0, False: 27.2k]
  Branch (160:13): [True: 0, False: 66.1k]
  Branch (160:13): [True: 38.1k, False: 5.46k]
  Branch (160:13): [True: 107k, False: 10.0k]
161
360k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
162
360k
            PlacementAddToList(m_available_memory_it, m_free_lists[remaining_available_bytes / ELEM_ALIGN_BYTES]);
163
360k
            ASAN_POISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
164
360k
        }
165
166
6.70M
        void* storage = ::operator new (m_chunk_size_bytes, std::align_val_t{ELEM_ALIGN_BYTES});
167
6.70M
        m_available_memory_it = new (storage) std::byte[m_chunk_size_bytes];
168
6.70M
        m_available_memory_end = m_available_memory_it + m_chunk_size_bytes;
169
6.70M
        ASAN_POISON_MEMORY_REGION(m_available_memory_it, m_chunk_size_bytes);
170
6.70M
        m_allocated_chunks.emplace_back(m_available_memory_it);
171
6.70M
    }
_ZN12PoolResourceILm152ELm8EE13AllocateChunkEv
Line
Count
Source
157
6.22M
    {
158
        // if there is still any available memory left, put it into the freelist.
159
6.22M
        size_t remaining_available_bytes = m_available_memory_end - m_available_memory_it;
160
6.22M
        if (0 != remaining_available_bytes) {
  Branch (160:13): [True: 449, False: 6.22M]
161
449
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
162
449
            PlacementAddToList(m_available_memory_it, m_free_lists[remaining_available_bytes / ELEM_ALIGN_BYTES]);
163
449
            ASAN_POISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
164
449
        }
165
166
6.22M
        void* storage = ::operator new (m_chunk_size_bytes, std::align_val_t{ELEM_ALIGN_BYTES});
167
6.22M
        m_available_memory_it = new (storage) std::byte[m_chunk_size_bytes];
168
6.22M
        m_available_memory_end = m_available_memory_it + m_chunk_size_bytes;
169
6.22M
        ASAN_POISON_MEMORY_REGION(m_available_memory_it, m_chunk_size_bytes);
170
6.22M
        m_allocated_chunks.emplace_back(m_available_memory_it);
171
6.22M
    }
_ZN12PoolResourceILm128ELm1EE13AllocateChunkEv
Line
Count
Source
157
51.4k
    {
158
        // if there is still any available memory left, put it into the freelist.
159
51.4k
        size_t remaining_available_bytes = m_available_memory_end - m_available_memory_it;
160
51.4k
        if (0 != remaining_available_bytes) {
  Branch (160:13): [True: 47.2k, False: 4.29k]
161
47.2k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
162
47.2k
            PlacementAddToList(m_available_memory_it, m_free_lists[remaining_available_bytes / ELEM_ALIGN_BYTES]);
163
47.2k
            ASAN_POISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
164
47.2k
        }
165
166
51.4k
        void* storage = ::operator new (m_chunk_size_bytes, std::align_val_t{ELEM_ALIGN_BYTES});
167
51.4k
        m_available_memory_it = new (storage) std::byte[m_chunk_size_bytes];
168
51.4k
        m_available_memory_end = m_available_memory_it + m_chunk_size_bytes;
169
51.4k
        ASAN_POISON_MEMORY_REGION(m_available_memory_it, m_chunk_size_bytes);
170
51.4k
        m_allocated_chunks.emplace_back(m_available_memory_it);
171
51.4k
    }
_ZN12PoolResourceILm128ELm2EE13AllocateChunkEv
Line
Count
Source
157
60.8k
    {
158
        // if there is still any available memory left, put it into the freelist.
159
60.8k
        size_t remaining_available_bytes = m_available_memory_end - m_available_memory_it;
160
60.8k
        if (0 != remaining_available_bytes) {
  Branch (160:13): [True: 55.9k, False: 4.91k]
161
55.9k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
162
55.9k
            PlacementAddToList(m_available_memory_it, m_free_lists[remaining_available_bytes / ELEM_ALIGN_BYTES]);
163
55.9k
            ASAN_POISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
164
55.9k
        }
165
166
60.8k
        void* storage = ::operator new (m_chunk_size_bytes, std::align_val_t{ELEM_ALIGN_BYTES});
167
60.8k
        m_available_memory_it = new (storage) std::byte[m_chunk_size_bytes];
168
60.8k
        m_available_memory_end = m_available_memory_it + m_chunk_size_bytes;
169
60.8k
        ASAN_POISON_MEMORY_REGION(m_available_memory_it, m_chunk_size_bytes);
170
60.8k
        m_allocated_chunks.emplace_back(m_available_memory_it);
171
60.8k
    }
_ZN12PoolResourceILm128ELm4EE13AllocateChunkEv
Line
Count
Source
157
58.6k
    {
158
        // if there is still any available memory left, put it into the freelist.
159
58.6k
        size_t remaining_available_bytes = m_available_memory_end - m_available_memory_it;
160
58.6k
        if (0 != remaining_available_bytes) {
  Branch (160:13): [True: 56.1k, False: 2.43k]
161
56.1k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
162
56.1k
            PlacementAddToList(m_available_memory_it, m_free_lists[remaining_available_bytes / ELEM_ALIGN_BYTES]);
163
56.1k
            ASAN_POISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
164
56.1k
        }
165
166
58.6k
        void* storage = ::operator new (m_chunk_size_bytes, std::align_val_t{ELEM_ALIGN_BYTES});
167
58.6k
        m_available_memory_it = new (storage) std::byte[m_chunk_size_bytes];
168
58.6k
        m_available_memory_end = m_available_memory_it + m_chunk_size_bytes;
169
58.6k
        ASAN_POISON_MEMORY_REGION(m_available_memory_it, m_chunk_size_bytes);
170
58.6k
        m_allocated_chunks.emplace_back(m_available_memory_it);
171
58.6k
    }
_ZN12PoolResourceILm128ELm8EE13AllocateChunkEv
Line
Count
Source
157
57.0k
    {
158
        // if there is still any available memory left, put it into the freelist.
159
57.0k
        size_t remaining_available_bytes = m_available_memory_end - m_available_memory_it;
160
57.0k
        if (0 != remaining_available_bytes) {
  Branch (160:13): [True: 55.1k, False: 1.93k]
161
55.1k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
162
55.1k
            PlacementAddToList(m_available_memory_it, m_free_lists[remaining_available_bytes / ELEM_ALIGN_BYTES]);
163
55.1k
            ASAN_POISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
164
55.1k
        }
165
166
57.0k
        void* storage = ::operator new (m_chunk_size_bytes, std::align_val_t{ELEM_ALIGN_BYTES});
167
57.0k
        m_available_memory_it = new (storage) std::byte[m_chunk_size_bytes];
168
57.0k
        m_available_memory_end = m_available_memory_it + m_chunk_size_bytes;
169
57.0k
        ASAN_POISON_MEMORY_REGION(m_available_memory_it, m_chunk_size_bytes);
170
57.0k
        m_allocated_chunks.emplace_back(m_available_memory_it);
171
57.0k
    }
_ZN12PoolResourceILm8ELm8EE13AllocateChunkEv
Line
Count
Source
157
27.2k
    {
158
        // if there is still any available memory left, put it into the freelist.
159
27.2k
        size_t remaining_available_bytes = m_available_memory_end - m_available_memory_it;
160
27.2k
        if (0 != remaining_available_bytes) {
  Branch (160:13): [True: 0, False: 27.2k]
161
0
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
162
0
            PlacementAddToList(m_available_memory_it, m_free_lists[remaining_available_bytes / ELEM_ALIGN_BYTES]);
163
0
            ASAN_POISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
164
0
        }
165
166
27.2k
        void* storage = ::operator new (m_chunk_size_bytes, std::align_val_t{ELEM_ALIGN_BYTES});
167
27.2k
        m_available_memory_it = new (storage) std::byte[m_chunk_size_bytes];
168
27.2k
        m_available_memory_end = m_available_memory_it + m_chunk_size_bytes;
169
27.2k
        ASAN_POISON_MEMORY_REGION(m_available_memory_it, m_chunk_size_bytes);
170
27.2k
        m_allocated_chunks.emplace_back(m_available_memory_it);
171
27.2k
    }
_ZN12PoolResourceILm16ELm16EE13AllocateChunkEv
Line
Count
Source
157
66.1k
    {
158
        // if there is still any available memory left, put it into the freelist.
159
66.1k
        size_t remaining_available_bytes = m_available_memory_end - m_available_memory_it;
160
66.1k
        if (0 != remaining_available_bytes) {
  Branch (160:13): [True: 0, False: 66.1k]
161
0
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
162
0
            PlacementAddToList(m_available_memory_it, m_free_lists[remaining_available_bytes / ELEM_ALIGN_BYTES]);
163
0
            ASAN_POISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
164
0
        }
165
166
66.1k
        void* storage = ::operator new (m_chunk_size_bytes, std::align_val_t{ELEM_ALIGN_BYTES});
167
66.1k
        m_available_memory_it = new (storage) std::byte[m_chunk_size_bytes];
168
66.1k
        m_available_memory_end = m_available_memory_it + m_chunk_size_bytes;
169
66.1k
        ASAN_POISON_MEMORY_REGION(m_available_memory_it, m_chunk_size_bytes);
170
66.1k
        m_allocated_chunks.emplace_back(m_available_memory_it);
171
66.1k
    }
_ZN12PoolResourceILm256ELm16EE13AllocateChunkEv
Line
Count
Source
157
43.5k
    {
158
        // if there is still any available memory left, put it into the freelist.
159
43.5k
        size_t remaining_available_bytes = m_available_memory_end - m_available_memory_it;
160
43.5k
        if (0 != remaining_available_bytes) {
  Branch (160:13): [True: 38.1k, False: 5.46k]
161
38.1k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
162
38.1k
            PlacementAddToList(m_available_memory_it, m_free_lists[remaining_available_bytes / ELEM_ALIGN_BYTES]);
163
38.1k
            ASAN_POISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
164
38.1k
        }
165
166
43.5k
        void* storage = ::operator new (m_chunk_size_bytes, std::align_val_t{ELEM_ALIGN_BYTES});
167
43.5k
        m_available_memory_it = new (storage) std::byte[m_chunk_size_bytes];
168
43.5k
        m_available_memory_end = m_available_memory_it + m_chunk_size_bytes;
169
43.5k
        ASAN_POISON_MEMORY_REGION(m_available_memory_it, m_chunk_size_bytes);
170
43.5k
        m_allocated_chunks.emplace_back(m_available_memory_it);
171
43.5k
    }
_ZN12PoolResourceILm256ELm64EE13AllocateChunkEv
Line
Count
Source
157
117k
    {
158
        // if there is still any available memory left, put it into the freelist.
159
117k
        size_t remaining_available_bytes = m_available_memory_end - m_available_memory_it;
160
117k
        if (0 != remaining_available_bytes) {
  Branch (160:13): [True: 107k, False: 10.0k]
161
107k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
162
107k
            PlacementAddToList(m_available_memory_it, m_free_lists[remaining_available_bytes / ELEM_ALIGN_BYTES]);
163
107k
            ASAN_POISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
164
107k
        }
165
166
117k
        void* storage = ::operator new (m_chunk_size_bytes, std::align_val_t{ELEM_ALIGN_BYTES});
167
117k
        m_available_memory_it = new (storage) std::byte[m_chunk_size_bytes];
168
117k
        m_available_memory_end = m_available_memory_it + m_chunk_size_bytes;
169
117k
        ASAN_POISON_MEMORY_REGION(m_available_memory_it, m_chunk_size_bytes);
170
117k
        m_allocated_chunks.emplace_back(m_available_memory_it);
171
117k
    }
172
173
    /**
174
     * Access to internals for testing purpose only
175
     */
176
    friend class PoolResourceTester;
177
178
public:
179
    /**
180
     * Construct a new PoolResource object which allocates the first chunk.
181
     * chunk_size_bytes will be rounded up to next multiple of ELEM_ALIGN_BYTES.
182
     */
183
    explicit PoolResource(std::size_t chunk_size_bytes)
184
6.22M
        : m_chunk_size_bytes(NumElemAlignBytes(chunk_size_bytes) * ELEM_ALIGN_BYTES)
185
6.22M
    {
186
6.22M
        assert(m_chunk_size_bytes >= MAX_BLOCK_SIZE_BYTES);
  Branch (186:9): [True: 6.22M, False: 0]
  Branch (186:9): [True: 143, False: 0]
  Branch (186:9): [True: 147, False: 0]
  Branch (186:9): [True: 150, False: 0]
  Branch (186:9): [True: 162, False: 0]
  Branch (186:9): [True: 129, False: 0]
  Branch (186:9): [True: 165, False: 0]
  Branch (186:9): [True: 140, False: 0]
  Branch (186:9): [True: 171, False: 0]
187
6.22M
        AllocateChunk();
188
6.22M
    }
_ZN12PoolResourceILm152ELm8EEC2Em
Line
Count
Source
184
6.22M
        : m_chunk_size_bytes(NumElemAlignBytes(chunk_size_bytes) * ELEM_ALIGN_BYTES)
185
6.22M
    {
186
6.22M
        assert(m_chunk_size_bytes >= MAX_BLOCK_SIZE_BYTES);
  Branch (186:9): [True: 6.22M, False: 0]
187
6.22M
        AllocateChunk();
188
6.22M
    }
_ZN12PoolResourceILm128ELm1EEC2Em
Line
Count
Source
184
143
        : m_chunk_size_bytes(NumElemAlignBytes(chunk_size_bytes) * ELEM_ALIGN_BYTES)
185
143
    {
186
143
        assert(m_chunk_size_bytes >= MAX_BLOCK_SIZE_BYTES);
  Branch (186:9): [True: 143, False: 0]
187
143
        AllocateChunk();
188
143
    }
_ZN12PoolResourceILm128ELm2EEC2Em
Line
Count
Source
184
147
        : m_chunk_size_bytes(NumElemAlignBytes(chunk_size_bytes) * ELEM_ALIGN_BYTES)
185
147
    {
186
147
        assert(m_chunk_size_bytes >= MAX_BLOCK_SIZE_BYTES);
  Branch (186:9): [True: 147, False: 0]
187
147
        AllocateChunk();
188
147
    }
_ZN12PoolResourceILm128ELm4EEC2Em
Line
Count
Source
184
150
        : m_chunk_size_bytes(NumElemAlignBytes(chunk_size_bytes) * ELEM_ALIGN_BYTES)
185
150
    {
186
150
        assert(m_chunk_size_bytes >= MAX_BLOCK_SIZE_BYTES);
  Branch (186:9): [True: 150, False: 0]
187
150
        AllocateChunk();
188
150
    }
_ZN12PoolResourceILm128ELm8EEC2Em
Line
Count
Source
184
162
        : m_chunk_size_bytes(NumElemAlignBytes(chunk_size_bytes) * ELEM_ALIGN_BYTES)
185
162
    {
186
162
        assert(m_chunk_size_bytes >= MAX_BLOCK_SIZE_BYTES);
  Branch (186:9): [True: 162, False: 0]
187
162
        AllocateChunk();
188
162
    }
_ZN12PoolResourceILm8ELm8EEC2Em
Line
Count
Source
184
129
        : m_chunk_size_bytes(NumElemAlignBytes(chunk_size_bytes) * ELEM_ALIGN_BYTES)
185
129
    {
186
129
        assert(m_chunk_size_bytes >= MAX_BLOCK_SIZE_BYTES);
  Branch (186:9): [True: 129, False: 0]
187
129
        AllocateChunk();
188
129
    }
_ZN12PoolResourceILm16ELm16EEC2Em
Line
Count
Source
184
165
        : m_chunk_size_bytes(NumElemAlignBytes(chunk_size_bytes) * ELEM_ALIGN_BYTES)
185
165
    {
186
165
        assert(m_chunk_size_bytes >= MAX_BLOCK_SIZE_BYTES);
  Branch (186:9): [True: 165, False: 0]
187
165
        AllocateChunk();
188
165
    }
_ZN12PoolResourceILm256ELm16EEC2Em
Line
Count
Source
184
140
        : m_chunk_size_bytes(NumElemAlignBytes(chunk_size_bytes) * ELEM_ALIGN_BYTES)
185
140
    {
186
140
        assert(m_chunk_size_bytes >= MAX_BLOCK_SIZE_BYTES);
  Branch (186:9): [True: 140, False: 0]
187
140
        AllocateChunk();
188
140
    }
_ZN12PoolResourceILm256ELm64EEC2Em
Line
Count
Source
184
171
        : m_chunk_size_bytes(NumElemAlignBytes(chunk_size_bytes) * ELEM_ALIGN_BYTES)
185
171
    {
186
171
        assert(m_chunk_size_bytes >= MAX_BLOCK_SIZE_BYTES);
  Branch (186:9): [True: 171, False: 0]
187
171
        AllocateChunk();
188
171
    }
189
190
    /**
191
     * Construct a new Pool Resource object, defaults to 2^18=262144 chunk size.
192
     */
193
6.22M
    PoolResource() : PoolResource(262144) {}
194
195
    /**
196
     * Disable copy & move semantics, these are not supported for the resource.
197
     */
198
    PoolResource(const PoolResource&) = delete;
199
    PoolResource& operator=(const PoolResource&) = delete;
200
    PoolResource(PoolResource&&) = delete;
201
    PoolResource& operator=(PoolResource&&) = delete;
202
203
    /**
204
     * Deallocates all memory allocated associated with the memory resource.
205
     */
206
    ~PoolResource()
207
6.22M
    {
208
6.70M
        for (std::byte* chunk : m_allocated_chunks) {
  Branch (208:31): [True: 6.22M, False: 6.22M]
  Branch (208:31): [True: 51.4k, False: 143]
  Branch (208:31): [True: 60.8k, False: 147]
  Branch (208:31): [True: 58.6k, False: 150]
  Branch (208:31): [True: 57.0k, False: 162]
  Branch (208:31): [True: 27.2k, False: 129]
  Branch (208:31): [True: 66.1k, False: 165]
  Branch (208:31): [True: 43.5k, False: 140]
  Branch (208:31): [True: 117k, False: 171]
209
6.70M
            std::destroy(chunk, chunk + m_chunk_size_bytes);
210
6.70M
            ::operator delete ((void*)chunk, std::align_val_t{ELEM_ALIGN_BYTES});
211
6.70M
            ASAN_UNPOISON_MEMORY_REGION(chunk, m_chunk_size_bytes);
212
6.70M
        }
213
6.22M
    }
_ZN12PoolResourceILm152ELm8EED2Ev
Line
Count
Source
207
6.22M
    {
208
6.22M
        for (std::byte* chunk : m_allocated_chunks) {
  Branch (208:31): [True: 6.22M, False: 6.22M]
209
6.22M
            std::destroy(chunk, chunk + m_chunk_size_bytes);
210
6.22M
            ::operator delete ((void*)chunk, std::align_val_t{ELEM_ALIGN_BYTES});
211
6.22M
            ASAN_UNPOISON_MEMORY_REGION(chunk, m_chunk_size_bytes);
212
6.22M
        }
213
6.22M
    }
_ZN12PoolResourceILm128ELm1EED2Ev
Line
Count
Source
207
143
    {
208
51.4k
        for (std::byte* chunk : m_allocated_chunks) {
  Branch (208:31): [True: 51.4k, False: 143]
209
51.4k
            std::destroy(chunk, chunk + m_chunk_size_bytes);
210
51.4k
            ::operator delete ((void*)chunk, std::align_val_t{ELEM_ALIGN_BYTES});
211
51.4k
            ASAN_UNPOISON_MEMORY_REGION(chunk, m_chunk_size_bytes);
212
51.4k
        }
213
143
    }
_ZN12PoolResourceILm128ELm2EED2Ev
Line
Count
Source
207
147
    {
208
60.8k
        for (std::byte* chunk : m_allocated_chunks) {
  Branch (208:31): [True: 60.8k, False: 147]
209
60.8k
            std::destroy(chunk, chunk + m_chunk_size_bytes);
210
60.8k
            ::operator delete ((void*)chunk, std::align_val_t{ELEM_ALIGN_BYTES});
211
60.8k
            ASAN_UNPOISON_MEMORY_REGION(chunk, m_chunk_size_bytes);
212
60.8k
        }
213
147
    }
_ZN12PoolResourceILm128ELm4EED2Ev
Line
Count
Source
207
150
    {
208
58.6k
        for (std::byte* chunk : m_allocated_chunks) {
  Branch (208:31): [True: 58.6k, False: 150]
209
58.6k
            std::destroy(chunk, chunk + m_chunk_size_bytes);
210
58.6k
            ::operator delete ((void*)chunk, std::align_val_t{ELEM_ALIGN_BYTES});
211
58.6k
            ASAN_UNPOISON_MEMORY_REGION(chunk, m_chunk_size_bytes);
212
58.6k
        }
213
150
    }
_ZN12PoolResourceILm128ELm8EED2Ev
Line
Count
Source
207
162
    {
208
57.0k
        for (std::byte* chunk : m_allocated_chunks) {
  Branch (208:31): [True: 57.0k, False: 162]
209
57.0k
            std::destroy(chunk, chunk + m_chunk_size_bytes);
210
57.0k
            ::operator delete ((void*)chunk, std::align_val_t{ELEM_ALIGN_BYTES});
211
57.0k
            ASAN_UNPOISON_MEMORY_REGION(chunk, m_chunk_size_bytes);
212
57.0k
        }
213
162
    }
_ZN12PoolResourceILm8ELm8EED2Ev
Line
Count
Source
207
129
    {
208
27.2k
        for (std::byte* chunk : m_allocated_chunks) {
  Branch (208:31): [True: 27.2k, False: 129]
209
27.2k
            std::destroy(chunk, chunk + m_chunk_size_bytes);
210
27.2k
            ::operator delete ((void*)chunk, std::align_val_t{ELEM_ALIGN_BYTES});
211
27.2k
            ASAN_UNPOISON_MEMORY_REGION(chunk, m_chunk_size_bytes);
212
27.2k
        }
213
129
    }
_ZN12PoolResourceILm16ELm16EED2Ev
Line
Count
Source
207
165
    {
208
66.1k
        for (std::byte* chunk : m_allocated_chunks) {
  Branch (208:31): [True: 66.1k, False: 165]
209
66.1k
            std::destroy(chunk, chunk + m_chunk_size_bytes);
210
66.1k
            ::operator delete ((void*)chunk, std::align_val_t{ELEM_ALIGN_BYTES});
211
66.1k
            ASAN_UNPOISON_MEMORY_REGION(chunk, m_chunk_size_bytes);
212
66.1k
        }
213
165
    }
_ZN12PoolResourceILm256ELm16EED2Ev
Line
Count
Source
207
140
    {
208
43.5k
        for (std::byte* chunk : m_allocated_chunks) {
  Branch (208:31): [True: 43.5k, False: 140]
209
43.5k
            std::destroy(chunk, chunk + m_chunk_size_bytes);
210
43.5k
            ::operator delete ((void*)chunk, std::align_val_t{ELEM_ALIGN_BYTES});
211
43.5k
            ASAN_UNPOISON_MEMORY_REGION(chunk, m_chunk_size_bytes);
212
43.5k
        }
213
140
    }
_ZN12PoolResourceILm256ELm64EED2Ev
Line
Count
Source
207
171
    {
208
117k
        for (std::byte* chunk : m_allocated_chunks) {
  Branch (208:31): [True: 117k, False: 171]
209
117k
            std::destroy(chunk, chunk + m_chunk_size_bytes);
210
117k
            ::operator delete ((void*)chunk, std::align_val_t{ELEM_ALIGN_BYTES});
211
117k
            ASAN_UNPOISON_MEMORY_REGION(chunk, m_chunk_size_bytes);
212
117k
        }
213
171
    }
214
215
    /**
216
     * Allocates a block of bytes. If possible the freelist is used, otherwise allocation
217
     * is forwarded to ::operator new().
218
     */
219
    void* Allocate(std::size_t bytes, std::size_t alignment)
220
25.5M
    {
221
25.5M
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (221:13): [True: 24.4M, False: 177k]
  Branch (221:13): [True: 120k, False: 7.80k]
  Branch (221:13): [True: 135k, False: 9.58k]
  Branch (221:13): [True: 94.0k, False: 14.6k]
  Branch (221:13): [True: 109k, False: 6.57k]
  Branch (221:13): [True: 56.0k, False: 8.06k]
  Branch (221:13): [True: 92.3k, False: 11.5k]
  Branch (221:13): [True: 79.1k, False: 3.80k]
  Branch (221:13): [True: 173k, False: 4.07k]
222
25.3M
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
223
25.3M
            if (nullptr != m_free_lists[num_alignments]) {
  Branch (223:17): [True: 9.08M, False: 15.3M]
  Branch (223:17): [True: 1.85k, False: 118k]
  Branch (223:17): [True: 1.94k, False: 133k]
  Branch (223:17): [True: 1.72k, False: 92.3k]
  Branch (223:17): [True: 1.26k, False: 108k]
  Branch (223:17): [True: 569, False: 55.4k]
  Branch (223:17): [True: 952, False: 91.3k]
  Branch (223:17): [True: 734, False: 78.4k]
  Branch (223:17): [True: 1.03k, False: 172k]
224
                // we've already got data in the pool's freelist, unlink one element and return the pointer
225
                // to the unlinked memory. Since FreeList is trivially destructible we can just treat it as
226
                // uninitialized memory.
227
9.09M
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
228
9.09M
                auto* next{m_free_lists[num_alignments]->m_next};
229
9.09M
                ASAN_POISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
230
9.09M
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], bytes);
231
9.09M
                return std::exchange(m_free_lists[num_alignments], next);
232
9.09M
            }
233
234
            // freelist is empty: get one allocation from allocated chunk memory.
235
16.2M
            const std::ptrdiff_t round_bytes = static_cast<std::ptrdiff_t>(num_alignments * ELEM_ALIGN_BYTES);
236
16.2M
            if (round_bytes > m_available_memory_end - m_available_memory_it) {
  Branch (236:17): [True: 657, False: 15.3M]
  Branch (236:17): [True: 51.3k, False: 67.5k]
  Branch (236:17): [True: 60.6k, False: 72.6k]
  Branch (236:17): [True: 58.4k, False: 33.8k]
  Branch (236:17): [True: 56.8k, False: 51.8k]
  Branch (236:17): [True: 27.1k, False: 28.2k]
  Branch (236:17): [True: 65.9k, False: 25.3k]
  Branch (236:17): [True: 43.4k, False: 34.9k]
  Branch (236:17): [True: 116k, False: 55.6k]
237
                // slow path, only happens when a new chunk needs to be allocated
238
481k
                AllocateChunk();
239
481k
            }
240
241
            // Make sure we use the right amount of bytes for that freelist (might be rounded up),
242
16.2M
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, round_bytes);
243
16.2M
            return std::exchange(m_available_memory_it, m_available_memory_it + round_bytes);
244
25.3M
        }
245
246
        // Can't use the pool => use operator new()
247
243k
        return ::operator new (bytes, std::align_val_t{alignment});
248
25.5M
    }
_ZN12PoolResourceILm152ELm8EE8AllocateEmm
Line
Count
Source
220
24.6M
    {
221
24.6M
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (221:13): [True: 24.4M, False: 177k]
222
24.4M
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
223
24.4M
            if (nullptr != m_free_lists[num_alignments]) {
  Branch (223:17): [True: 9.08M, False: 15.3M]
224
                // we've already got data in the pool's freelist, unlink one element and return the pointer
225
                // to the unlinked memory. Since FreeList is trivially destructible we can just treat it as
226
                // uninitialized memory.
227
9.08M
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
228
9.08M
                auto* next{m_free_lists[num_alignments]->m_next};
229
9.08M
                ASAN_POISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
230
9.08M
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], bytes);
231
9.08M
                return std::exchange(m_free_lists[num_alignments], next);
232
9.08M
            }
233
234
            // freelist is empty: get one allocation from allocated chunk memory.
235
15.3M
            const std::ptrdiff_t round_bytes = static_cast<std::ptrdiff_t>(num_alignments * ELEM_ALIGN_BYTES);
236
15.3M
            if (round_bytes > m_available_memory_end - m_available_memory_it) {
  Branch (236:17): [True: 657, False: 15.3M]
237
                // slow path, only happens when a new chunk needs to be allocated
238
657
                AllocateChunk();
239
657
            }
240
241
            // Make sure we use the right amount of bytes for that freelist (might be rounded up),
242
15.3M
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, round_bytes);
243
15.3M
            return std::exchange(m_available_memory_it, m_available_memory_it + round_bytes);
244
24.4M
        }
245
246
        // Can't use the pool => use operator new()
247
177k
        return ::operator new (bytes, std::align_val_t{alignment});
248
24.6M
    }
_ZN12PoolResourceILm128ELm1EE8AllocateEmm
Line
Count
Source
220
128k
    {
221
128k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (221:13): [True: 120k, False: 7.80k]
222
120k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
223
120k
            if (nullptr != m_free_lists[num_alignments]) {
  Branch (223:17): [True: 1.85k, False: 118k]
224
                // we've already got data in the pool's freelist, unlink one element and return the pointer
225
                // to the unlinked memory. Since FreeList is trivially destructible we can just treat it as
226
                // uninitialized memory.
227
1.85k
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
228
1.85k
                auto* next{m_free_lists[num_alignments]->m_next};
229
1.85k
                ASAN_POISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
230
1.85k
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], bytes);
231
1.85k
                return std::exchange(m_free_lists[num_alignments], next);
232
1.85k
            }
233
234
            // freelist is empty: get one allocation from allocated chunk memory.
235
118k
            const std::ptrdiff_t round_bytes = static_cast<std::ptrdiff_t>(num_alignments * ELEM_ALIGN_BYTES);
236
118k
            if (round_bytes > m_available_memory_end - m_available_memory_it) {
  Branch (236:17): [True: 51.3k, False: 67.5k]
237
                // slow path, only happens when a new chunk needs to be allocated
238
51.3k
                AllocateChunk();
239
51.3k
            }
240
241
            // Make sure we use the right amount of bytes for that freelist (might be rounded up),
242
118k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, round_bytes);
243
118k
            return std::exchange(m_available_memory_it, m_available_memory_it + round_bytes);
244
120k
        }
245
246
        // Can't use the pool => use operator new()
247
7.80k
        return ::operator new (bytes, std::align_val_t{alignment});
248
128k
    }
_ZN12PoolResourceILm128ELm2EE8AllocateEmm
Line
Count
Source
220
144k
    {
221
144k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (221:13): [True: 135k, False: 9.58k]
222
135k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
223
135k
            if (nullptr != m_free_lists[num_alignments]) {
  Branch (223:17): [True: 1.94k, False: 133k]
224
                // we've already got data in the pool's freelist, unlink one element and return the pointer
225
                // to the unlinked memory. Since FreeList is trivially destructible we can just treat it as
226
                // uninitialized memory.
227
1.94k
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
228
1.94k
                auto* next{m_free_lists[num_alignments]->m_next};
229
1.94k
                ASAN_POISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
230
1.94k
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], bytes);
231
1.94k
                return std::exchange(m_free_lists[num_alignments], next);
232
1.94k
            }
233
234
            // freelist is empty: get one allocation from allocated chunk memory.
235
133k
            const std::ptrdiff_t round_bytes = static_cast<std::ptrdiff_t>(num_alignments * ELEM_ALIGN_BYTES);
236
133k
            if (round_bytes > m_available_memory_end - m_available_memory_it) {
  Branch (236:17): [True: 60.6k, False: 72.6k]
237
                // slow path, only happens when a new chunk needs to be allocated
238
60.6k
                AllocateChunk();
239
60.6k
            }
240
241
            // Make sure we use the right amount of bytes for that freelist (might be rounded up),
242
133k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, round_bytes);
243
133k
            return std::exchange(m_available_memory_it, m_available_memory_it + round_bytes);
244
135k
        }
245
246
        // Can't use the pool => use operator new()
247
9.58k
        return ::operator new (bytes, std::align_val_t{alignment});
248
144k
    }
_ZN12PoolResourceILm128ELm4EE8AllocateEmm
Line
Count
Source
220
108k
    {
221
108k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (221:13): [True: 94.0k, False: 14.6k]
222
94.0k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
223
94.0k
            if (nullptr != m_free_lists[num_alignments]) {
  Branch (223:17): [True: 1.72k, False: 92.3k]
224
                // we've already got data in the pool's freelist, unlink one element and return the pointer
225
                // to the unlinked memory. Since FreeList is trivially destructible we can just treat it as
226
                // uninitialized memory.
227
1.72k
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
228
1.72k
                auto* next{m_free_lists[num_alignments]->m_next};
229
1.72k
                ASAN_POISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
230
1.72k
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], bytes);
231
1.72k
                return std::exchange(m_free_lists[num_alignments], next);
232
1.72k
            }
233
234
            // freelist is empty: get one allocation from allocated chunk memory.
235
92.3k
            const std::ptrdiff_t round_bytes = static_cast<std::ptrdiff_t>(num_alignments * ELEM_ALIGN_BYTES);
236
92.3k
            if (round_bytes > m_available_memory_end - m_available_memory_it) {
  Branch (236:17): [True: 58.4k, False: 33.8k]
237
                // slow path, only happens when a new chunk needs to be allocated
238
58.4k
                AllocateChunk();
239
58.4k
            }
240
241
            // Make sure we use the right amount of bytes for that freelist (might be rounded up),
242
92.3k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, round_bytes);
243
92.3k
            return std::exchange(m_available_memory_it, m_available_memory_it + round_bytes);
244
94.0k
        }
245
246
        // Can't use the pool => use operator new()
247
14.6k
        return ::operator new (bytes, std::align_val_t{alignment});
248
108k
    }
_ZN12PoolResourceILm128ELm8EE8AllocateEmm
Line
Count
Source
220
116k
    {
221
116k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (221:13): [True: 109k, False: 6.57k]
222
109k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
223
109k
            if (nullptr != m_free_lists[num_alignments]) {
  Branch (223:17): [True: 1.26k, False: 108k]
224
                // we've already got data in the pool's freelist, unlink one element and return the pointer
225
                // to the unlinked memory. Since FreeList is trivially destructible we can just treat it as
226
                // uninitialized memory.
227
1.26k
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
228
1.26k
                auto* next{m_free_lists[num_alignments]->m_next};
229
1.26k
                ASAN_POISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
230
1.26k
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], bytes);
231
1.26k
                return std::exchange(m_free_lists[num_alignments], next);
232
1.26k
            }
233
234
            // freelist is empty: get one allocation from allocated chunk memory.
235
108k
            const std::ptrdiff_t round_bytes = static_cast<std::ptrdiff_t>(num_alignments * ELEM_ALIGN_BYTES);
236
108k
            if (round_bytes > m_available_memory_end - m_available_memory_it) {
  Branch (236:17): [True: 56.8k, False: 51.8k]
237
                // slow path, only happens when a new chunk needs to be allocated
238
56.8k
                AllocateChunk();
239
56.8k
            }
240
241
            // Make sure we use the right amount of bytes for that freelist (might be rounded up),
242
108k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, round_bytes);
243
108k
            return std::exchange(m_available_memory_it, m_available_memory_it + round_bytes);
244
109k
        }
245
246
        // Can't use the pool => use operator new()
247
6.57k
        return ::operator new (bytes, std::align_val_t{alignment});
248
116k
    }
_ZN12PoolResourceILm8ELm8EE8AllocateEmm
Line
Count
Source
220
64.0k
    {
221
64.0k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (221:13): [True: 56.0k, False: 8.06k]
222
56.0k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
223
56.0k
            if (nullptr != m_free_lists[num_alignments]) {
  Branch (223:17): [True: 569, False: 55.4k]
224
                // we've already got data in the pool's freelist, unlink one element and return the pointer
225
                // to the unlinked memory. Since FreeList is trivially destructible we can just treat it as
226
                // uninitialized memory.
227
569
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
228
569
                auto* next{m_free_lists[num_alignments]->m_next};
229
569
                ASAN_POISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
230
569
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], bytes);
231
569
                return std::exchange(m_free_lists[num_alignments], next);
232
569
            }
233
234
            // freelist is empty: get one allocation from allocated chunk memory.
235
55.4k
            const std::ptrdiff_t round_bytes = static_cast<std::ptrdiff_t>(num_alignments * ELEM_ALIGN_BYTES);
236
55.4k
            if (round_bytes > m_available_memory_end - m_available_memory_it) {
  Branch (236:17): [True: 27.1k, False: 28.2k]
237
                // slow path, only happens when a new chunk needs to be allocated
238
27.1k
                AllocateChunk();
239
27.1k
            }
240
241
            // Make sure we use the right amount of bytes for that freelist (might be rounded up),
242
55.4k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, round_bytes);
243
55.4k
            return std::exchange(m_available_memory_it, m_available_memory_it + round_bytes);
244
56.0k
        }
245
246
        // Can't use the pool => use operator new()
247
8.06k
        return ::operator new (bytes, std::align_val_t{alignment});
248
64.0k
    }
_ZN12PoolResourceILm16ELm16EE8AllocateEmm
Line
Count
Source
220
103k
    {
221
103k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (221:13): [True: 92.3k, False: 11.5k]
222
92.3k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
223
92.3k
            if (nullptr != m_free_lists[num_alignments]) {
  Branch (223:17): [True: 952, False: 91.3k]
224
                // we've already got data in the pool's freelist, unlink one element and return the pointer
225
                // to the unlinked memory. Since FreeList is trivially destructible we can just treat it as
226
                // uninitialized memory.
227
952
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
228
952
                auto* next{m_free_lists[num_alignments]->m_next};
229
952
                ASAN_POISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
230
952
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], bytes);
231
952
                return std::exchange(m_free_lists[num_alignments], next);
232
952
            }
233
234
            // freelist is empty: get one allocation from allocated chunk memory.
235
91.3k
            const std::ptrdiff_t round_bytes = static_cast<std::ptrdiff_t>(num_alignments * ELEM_ALIGN_BYTES);
236
91.3k
            if (round_bytes > m_available_memory_end - m_available_memory_it) {
  Branch (236:17): [True: 65.9k, False: 25.3k]
237
                // slow path, only happens when a new chunk needs to be allocated
238
65.9k
                AllocateChunk();
239
65.9k
            }
240
241
            // Make sure we use the right amount of bytes for that freelist (might be rounded up),
242
91.3k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, round_bytes);
243
91.3k
            return std::exchange(m_available_memory_it, m_available_memory_it + round_bytes);
244
92.3k
        }
245
246
        // Can't use the pool => use operator new()
247
11.5k
        return ::operator new (bytes, std::align_val_t{alignment});
248
103k
    }
_ZN12PoolResourceILm256ELm16EE8AllocateEmm
Line
Count
Source
220
82.9k
    {
221
82.9k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (221:13): [True: 79.1k, False: 3.80k]
222
79.1k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
223
79.1k
            if (nullptr != m_free_lists[num_alignments]) {
  Branch (223:17): [True: 734, False: 78.4k]
224
                // we've already got data in the pool's freelist, unlink one element and return the pointer
225
                // to the unlinked memory. Since FreeList is trivially destructible we can just treat it as
226
                // uninitialized memory.
227
734
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
228
734
                auto* next{m_free_lists[num_alignments]->m_next};
229
734
                ASAN_POISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
230
734
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], bytes);
231
734
                return std::exchange(m_free_lists[num_alignments], next);
232
734
            }
233
234
            // freelist is empty: get one allocation from allocated chunk memory.
235
78.4k
            const std::ptrdiff_t round_bytes = static_cast<std::ptrdiff_t>(num_alignments * ELEM_ALIGN_BYTES);
236
78.4k
            if (round_bytes > m_available_memory_end - m_available_memory_it) {
  Branch (236:17): [True: 43.4k, False: 34.9k]
237
                // slow path, only happens when a new chunk needs to be allocated
238
43.4k
                AllocateChunk();
239
43.4k
            }
240
241
            // Make sure we use the right amount of bytes for that freelist (might be rounded up),
242
78.4k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, round_bytes);
243
78.4k
            return std::exchange(m_available_memory_it, m_available_memory_it + round_bytes);
244
79.1k
        }
245
246
        // Can't use the pool => use operator new()
247
3.80k
        return ::operator new (bytes, std::align_val_t{alignment});
248
82.9k
    }
_ZN12PoolResourceILm256ELm64EE8AllocateEmm
Line
Count
Source
220
177k
    {
221
177k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (221:13): [True: 173k, False: 4.07k]
222
173k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
223
173k
            if (nullptr != m_free_lists[num_alignments]) {
  Branch (223:17): [True: 1.03k, False: 172k]
224
                // we've already got data in the pool's freelist, unlink one element and return the pointer
225
                // to the unlinked memory. Since FreeList is trivially destructible we can just treat it as
226
                // uninitialized memory.
227
1.03k
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
228
1.03k
                auto* next{m_free_lists[num_alignments]->m_next};
229
1.03k
                ASAN_POISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
230
1.03k
                ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], bytes);
231
1.03k
                return std::exchange(m_free_lists[num_alignments], next);
232
1.03k
            }
233
234
            // freelist is empty: get one allocation from allocated chunk memory.
235
172k
            const std::ptrdiff_t round_bytes = static_cast<std::ptrdiff_t>(num_alignments * ELEM_ALIGN_BYTES);
236
172k
            if (round_bytes > m_available_memory_end - m_available_memory_it) {
  Branch (236:17): [True: 116k, False: 55.6k]
237
                // slow path, only happens when a new chunk needs to be allocated
238
116k
                AllocateChunk();
239
116k
            }
240
241
            // Make sure we use the right amount of bytes for that freelist (might be rounded up),
242
172k
            ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, round_bytes);
243
172k
            return std::exchange(m_available_memory_it, m_available_memory_it + round_bytes);
244
173k
        }
245
246
        // Can't use the pool => use operator new()
247
4.07k
        return ::operator new (bytes, std::align_val_t{alignment});
248
177k
    }
249
250
    /**
251
     * Returns a block to the freelists, or deletes the block when it did not come from the chunks.
252
     */
253
    void Deallocate(void* p, std::size_t bytes, std::size_t alignment) noexcept
254
25.5M
    {
255
25.5M
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (255:13): [True: 24.4M, False: 177k]
  Branch (255:13): [True: 120k, False: 7.80k]
  Branch (255:13): [True: 135k, False: 9.58k]
  Branch (255:13): [True: 94.0k, False: 14.6k]
  Branch (255:13): [True: 109k, False: 6.57k]
  Branch (255:13): [True: 56.0k, False: 8.06k]
  Branch (255:13): [True: 92.3k, False: 11.5k]
  Branch (255:13): [True: 79.1k, False: 3.80k]
  Branch (255:13): [True: 173k, False: 4.07k]
256
25.3M
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
257
            // put the memory block into the linked list. We can placement construct the FreeList
258
            // into the memory since we can be sure the alignment is correct.
259
25.3M
            ASAN_UNPOISON_MEMORY_REGION(p, sizeof(ListNode));
260
25.3M
            PlacementAddToList(p, m_free_lists[num_alignments]);
261
25.3M
            ASAN_POISON_MEMORY_REGION(p, std::max(bytes, sizeof(ListNode)));
262
25.3M
        } else {
263
            // Can't use the pool => forward deallocation to ::operator delete().
264
243k
            ::operator delete (p, std::align_val_t{alignment});
265
243k
        }
266
25.5M
    }
_ZN12PoolResourceILm152ELm8EE10DeallocateEPvmm
Line
Count
Source
254
24.6M
    {
255
24.6M
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (255:13): [True: 24.4M, False: 177k]
256
24.4M
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
257
            // put the memory block into the linked list. We can placement construct the FreeList
258
            // into the memory since we can be sure the alignment is correct.
259
24.4M
            ASAN_UNPOISON_MEMORY_REGION(p, sizeof(ListNode));
260
24.4M
            PlacementAddToList(p, m_free_lists[num_alignments]);
261
24.4M
            ASAN_POISON_MEMORY_REGION(p, std::max(bytes, sizeof(ListNode)));
262
24.4M
        } else {
263
            // Can't use the pool => forward deallocation to ::operator delete().
264
177k
            ::operator delete (p, std::align_val_t{alignment});
265
177k
        }
266
24.6M
    }
_ZN12PoolResourceILm128ELm1EE10DeallocateEPvmm
Line
Count
Source
254
128k
    {
255
128k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (255:13): [True: 120k, False: 7.80k]
256
120k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
257
            // put the memory block into the linked list. We can placement construct the FreeList
258
            // into the memory since we can be sure the alignment is correct.
259
120k
            ASAN_UNPOISON_MEMORY_REGION(p, sizeof(ListNode));
260
120k
            PlacementAddToList(p, m_free_lists[num_alignments]);
261
120k
            ASAN_POISON_MEMORY_REGION(p, std::max(bytes, sizeof(ListNode)));
262
120k
        } else {
263
            // Can't use the pool => forward deallocation to ::operator delete().
264
7.80k
            ::operator delete (p, std::align_val_t{alignment});
265
7.80k
        }
266
128k
    }
_ZN12PoolResourceILm128ELm2EE10DeallocateEPvmm
Line
Count
Source
254
144k
    {
255
144k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (255:13): [True: 135k, False: 9.58k]
256
135k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
257
            // put the memory block into the linked list. We can placement construct the FreeList
258
            // into the memory since we can be sure the alignment is correct.
259
135k
            ASAN_UNPOISON_MEMORY_REGION(p, sizeof(ListNode));
260
135k
            PlacementAddToList(p, m_free_lists[num_alignments]);
261
135k
            ASAN_POISON_MEMORY_REGION(p, std::max(bytes, sizeof(ListNode)));
262
135k
        } else {
263
            // Can't use the pool => forward deallocation to ::operator delete().
264
9.58k
            ::operator delete (p, std::align_val_t{alignment});
265
9.58k
        }
266
144k
    }
_ZN12PoolResourceILm128ELm4EE10DeallocateEPvmm
Line
Count
Source
254
108k
    {
255
108k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (255:13): [True: 94.0k, False: 14.6k]
256
94.0k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
257
            // put the memory block into the linked list. We can placement construct the FreeList
258
            // into the memory since we can be sure the alignment is correct.
259
94.0k
            ASAN_UNPOISON_MEMORY_REGION(p, sizeof(ListNode));
260
94.0k
            PlacementAddToList(p, m_free_lists[num_alignments]);
261
94.0k
            ASAN_POISON_MEMORY_REGION(p, std::max(bytes, sizeof(ListNode)));
262
94.0k
        } else {
263
            // Can't use the pool => forward deallocation to ::operator delete().
264
14.6k
            ::operator delete (p, std::align_val_t{alignment});
265
14.6k
        }
266
108k
    }
_ZN12PoolResourceILm128ELm8EE10DeallocateEPvmm
Line
Count
Source
254
116k
    {
255
116k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (255:13): [True: 109k, False: 6.57k]
256
109k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
257
            // put the memory block into the linked list. We can placement construct the FreeList
258
            // into the memory since we can be sure the alignment is correct.
259
109k
            ASAN_UNPOISON_MEMORY_REGION(p, sizeof(ListNode));
260
109k
            PlacementAddToList(p, m_free_lists[num_alignments]);
261
109k
            ASAN_POISON_MEMORY_REGION(p, std::max(bytes, sizeof(ListNode)));
262
109k
        } else {
263
            // Can't use the pool => forward deallocation to ::operator delete().
264
6.57k
            ::operator delete (p, std::align_val_t{alignment});
265
6.57k
        }
266
116k
    }
_ZN12PoolResourceILm8ELm8EE10DeallocateEPvmm
Line
Count
Source
254
64.0k
    {
255
64.0k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (255:13): [True: 56.0k, False: 8.06k]
256
56.0k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
257
            // put the memory block into the linked list. We can placement construct the FreeList
258
            // into the memory since we can be sure the alignment is correct.
259
56.0k
            ASAN_UNPOISON_MEMORY_REGION(p, sizeof(ListNode));
260
56.0k
            PlacementAddToList(p, m_free_lists[num_alignments]);
261
56.0k
            ASAN_POISON_MEMORY_REGION(p, std::max(bytes, sizeof(ListNode)));
262
56.0k
        } else {
263
            // Can't use the pool => forward deallocation to ::operator delete().
264
8.06k
            ::operator delete (p, std::align_val_t{alignment});
265
8.06k
        }
266
64.0k
    }
_ZN12PoolResourceILm16ELm16EE10DeallocateEPvmm
Line
Count
Source
254
103k
    {
255
103k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (255:13): [True: 92.3k, False: 11.5k]
256
92.3k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
257
            // put the memory block into the linked list. We can placement construct the FreeList
258
            // into the memory since we can be sure the alignment is correct.
259
92.3k
            ASAN_UNPOISON_MEMORY_REGION(p, sizeof(ListNode));
260
92.3k
            PlacementAddToList(p, m_free_lists[num_alignments]);
261
92.3k
            ASAN_POISON_MEMORY_REGION(p, std::max(bytes, sizeof(ListNode)));
262
92.3k
        } else {
263
            // Can't use the pool => forward deallocation to ::operator delete().
264
11.5k
            ::operator delete (p, std::align_val_t{alignment});
265
11.5k
        }
266
103k
    }
_ZN12PoolResourceILm256ELm16EE10DeallocateEPvmm
Line
Count
Source
254
82.9k
    {
255
82.9k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (255:13): [True: 79.1k, False: 3.80k]
256
79.1k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
257
            // put the memory block into the linked list. We can placement construct the FreeList
258
            // into the memory since we can be sure the alignment is correct.
259
79.1k
            ASAN_UNPOISON_MEMORY_REGION(p, sizeof(ListNode));
260
79.1k
            PlacementAddToList(p, m_free_lists[num_alignments]);
261
79.1k
            ASAN_POISON_MEMORY_REGION(p, std::max(bytes, sizeof(ListNode)));
262
79.1k
        } else {
263
            // Can't use the pool => forward deallocation to ::operator delete().
264
3.80k
            ::operator delete (p, std::align_val_t{alignment});
265
3.80k
        }
266
82.9k
    }
_ZN12PoolResourceILm256ELm64EE10DeallocateEPvmm
Line
Count
Source
254
177k
    {
255
177k
        if (IsFreeListUsable(bytes, alignment)) {
  Branch (255:13): [True: 173k, False: 4.07k]
256
173k
            const std::size_t num_alignments = NumElemAlignBytes(bytes);
257
            // put the memory block into the linked list. We can placement construct the FreeList
258
            // into the memory since we can be sure the alignment is correct.
259
173k
            ASAN_UNPOISON_MEMORY_REGION(p, sizeof(ListNode));
260
173k
            PlacementAddToList(p, m_free_lists[num_alignments]);
261
173k
            ASAN_POISON_MEMORY_REGION(p, std::max(bytes, sizeof(ListNode)));
262
173k
        } else {
263
            // Can't use the pool => forward deallocation to ::operator delete().
264
4.07k
            ::operator delete (p, std::align_val_t{alignment});
265
4.07k
        }
266
177k
    }
267
268
    /**
269
     * Number of allocated chunks
270
     */
271
    [[nodiscard]] std::size_t NumAllocatedChunks() const
272
20.8M
    {
273
20.8M
        return m_allocated_chunks.size();
274
20.8M
    }
275
276
    /**
277
     * Size in bytes to allocate per chunk, currently hardcoded to a fixed size.
278
     */
279
    [[nodiscard]] size_t ChunkSizeBytes() const
280
10.9M
    {
281
10.9M
        return m_chunk_size_bytes;
282
10.9M
    }
_ZNK12PoolResourceILm128ELm1EE14ChunkSizeBytesEv
Line
Count
Source
280
51.4k
    {
281
51.4k
        return m_chunk_size_bytes;
282
51.4k
    }
_ZNK12PoolResourceILm128ELm2EE14ChunkSizeBytesEv
Line
Count
Source
280
60.8k
    {
281
60.8k
        return m_chunk_size_bytes;
282
60.8k
    }
_ZNK12PoolResourceILm128ELm4EE14ChunkSizeBytesEv
Line
Count
Source
280
58.6k
    {
281
58.6k
        return m_chunk_size_bytes;
282
58.6k
    }
_ZNK12PoolResourceILm128ELm8EE14ChunkSizeBytesEv
Line
Count
Source
280
57.0k
    {
281
57.0k
        return m_chunk_size_bytes;
282
57.0k
    }
_ZNK12PoolResourceILm8ELm8EE14ChunkSizeBytesEv
Line
Count
Source
280
27.2k
    {
281
27.2k
        return m_chunk_size_bytes;
282
27.2k
    }
_ZNK12PoolResourceILm16ELm16EE14ChunkSizeBytesEv
Line
Count
Source
280
66.1k
    {
281
66.1k
        return m_chunk_size_bytes;
282
66.1k
    }
_ZNK12PoolResourceILm256ELm16EE14ChunkSizeBytesEv
Line
Count
Source
280
43.5k
    {
281
43.5k
        return m_chunk_size_bytes;
282
43.5k
    }
_ZNK12PoolResourceILm256ELm64EE14ChunkSizeBytesEv
Line
Count
Source
280
117k
    {
281
117k
        return m_chunk_size_bytes;
282
117k
    }
_ZNK12PoolResourceILm152ELm8EE14ChunkSizeBytesEv
Line
Count
Source
280
10.4M
    {
281
10.4M
        return m_chunk_size_bytes;
282
10.4M
    }
283
};
284
285
286
/**
287
 * Forwards all allocations/deallocations to the PoolResource.
288
 */
289
template <class T, std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES = alignof(T)>
290
class PoolAllocator
291
{
292
    PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>* m_resource;
293
294
    template <typename U, std::size_t M, std::size_t A>
295
    friend class PoolAllocator;
296
297
public:
298
    using value_type = T;
299
    using ResourceType = PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>;
300
301
    /**
302
     * Not explicit so we can easily construct it with the correct resource
303
     */
304
    PoolAllocator(ResourceType* resource) noexcept
305
6.22M
        : m_resource(resource)
306
6.22M
    {
307
6.22M
    }
308
309
    PoolAllocator(const PoolAllocator& other) noexcept = default;
310
    PoolAllocator& operator=(const PoolAllocator& other) noexcept = default;
311
312
    template <class U>
313
    PoolAllocator(const PoolAllocator<U, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& other) noexcept
314
22.4M
        : m_resource(other.resource())
315
22.4M
    {
316
22.4M
    }
_ZN13PoolAllocatorIPNSt8__detail15_Hash_node_baseELm152ELm8EEC2INS0_10_Hash_nodeISt4pairIK9COutPoint16CCoinsCacheEntryELb0EEEEERKS_IT_Lm152ELm8EE
Line
Count
Source
314
5.79M
        : m_resource(other.resource())
315
5.79M
    {
316
5.79M
    }
_ZN13PoolAllocatorINSt8__detail10_Hash_nodeISt4pairIK9COutPoint16CCoinsCacheEntryELb0EEELm152ELm8EEC2IS6_EERKS_IT_Lm152ELm8EE
Line
Count
Source
314
6.22M
        : m_resource(other.resource())
315
6.22M
    {
316
6.22M
    }
_ZN13PoolAllocatorISt4pairIK9COutPoint16CCoinsCacheEntryELm152ELm8EEC2INSt8__detail10_Hash_nodeIS4_Lb0EEEEERKS_IT_Lm152ELm8EE
Line
Count
Source
314
10.4M
        : m_resource(other.resource())
315
10.4M
    {
316
10.4M
    }
317
318
    /**
319
     * The rebind struct here is mandatory because we use non type template arguments for
320
     * PoolAllocator. See https://en.cppreference.com/w/cpp/named_req/Allocator#cite_note-2
321
     */
322
    template <typename U>
323
    struct rebind {
324
        using other = PoolAllocator<U, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>;
325
    };
326
327
    /**
328
     * Forwards each call to the resource.
329
     */
330
    T* allocate(size_t n)
331
24.6M
    {
332
24.6M
        return static_cast<T*>(m_resource->Allocate(n * sizeof(T), alignof(T)));
333
24.6M
    }
_ZN13PoolAllocatorIPNSt8__detail15_Hash_node_baseELm152ELm8EE8allocateEm
Line
Count
Source
331
2.89M
    {
332
2.89M
        return static_cast<T*>(m_resource->Allocate(n * sizeof(T), alignof(T)));
333
2.89M
    }
_ZN13PoolAllocatorINSt8__detail10_Hash_nodeISt4pairIK9COutPoint16CCoinsCacheEntryELb0EEELm152ELm8EE8allocateEm
Line
Count
Source
331
21.7M
    {
332
21.7M
        return static_cast<T*>(m_resource->Allocate(n * sizeof(T), alignof(T)));
333
21.7M
    }
334
335
    /**
336
     * Forwards each call to the resource.
337
     */
338
    void deallocate(T* p, size_t n) noexcept
339
24.6M
    {
340
24.6M
        m_resource->Deallocate(p, n * sizeof(T), alignof(T));
341
24.6M
    }
_ZN13PoolAllocatorINSt8__detail10_Hash_nodeISt4pairIK9COutPoint16CCoinsCacheEntryELb0EEELm152ELm8EE10deallocateEPS7_m
Line
Count
Source
339
21.7M
    {
340
21.7M
        m_resource->Deallocate(p, n * sizeof(T), alignof(T));
341
21.7M
    }
_ZN13PoolAllocatorIPNSt8__detail15_Hash_node_baseELm152ELm8EE10deallocateEPS2_m
Line
Count
Source
339
2.89M
    {
340
2.89M
        m_resource->Deallocate(p, n * sizeof(T), alignof(T));
341
2.89M
    }
342
343
    ResourceType* resource() const noexcept
344
32.9M
    {
345
32.9M
        return m_resource;
346
32.9M
    }
_ZNK13PoolAllocatorINSt8__detail10_Hash_nodeISt4pairIK9COutPoint16CCoinsCacheEntryELb0EEELm152ELm8EE8resourceEv
Line
Count
Source
344
16.2M
    {
345
16.2M
        return m_resource;
346
16.2M
    }
_ZNK13PoolAllocatorISt4pairIK9COutPoint16CCoinsCacheEntryELm152ELm8EE8resourceEv
Line
Count
Source
344
16.6M
    {
345
16.6M
        return m_resource;
346
16.6M
    }
347
};
348
349
template <class T1, class T2, std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
350
bool operator==(const PoolAllocator<T1, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& a,
351
                const PoolAllocator<T2, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& b) noexcept
352
{
353
    return a.resource() == b.resource();
354
}
355
356
#endif // BITCOIN_SUPPORT_ALLOCATORS_POOL_H