12
12
* Although MemoryChunks are used by each of our MemoryContexts, future
13
13
* implementations may choose to implement their own method for storing chunk
14
14
* headers. The only requirement is that the header ends with an 8-byte value
15
- * which the least significant 3 -bits of are set to the MemoryContextMethodID
15
+ * which the least significant 4 -bits of are set to the MemoryContextMethodID
16
16
* of the given context.
17
17
*
18
18
* By default, a MemoryChunk is 8 bytes in size, however, when
25
25
* used to encode 4 separate pieces of information. Starting with the least
26
26
* significant bits of 'hdrmask', the bit space is reserved as follows:
27
27
*
28
- * 1. 3 -bits to indicate the MemoryContextMethodID as defined by
28
+ * 1. 4 -bits to indicate the MemoryContextMethodID as defined by
29
29
* MEMORY_CONTEXT_METHODID_MASK
30
30
* 2. 1-bit to denote an "external" chunk (see below)
31
31
* 3. 30-bits reserved for the MemoryContext to use for anything it
32
- * requires. Most MemoryContext likely want to store the size of the
32
+ * requires. Most MemoryContexts likely want to store the size of the
33
33
* chunk here.
34
34
* 4. 30-bits for the number of bytes that must be subtracted from the chunk
35
35
* to obtain the address of the block that the chunk is stored on.
36
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
+ *
37
45
* In some cases, for example when memory allocations become large, it's
38
46
* possible fields 3 and 4 above are not large enough to store the values
39
47
* required for the chunk. In this case, the MemoryContext can choose to mark
93
101
*/
94
102
#define MEMORYCHUNK_MAX_BLOCKOFFSET UINT64CONST(0x3FFFFFFF)
95
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
+ #define MEMORYCHUNK_BLOCKOFFSET_MASK UINT64CONST(0x3FFFFFFE)
109
+
96
110
/* define the least significant base-0 bit of each portion of the hdrmask */
97
111
#define MEMORYCHUNK_EXTERNAL_BASEBIT MEMORY_CONTEXT_METHODID_BITS
98
112
#define MEMORYCHUNK_VALUE_BASEBIT (MEMORYCHUNK_EXTERNAL_BASEBIT + 1)
99
- #define MEMORYCHUNK_BLOCKOFFSET_BASEBIT (MEMORYCHUNK_VALUE_BASEBIT + 30 )
113
+ #define MEMORYCHUNK_BLOCKOFFSET_BASEBIT (MEMORYCHUNK_VALUE_BASEBIT + 29 )
100
114
101
115
/*
102
116
* A magic number for storing in the free bits of an external chunk. This
@@ -131,11 +145,11 @@ typedef struct MemoryChunk
131
145
(((hdrmask) >> MEMORYCHUNK_VALUE_BASEBIT) & MEMORYCHUNK_MAX_VALUE)
132
146
133
147
/*
134
- * We should have used up all the bits here, so the compiler is likely to
135
- * optimize out the & MEMORYCHUNK_MAX_BLOCKOFFSET .
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 .
136
150
*/
137
151
#define HdrMaskBlockOffset (hdrmask ) \
138
- (((hdrmask) >> MEMORYCHUNK_BLOCKOFFSET_BASEBIT) & MEMORYCHUNK_MAX_BLOCKOFFSET )
152
+ (((hdrmask) >> MEMORYCHUNK_BLOCKOFFSET_BASEBIT) & MEMORYCHUNK_BLOCKOFFSET_MASK )
139
153
140
154
/* For external chunks only, check the magic number matches */
141
155
#define HdrMaskCheckMagic (hdrmask ) \
@@ -149,6 +163,7 @@ typedef struct MemoryChunk
149
163
* The number of bytes between 'block' and 'chunk' must be <=
150
164
* MEMORYCHUNK_MAX_BLOCKOFFSET.
151
165
* 'value' must be <= MEMORYCHUNK_MAX_VALUE.
166
+ * Both 'chunk' and 'block' must be MAXALIGNed pointers.
152
167
*/
153
168
static inline void
154
169
MemoryChunkSetHdrMask (MemoryChunk * chunk , void * block ,
@@ -157,7 +172,7 @@ MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block,
157
172
Size blockoffset = (char * ) chunk - (char * ) block ;
158
173
159
174
Assert ((char * ) chunk >= (char * ) block );
160
- Assert (blockoffset <= MEMORYCHUNK_MAX_BLOCKOFFSET );
175
+ Assert (( blockoffset & MEMORYCHUNK_BLOCKOFFSET_MASK ) == blockoffset );
161
176
Assert (value <= MEMORYCHUNK_MAX_VALUE );
162
177
Assert ((int ) methodid <= MEMORY_CONTEXT_METHODID_MASK );
163
178
@@ -225,6 +240,7 @@ MemoryChunkGetBlock(MemoryChunk *chunk)
225
240
}
226
241
227
242
/* cleanup all internal definitions */
243
+ #undef MEMORYCHUNK_BLOCKOFFSET_MASK
228
244
#undef MEMORYCHUNK_EXTERNAL_BASEBIT
229
245
#undef MEMORYCHUNK_VALUE_BASEBIT
230
246
#undef MEMORYCHUNK_BLOCKOFFSET_BASEBIT
0 commit comments