Skip to content

Commit 0c31c96

Browse files
vstinnermcepl
authored andcommitted
bpo-40609: Remove _Py_hashtable_t.key_size (pythonGH-20060)
Rewrite _Py_hashtable_t type to always store the key as a "const void *" pointer. Add an explicit "key" member to _Py_hashtable_entry_t. Remove _Py_hashtable_t.key_size member. hash and compare functions drop their hash table parameter, and their 'key' parameter type becomes "const void *".
1 parent de3656f commit 0c31c96

File tree

4 files changed

+113
-175
lines changed

4 files changed

+113
-175
lines changed

Modules/_tracemalloc.c

+42-53
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ static void raw_free(void *ptr);
1616
# define TRACE_DEBUG
1717
#endif
1818

19+
#define TO_PTR(key) ((const void *)(uintptr_t)key)
20+
#define FROM_PTR(key) ((uintptr_t)key)
21+
1922
/* Protected by the GIL */
2023
static struct {
2124
PyMemAllocatorEx mem;
@@ -226,28 +229,24 @@ set_reentrant(int reentrant)
226229

227230

228231
static Py_uhash_t
229-
hashtable_hash_pyobject(_Py_hashtable_t *ht, const void *pkey)
232+
hashtable_hash_pyobject(const void *key)
230233
{
231-
PyObject *obj;
232-
233-
_Py_HASHTABLE_READ_KEY(ht, pkey, obj);
234+
PyObject *obj = (PyObject *)key;
234235
return PyObject_Hash(obj);
235236
}
236237

237238

238239
static int
239-
hashtable_compare_unicode(_Py_hashtable_t *ht, const void *pkey,
240-
const _Py_hashtable_entry_t *entry)
240+
hashtable_compare_unicode(const void *key1, const void *key2)
241241
{
242-
PyObject *key1, *key2;
243-
244-
_Py_HASHTABLE_READ_KEY(ht, pkey, key1);
245-
_Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, key2);
246-
247-
if (key1 != NULL && key2 != NULL)
248-
return (PyUnicode_Compare(key1, key2) == 0);
249-
else
250-
return key1 == key2;
242+
PyObject *obj1 = (PyObject *)key1;
243+
PyObject *obj2 = (PyObject *)key2;
244+
if (obj1 != NULL && obj2 != NULL) {
245+
return (PyUnicode_Compare(obj1, obj2) == 0);
246+
}
247+
else {
248+
return obj1 == obj2;
249+
}
251250
}
252251

253252

@@ -266,28 +265,24 @@ hashtable_hash_pointer_t(_Py_hashtable_t *ht, const void *pkey)
266265

267266

268267
static int
269-
hashtable_compare_pointer_t(_Py_hashtable_t *ht, const void *pkey,
270-
const _Py_hashtable_entry_t *entry)
268+
hashtable_compare_pointer_t(const void *key1, const void *key2)
271269
{
272-
pointer_t ptr1, ptr2;
273-
274-
_Py_HASHTABLE_READ_KEY(ht, pkey, ptr1);
275-
_Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, ptr2);
270+
const pointer_t ptr1 = (pointer_t)key1;
271+
const pointer_t ptr2 = (pointer_t)key2;
276272

277273
/* compare pointer before domain, because pointer is more likely to be
278274
different */
279275
return (ptr1.ptr == ptr2.ptr && ptr1.domain == ptr2.domain);
280-
281276
}
282277

283278

