Coverage Report

Created: 2026-08-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/include/utils/memutils_memorychunk.h
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * memutils_memorychunk.h
4
 *    Here we define a struct named MemoryChunk which implementations of
5
 *    MemoryContexts may use as a header for chunks of memory they allocate.
6
 *
7
 * MemoryChunk provides a lightweight header that a MemoryContext can use to
8
 * store a reference back to the block which the given chunk is allocated on
9
 * and also an additional 30-bits to store another value such as the size of
10
 * the allocated chunk.
11
 *
12
 * Although MemoryChunks are used by each of our MemoryContexts, future
13
 * implementations may choose to implement their own method for storing chunk
14
 * headers.  The only requirement is that the header ends with an 8-byte value
15
 * which the least significant 4-bits of are set to the MemoryContextMethodID
16
 * of the given context.
17
 *
18
 * By default, a MemoryChunk is 8 bytes in size, however, when
19
 * MEMORY_CONTEXT_CHECKING is defined the header becomes 16 bytes in size due
20
 * to the additional requested_size field.  The MemoryContext may use this
21
 * field for whatever they wish, but it is intended to be used for additional
22
 * checks which are only done in MEMORY_CONTEXT_CHECKING builds.
23
 *
24
 * The MemoryChunk contains a uint64 field named 'hdrmask'.  This field is
25
 * used to encode 4 separate pieces of information.  Starting with the least
26
 * significant bits of 'hdrmask', the bit space is reserved as follows:
27
 *
28
 * 1. 4-bits to indicate the MemoryContextMethodID as defined by
29
 *    MEMORY_CONTEXT_METHODID_MASK
30
 * 2. 1-bit to denote an "external" chunk (see below)
31
 * 3. 30-bits reserved for the MemoryContext to use for anything it
32
 *    requires.  Most MemoryContexts likely want to store the size of the
33
 *    chunk here.
34
 * 4. 30-bits for the number of bytes that must be subtracted from the chunk
35
 *    to obtain the address of the block that the chunk is stored on.
36
 *
37
 * If you're paying close attention, you'll notice this adds up to 65 bits
38
 * rather than 64 bits.  This is because the highest-order bit of #3 is the
39
 * same bit as the lowest-order bit of #4.  We can do this as we insist that
40
 * the chunk and block pointers are both MAXALIGNed, therefore the relative
41
 * offset between those will always be a MAXALIGNed value which means the
42
 * lowest order bit is always 0.  When fetching the chunk to block offset we
43
 * mask out the lowest-order bit to ensure it's still zero.
44
 *
45
 * In some cases, for example when memory allocations become large, it's
46
 * possible fields 3 and 4 above are not large enough to store the values
47
 * required for the chunk.  In this case, the MemoryContext can choose to mark
48
 * the chunk as "external" by calling the MemoryChunkSetHdrMaskExternal()
49
 * function.  When this is done, fields 3 and 4 are unavailable for use by the
50
 * MemoryContext and it's up to the MemoryContext itself to devise its own
51
 * method for getting the reference to the block.
52
 *
53
 * Interface:
54
 *
55
 * MemoryChunkSetHdrMask:
56
 *    Used to set up a non-external MemoryChunk.
57
 *
58
 * MemoryChunkSetHdrMaskExternal:
59
 *    Used to set up an externally managed MemoryChunk.
60
 *
61
 * MemoryChunkIsExternal:
62
 *    Determine if the given MemoryChunk is externally managed, i.e.
63
 *    MemoryChunkSetHdrMaskExternal() was called on the chunk.
64
 *
65
 * MemoryChunkGetValue:
66
 *    For non-external chunks, return the stored 30-bit value as it was set
67
 *    in the call to MemoryChunkSetHdrMask().
68
 *
69
 * MemoryChunkGetBlock:
70
 *    For non-external chunks, return a pointer to the block as it was set
71
 *    in the call to MemoryChunkSetHdrMask().
72
 *
73
 * Also exports:
74
 *    MEMORYCHUNK_MAX_VALUE
75
 *    MEMORYCHUNK_MAX_BLOCKOFFSET
76
 *    PointerGetMemoryChunk
77
 *    MemoryChunkGetPointer
78
 *
79
 * Portions Copyright (c) 2022-2026, PostgreSQL Global Development Group
80
 * Portions Copyright (c) 1994, Regents of the University of California
81
 *
82
 * src/include/utils/memutils_memorychunk.h