284279
static _Py_hashtable_t *
285-
hashtable_new(size_t key_size, size_t data_size,
280+
hashtable_new(size_t data_size,
286281
_Py_hashtable_hash_func hash_func,
287282
_Py_hashtable_compare_func compare_func)
288283
{
289284
_Py_hashtable_allocator_t hashtable_alloc = {malloc, free};
290-
return _Py_hashtable_new_full(key_size, data_size, 0,
285+
return _Py_hashtable_new_full(data_size, 0,
291286
hash_func, compare_func,
292287
&hashtable_alloc);
293288
}
@@ -307,35 +302,33 @@ raw_free(void *ptr)
307302

308303

309304
static Py_uhash_t
310-
hashtable_hash_traceback(_Py_hashtable_t *ht, const void *pkey)
305+
hashtable_hash_traceback(const void *key)
311306
{
312-
traceback_t *traceback;
313-
314-
_Py_HASHTABLE_READ_KEY(ht, pkey, traceback);
307+
const traceback_t *traceback = (const traceback_t *)key;
315308
return traceback->hash;
316309
}
317310

318311

319312
static int
320-
hashtable_compare_traceback(_Py_hashtable_t *ht, const void *pkey,
321-
const _Py_hashtable_entry_t *entry)
313+
hashtable_compare_traceback(const void *key1, const void *key2)
322314
{
323-
traceback_t *traceback1, *traceback2;
324-
const frame_t *frame1, *frame2;
325-
int i;
326-
327-
_Py_HASHTABLE_READ_KEY(ht, pkey, traceback1);
328-
_Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, traceback2);
315+
const traceback_t *traceback1 = (const traceback_t *)key1;
316+
const traceback_t *traceback2 = (const traceback_t *)key2;
329317

330-
if (traceback1->nframe != traceback2->nframe)
318+
if (traceback1->nframe != traceback2->nframe) {
331319
return 0;
320+
}
321+
if (traceback1->total_nframe != traceback2->total_nframe) {
322+
return 0;
323+
}
332324

333-
for (i=0; i < traceback1->nframe; i++) {
334-
frame1 = &traceback1->frames[i];
335-
frame2 = &traceback2->frames[i];
325+
for (int i=0; i < traceback1->nframe; i++) {
326+
const frame_t *frame1 = &traceback1->frames[i];
327+
const frame_t *frame2 = &traceback2->frames[i];
336328

337-
if (frame1->lineno != frame2->lineno)
329+
if (frame1->lineno != frame2->lineno) {
338330
return 0;
331+
}
339332

340333
if (frame1->filename != frame2->filename) {
341334
assert(PyUnicode_Compare(frame1->filename, frame2->filename) != 0);
@@ -398,7 +391,7 @@ tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame)
398391
/* intern the filename */
399392
entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_filenames, filename);
400393
if (entry != NULL) {
401-
_Py_HASHTABLE_ENTRY_READ_KEY(tracemalloc_filenames, entry, filename);
394+
filename = (PyObject *)entry->key;
402395
}
403396
else {
404397
/* tracemalloc_filenames is responsible to keep a reference
@@ -492,7 +485,7 @@ traceback_new(void)
492485
/* intern the traceback */
493486
entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_tracebacks, traceback);
494487
if (entry != NULL) {
495-
_Py_HASHTABLE_ENTRY_READ_KEY(tracemalloc_tracebacks, entry, traceback);
488+
traceback = (traceback_t *)entry->key;
496489
}
497490
else {
498491
traceback_t *copy;
@@ -932,9 +925,7 @@ static int
932925
tracemalloc_clear_filename(_Py_hashtable_t *ht, _Py_hashtable_entry_t *entry,
933926
void *user_data)
934927
{
935-
PyObject *filename;
936-
937-
_Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, filename);
928+
PyObject *filename = (PyObject *)entry->key;
938929
Py_DECREF(filename);
939930
return 0;
940931
}
@@ -944,9 +935,7 @@ static int
944935
traceback_free_traceback(_Py_hashtable_t *ht, _Py_hashtable_entry_t *entry,
945936
void *user_data)
946937
{
947-
traceback_t *traceback;
948-
949-
_Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, traceback);
938+
traceback_t *traceback = (traceback_t *)entry->key;
950939
raw_free(traceback);
951940
return 0;
952941
}
@@ -1011,11 +1000,11 @@ tracemalloc_init(void)
10111000
}
10121001
#endif
10131002

1014-
tracemalloc_filenames = hashtable_new(sizeof(PyObject *), 0,
1003+
tracemalloc_filenames = hashtable_new(0,
10151004
hashtable_hash_pyobject,
10161005
hashtable_compare_unicode);
10171006

1018-
tracemalloc_tracebacks = hashtable_new(sizeof(traceback_t *), 0,
1007+
tracemalloc_tracebacks = hashtable_new(0,
10191008
hashtable_hash_traceback,
10201009
hashtable_compare_traceback);
10211010

@@ -1227,7 +1216,7 @@ traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table)
12271216
PyObject *frames, *frame;
12281217

12291218
if (intern_table != NULL) {
1230-
if (_Py_HASHTABLE_GET(intern_table, traceback, frames)) {
1219+
if (_Py_HASHTABLE_GET(intern_table, (const void *)traceback, frames)) {
12311220
Py_INCREF(frames);
12321221
return frames;
12331222
}
@@ -1431,7 +1420,7 @@ tracemalloc_get_traceback(_PyTraceMalloc_domain_t domain, uintptr_t ptr)
14311420
found = _Py_HASHTABLE_GET(tracemalloc_traces, key, trace);
14321421
}
14331422
else {
1434-
found = _Py_HASHTABLE_GET(tracemalloc_traces, ptr, trace);
1423+
found = _Py_HASHTABLE_GET(tracemalloc_traces, TO_PTR(ptr), trace);
14351424
}
14361425
TABLES_UNLOCK();
14371426

Modules/hashtable.h

+21-53
Original file line numberDiff line numberDiff line change
@@ -25,32 +25,13 @@ typedef struct {
2525
_Py_slist_item_t _Py_slist_item;
2626

2727
Py_uhash_t key_hash;
28-
29-
/* key (key_size bytes) and then data (data_size bytes) follows */
28+
void *key;
29+
/* data (data_size bytes) follows */
3030
} _Py_hashtable_entry_t;
3131

32-
#define _Py_HASHTABLE_ENTRY_PKEY(ENTRY) \
33-
((const void *)((char *)(ENTRY) \
34-
+ sizeof(_Py_hashtable_entry_t)))
35-
3632
#define _Py_HASHTABLE_ENTRY_PDATA(TABLE, ENTRY) \
3733
((const void *)((char *)(ENTRY) \
38-
+ sizeof(_Py_hashtable_entry_t) \
39-
+ (TABLE)->key_size))
40-
41-
/* Get a key value from pkey: use memcpy() rather than a pointer dereference
42-
to avoid memory alignment issues. */
43-
#define _Py_HASHTABLE_READ_KEY(TABLE, PKEY, DST_KEY) \
44-
do { \
45-
assert(sizeof(DST_KEY) == (TABLE)->key_size); \
46-
memcpy(&(DST_KEY), (PKEY), sizeof(DST_KEY)); \
47-
} while (0)
48-
49-
#define _Py_HASHTABLE_ENTRY_READ_KEY(TABLE, ENTRY, KEY) \
50-
do { \
51-
assert(sizeof(KEY) == (TABLE)->key_size); \
52-
memcpy(&(KEY), _Py_HASHTABLE_ENTRY_PKEY(ENTRY), sizeof(KEY)); \
53-
} while (0)
34+
+ sizeof(_Py_hashtable_entry_t)))
5435

5536
#define _Py_HASHTABLE_ENTRY_READ_DATA(TABLE, ENTRY, DATA) \
5637
do { \
@@ -73,15 +54,12 @@ typedef struct {
7354
struct _Py_hashtable_t;
7455
typedef struct _Py_hashtable_t _Py_hashtable_t;
7556

76-
typedef Py_uhash_t (*_Py_hashtable_hash_func) (_Py_hashtable_t *ht,
77-
const void *pkey);
78-
typedef int (*_Py_hashtable_compare_func) (_Py_hashtable_t *ht,
79-
const void *pkey,
80-
const _Py_hashtable_entry_t *he);
57+
typedef Py_uhash_t (*_Py_hashtable_hash_func) (const void *pkey);
58+
typedef int (*_Py_hashtable_compare_func) (const void *key1, const void *key2);
8159
typedef _Py_hashtable_entry_t* (*_Py_hashtable_get_entry_func)(_Py_hashtable_t *ht,
82-
const void *pkey);
60+
const void *key);
8361
typedef int (*_Py_hashtable_get_func) (_Py_hashtable_t *ht,
84-
const void *pkey, void *data);
62+
const void *key, void *data);
8563

8664
typedef struct {
8765
/* allocate a memory block */
@@ -97,7 +75,6 @@ struct _Py_hashtable_t {
9775
size_t num_buckets;
9876
size_t entries; /* Total number of entries in the table. */
9977
_Py_slist_t *buckets;
100-
size_t key_size;
10178
size_t data_size;
10279

10380
_Py_hashtable_get_func get_func;
@@ -108,24 +85,19 @@ struct _Py_hashtable_t {
10885
};
10986

11087
/* hash a pointer (void*) */
111-
PyAPI_FUNC(Py_uhash_t) _Py_hashtable_hash_ptr(
112-
struct _Py_hashtable_t *ht,
113-
const void *pkey);
88+
+PyAPI_FUNC(Py_uhash_t) _Py_hashtable_hash_ptr(const void *key);
11489

11590
/* comparison using memcmp() */
11691
PyAPI_FUNC(int) _Py_hashtable_compare_direct(
117-
_Py_hashtable_t *ht,
118-
const void *pkey,
119-
const _Py_hashtable_entry_t *entry);
92+
const void *key1,
93+
const void *key2);
12094

12195
PyAPI_FUNC(_Py_hashtable_t *) _Py_hashtable_new(
122-
size_t key_size,
12396
size_t data_size,
12497
_Py_hashtable_hash_func hash_func,
12598
_Py_hashtable_compare_func compare_func);
12699

127100
PyAPI_FUNC(_Py_hashtable_t *) _Py_hashtable_new_full(
128-
size_t key_size,
129101
size_t data_size,
130102
size_t init_size,
131103
_Py_hashtable_hash_func hash_func,
@@ -160,16 +132,15 @@ PyAPI_FUNC(size_t) _Py_hashtable_size(_Py_hashtable_t *ht);
160132
but use _Py_HASHTABLE_SET() and _Py_HASHTABLE_SET_NODATA() macros */
161133
PyAPI_FUNC(int) _Py_hashtable_set(
162134
_Py_hashtable_t *ht,
163-
size_t key_size,
164-
const void *pkey,
135+
const void *key,
165136
size_t data_size,
166137
const void *data);
167138

168139
#define _Py_HASHTABLE_SET(TABLE, KEY, DATA) \
169-
_Py_hashtable_set(TABLE, sizeof(KEY), &(KEY), sizeof(DATA), &(DATA))
140+
_Py_hashtable_set(TABLE, (KEY), sizeof(DATA), &(DATA))
170141

171142
#define _Py_HASHTABLE_SET_NODATA(TABLE, KEY) \
172-
_Py_hashtable_set(TABLE, sizeof(KEY), &(KEY), 0, NULL)
143+
_Py_hashtable_set(TABLE, (KEY), 0, NULL)
173144

174145

175146
/* Get an entry.
@@ -178,43 +149,40 @@ PyAPI_FUNC(int) _Py_hashtable_set(
178149
Don't call directly this function, but use _Py_HASHTABLE_GET_ENTRY()
179150
macro */
180151
static inline _Py_hashtable_entry_t *
181-
_Py_hashtable_get_entry(_Py_hashtable_t *ht, size_t key_size, const void *pkey)
152+
_Py_hashtable_get_entry(_Py_hashtable_t *ht, const void *key)
182153
{
183-
assert(key_size == ht->key_size);
184-
return ht->get_entry_func(ht, pkey);
154+
return ht->get_entry_func(ht, key);
185155
}
186156

187157
#define _Py_HASHTABLE_GET_ENTRY(TABLE, KEY) \
188-
_Py_hashtable_get_entry(TABLE, sizeof(KEY), &(KEY))
158+
_Py_hashtable_get_entry(TABLE, (const void *)(KEY))
189159

190160

191161
/* Get data from an entry. Copy entry data into data and return 1 if the entry
192162
exists, return 0 if the entry does not exist.
193163
194164
Don't call directly this function, but use _Py_HASHTABLE_GET() macro */
195165
static inline int
196-
_Py_hashtable_get(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
166+
_Py_hashtable_get(_Py_hashtable_t *ht, const void *key,
197167
size_t data_size, void *data)
198168
{
199-
assert(key_size == ht->key_size);
200169
assert(data_size == ht->data_size);
201-
return ht->get_func(ht, pkey, data);
170+
return ht->get_func(ht, key, data);
202171
}
203172

204173
#define _Py_HASHTABLE_GET(TABLE, KEY, DATA) \
205-
_Py_hashtable_get(TABLE, sizeof(KEY), &(KEY), sizeof(DATA), &(DATA))
174+
_Py_hashtable_get(TABLE, (KEY), sizeof(DATA), &(DATA))
206175

207176

208177
/* Don't call directly this function, but use _Py_HASHTABLE_POP() macro */
209178
PyAPI_FUNC(int) _Py_hashtable_pop(
210179
_Py_hashtable_t *ht,
211-
size_t key_size,
212-
const void *pkey,
180+
const void *key,
213181
size_t data_size,
214182
void *data);
215183

216184
#define _Py_HASHTABLE_POP(TABLE, KEY, DATA) \
217-
_Py_hashtable_pop(TABLE, sizeof(KEY), &(KEY), sizeof(DATA), &(DATA))
185+
_Py_hashtable_pop(TABLE, (KEY), sizeof(DATA), &(DATA))
218186

219187

220188
#endif /* Py_LIMITED_API */

0 commit comments

Comments
 (0)