83
 *
84
 *-------------------------------------------------------------------------
85
 */
86
87
#ifndef MEMUTILS_MEMORYCHUNK_H
88
#define MEMUTILS_MEMORYCHUNK_H
89
90
#include "utils/memutils_internal.h"
91
92
 /*
93
  * The maximum allowed value that MemoryContexts can store in the value
94
  * field.  Must be 1 less than a power of 2.
95
  */
96
694k
#define MEMORYCHUNK_MAX_VALUE     UINT64CONST(0x3FFFFFFF)
97
98
/*
99
 * The maximum distance in bytes that a MemoryChunk can be offset from the
100
 * block that is storing the chunk.  Must be 1 less than a power of 2.
101
 */
102
#define MEMORYCHUNK_MAX_BLOCKOFFSET   UINT64CONST(0x3FFFFFFF)
103
104
/*
105
 * As above, but mask out the lowest-order (always zero) bit as this is shared
106
 * with the MemoryChunkGetValue field.
107
 */
108
697k
#define MEMORYCHUNK_BLOCKOFFSET_MASK  UINT64CONST(0x3FFFFFFE)
109
110
/* define the least significant base-0 bit of each portion of the hdrmask */
111
22.9M
#define MEMORYCHUNK_EXTERNAL_BASEBIT  MEMORY_CONTEXT_METHODID_BITS
112
22.2M
#define MEMORYCHUNK_VALUE_BASEBIT   (MEMORYCHUNK_EXTERNAL_BASEBIT + 1)
113
11.0M
#define MEMORYCHUNK_BLOCKOFFSET_BASEBIT (MEMORYCHUNK_VALUE_BASEBIT + 29)
114
115
/*
116
 * A magic number for storing in the free bits of an external chunk.  This
117
 * must mask out the bits used for storing the MemoryContextMethodID and the
118
 * external bit.
119
 */
120
3.78k
#define MEMORYCHUNK_MAGIC   (UINT64CONST(0xB1A8DB858EB6EFBA) >> \
121
3.78k
                 MEMORYCHUNK_VALUE_BASEBIT << \
122
3.78k
                 MEMORYCHUNK_VALUE_BASEBIT)
123
124
typedef struct MemoryChunk
125
{
126
#ifdef MEMORY_CONTEXT_CHECKING
127
  Size    requested_size;
128
#endif
129
130
  /* bitfield for storing details about the chunk */
131
  uint64    hdrmask;    /* must be last */
132
} MemoryChunk;
133
134
/* Get the MemoryChunk from the pointer */
135
#define PointerGetMemoryChunk(p) \
136
701k
  ((MemoryChunk *) ((char *) (p) - sizeof(MemoryChunk)))
137
/* Get the pointer from the MemoryChunk */
138
#define MemoryChunkGetPointer(c) \
139
11.0M
  ((void *) ((char *) (c) + sizeof(MemoryChunk)))
140
141
/* private macros for making the inline functions below more simple */
142
#define HdrMaskIsExternal(hdrmask) \
143
701k
  ((hdrmask) & (((uint64) 1) << MEMORYCHUNK_EXTERNAL_BASEBIT))
144
#define HdrMaskGetValue(hdrmask) \
145
694k
  (((hdrmask) >> MEMORYCHUNK_VALUE_BASEBIT) & MEMORYCHUNK_MAX_VALUE)
146
147
/*
148
 * Shift the block offset down to the 0th bit position and mask off the single
149
 * bit that's shared with the MemoryChunkGetValue field.
150
 */
151
#define HdrMaskBlockOffset(hdrmask) \
152
697k
  (((hdrmask) >> MEMORYCHUNK_BLOCKOFFSET_BASEBIT) & MEMORYCHUNK_BLOCKOFFSET_MASK)
153
154
/* For external chunks only, check the magic number matches */
155
#define HdrMaskCheckMagic(hdrmask) \
156
  (MEMORYCHUNK_MAGIC == \
157
   ((hdrmask) >> MEMORYCHUNK_VALUE_BASEBIT << MEMORYCHUNK_VALUE_BASEBIT))
158
/*
159
 * MemoryChunkSetHdrMask
160
 *    Store the given 'block', 'chunk_size' and 'methodid' in the given
161
 *    MemoryChunk.
162
 *
163
 * The number of bytes between 'block' and 'chunk' must be <=
164
 * MEMORYCHUNK_MAX_BLOCKOFFSET.
165
 * 'value' must be <= MEMORYCHUNK_MAX_VALUE.
166
 * Both 'chunk' and 'block' must be MAXALIGNed pointers.
167
 */
168
static inline void
169
MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block,
170
            Size value, MemoryContextMethodID methodid)
171
10.4M
{
172
10.4M
  Size    blockoffset = (char *) chunk - (char *) block;
173
174
10.4M
  Assert((char *) chunk >= (char *) block);
175
10.4M
  Assert((blockoffset & MEMORYCHUNK_BLOCKOFFSET_MASK) == blockoffset);
176
10.4M
  Assert(value <= MEMORYCHUNK_MAX_VALUE);
177
10.4M
  Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK);
178
179
10.4M
  chunk->hdrmask = (((uint64) blockoffset) << MEMORYCHUNK_BLOCKOFFSET_BASEBIT) |
180
10.4M
    (((uint64) value) << MEMORYCHUNK_VALUE_BASEBIT) |
181
10.4M
    methodid;
182
10.4M
}
Unexecuted instantiation: nodeAgg.c:MemoryChunkSetHdrMask
Unexecuted instantiation: alignedalloc.c:MemoryChunkSetHdrMask
aset.c:MemoryChunkSetHdrMask
Line
Count
Source
171
10.4M
{
172
10.4M
  Size    blockoffset = (char *) chunk - (char *) block;
173
174
10.4M
  Assert((char *) chunk >= (char *) block);
175
10.4M
  Assert((blockoffset & MEMORYCHUNK_BLOCKOFFSET_MASK) == blockoffset);
176
10.4M
  Assert(value <= MEMORYCHUNK_MAX_VALUE);
177
10.4M
  Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK);
178
179
10.4M
  chunk->hdrmask = (((uint64) blockoffset) << MEMORYCHUNK_BLOCKOFFSET_BASEBIT) |
180
10.4M
    (((uint64) value) << MEMORYCHUNK_VALUE_BASEBIT) |
181
10.4M
    methodid;
182
10.4M
}
Unexecuted instantiation: bump.c:MemoryChunkSetHdrMask
Unexecuted instantiation: generation.c:MemoryChunkSetHdrMask
Unexecuted instantiation: mcxt.c:MemoryChunkSetHdrMask
Unexecuted instantiation: slab.c:MemoryChunkSetHdrMask
183
184
/*
185
 * MemoryChunkSetHdrMaskExternal
186
 *    Set 'chunk' as an externally managed chunk.  Here we only record the
187
 *    MemoryContextMethodID and set the external chunk bit.
188
 */
189
static inline void
190
MemoryChunkSetHdrMaskExternal(MemoryChunk *chunk,
191
                MemoryContextMethodID methodid)
192
3.78k
{
193
3.78k
  Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK);
194
195
3.78k
  chunk->hdrmask = MEMORYCHUNK_MAGIC | (((uint64) 1) << MEMORYCHUNK_EXTERNAL_BASEBIT) |
196
3.78k
    methodid;
197
3.78k
}
Unexecuted instantiation: nodeAgg.c:MemoryChunkSetHdrMaskExternal
Unexecuted instantiation: alignedalloc.c:MemoryChunkSetHdrMaskExternal
aset.c:MemoryChunkSetHdrMaskExternal
Line
Count
Source
192
3.78k
{
193
3.78k
  Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK);
194
195
3.78k
  chunk->hdrmask = MEMORYCHUNK_MAGIC | (((uint64) 1) << MEMORYCHUNK_EXTERNAL_BASEBIT) |
196
3.78k
    methodid;
197
3.78k
}
Unexecuted instantiation: bump.c:MemoryChunkSetHdrMaskExternal
Unexecuted instantiation: generation.c:MemoryChunkSetHdrMaskExternal
Unexecuted instantiation: mcxt.c:MemoryChunkSetHdrMaskExternal
Unexecuted instantiation: slab.c:MemoryChunkSetHdrMaskExternal
198
199
/*
200
 * MemoryChunkIsExternal
201
 *    Return true if 'chunk' is marked as external.
202
 */
203
static inline bool
204
MemoryChunkIsExternal(MemoryChunk *chunk)
205
701k
{
206
  /*
207
   * External chunks should always store MEMORYCHUNK_MAGIC in the upper
208
   * portion of the hdrmask, check that nothing has stomped on that.
209
   */
210
701k
  Assert(!HdrMaskIsExternal(chunk->hdrmask) ||
211
701k
       HdrMaskCheckMagic(chunk->hdrmask));
212
213
701k
  return HdrMaskIsExternal(chunk->hdrmask);
214
701k
}
Unexecuted instantiation: nodeAgg.c:MemoryChunkIsExternal
Unexecuted instantiation: alignedalloc.c:MemoryChunkIsExternal
aset.c:MemoryChunkIsExternal
Line
Count
Source
205
701k
{
206
  /*
207
   * External chunks should always store MEMORYCHUNK_MAGIC in the upper
208
   * portion of the hdrmask, check that nothing has stomped on that.
209
   */
210
701k
  Assert(!HdrMaskIsExternal(chunk->hdrmask) ||
211
701k
       HdrMaskCheckMagic(chunk->hdrmask));
212
213
701k
  return HdrMaskIsExternal(chunk->hdrmask);
214
701k
}
Unexecuted instantiation: bump.c:MemoryChunkIsExternal
Unexecuted instantiation: generation.c:MemoryChunkIsExternal
Unexecuted instantiation: mcxt.c:MemoryChunkIsExternal
Unexecuted instantiation: slab.c:MemoryChunkIsExternal
215
216
/*
217
 * MemoryChunkGetValue
218
 *    For non-external chunks, returns the value field as it was set in
219
 *    MemoryChunkSetHdrMask.
220
 */
221
static inline Size
222
MemoryChunkGetValue(MemoryChunk *chunk)
223
694k
{
224
694k
  Assert(!HdrMaskIsExternal(chunk->hdrmask));
225
226
694k
  return HdrMaskGetValue(chunk->hdrmask);
227
694k
}
Unexecuted instantiation: nodeAgg.c:MemoryChunkGetValue
Unexecuted instantiation: alignedalloc.c:MemoryChunkGetValue
aset.c:MemoryChunkGetValue
Line
Count
Source
223
694k
{
224
694k
  Assert(!HdrMaskIsExternal(chunk->hdrmask));
225
226
  return HdrMaskGetValue(chunk->hdrmask);
227
694k
}
Unexecuted instantiation: bump.c:MemoryChunkGetValue
Unexecuted instantiation: generation.c:MemoryChunkGetValue
Unexecuted instantiation: mcxt.c:MemoryChunkGetValue
Unexecuted instantiation: slab.c:MemoryChunkGetValue
228
229
/*
230
 * MemoryChunkGetBlock
231
 *    For non-external chunks, returns the pointer to the block as was set
232
 *    in MemoryChunkSetHdrMask.
233
 */
234
static inline void *
235
MemoryChunkGetBlock(MemoryChunk *chunk)
236
697k
{
237
697k
  Assert(!HdrMaskIsExternal(chunk->hdrmask));
238
239
  return (void *) ((char *) chunk - HdrMaskBlockOffset(chunk->hdrmask));
240
697k
}
Unexecuted instantiation: nodeAgg.c:MemoryChunkGetBlock
Unexecuted instantiation: alignedalloc.c:MemoryChunkGetBlock
aset.c:MemoryChunkGetBlock
Line
Count
Source
236
697k
{
237
697k
  Assert(!HdrMaskIsExternal(chunk->hdrmask));
238
239
  return (void *) ((char *) chunk - HdrMaskBlockOffset(chunk->hdrmask));
240
697k
}
Unexecuted instantiation: bump.c:MemoryChunkGetBlock
Unexecuted instantiation: generation.c:MemoryChunkGetBlock
Unexecuted instantiation: mcxt.c:MemoryChunkGetBlock
Unexecuted instantiation: slab.c:MemoryChunkGetBlock
241
242
/* cleanup all internal definitions */
243
#undef MEMORYCHUNK_BLOCKOFFSET_MASK
244
#undef MEMORYCHUNK_EXTERNAL_BASEBIT
245
#undef MEMORYCHUNK_VALUE_BASEBIT
246
#undef MEMORYCHUNK_BLOCKOFFSET_BASEBIT
247
#undef MEMORYCHUNK_MAGIC
248
#undef HdrMaskIsExternal
249
#undef HdrMaskGetValue
250
#undef HdrMaskBlockOffset
251
#undef HdrMaskCheckMagic
252
253
#endif              /* MEMUTILS_MEMORYCHUNK_H */