1 /* Dictionary object implementation using a hash table */
2
3 /* The distribution includes a separate file, Objects/dictnotes.txt,
4 describing explorations into dictionary design and optimization.
5 It covers typical dictionary use patterns, the parameters for
6 tuning dictionaries, and several ideas for possible optimizations.
7 */
8
9 /* PyDictKeysObject
10
11 This implements the dictionary's hashtable.
12
13 As of Python 3.6, this is compact and ordered. Basic idea is described here:
14 * https://mail.python.org/pipermail/python-dev/2012-December/123028.html
15 * https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html
16
17 layout:
18
19 +---------------------+
20 | dk_refcnt |
21 | dk_log2_size |
22 | dk_log2_index_bytes |
23 | dk_kind |
24 | dk_version |
25 | dk_usable |
26 | dk_nentries |
27 +---------------------+
28 | dk_indices[] |
29 | |
30 +---------------------+
31 | dk_entries[] |
32 | |
33 +---------------------+
34
35 dk_indices is actual hashtable. It holds index in entries, or DKIX_EMPTY(-1)
36 or DKIX_DUMMY(-2).
37 Size of indices is dk_size. Type of each index in indices is vary on dk_size:
38
39 * int8 for dk_size <= 128
40 * int16 for 256 <= dk_size <= 2**15
41 * int32 for 2**16 <= dk_size <= 2**31
42 * int64 for 2**32 <= dk_size
43
44 dk_entries is array of PyDictKeyEntry when dk_kind == DICT_KEYS_GENERAL or
45 PyDictUnicodeEntry otherwise. Its length is USABLE_FRACTION(dk_size).
46
47 NOTE: Since negative value is used for DKIX_EMPTY and DKIX_DUMMY, type of
48 dk_indices entry is signed integer and int16 is used for table which
49 dk_size == 256.
50 */
51
52
53 /*
54 The DictObject can be in one of two forms.
55
56 Either:
57 A combined table:
58 ma_values == NULL, dk_refcnt == 1.
59 Values are stored in the me_value field of the PyDictKeyEntry.
60 Or:
61 A split table:
62 ma_values != NULL, dk_refcnt >= 1
63 Values are stored in the ma_values array.
64 Only string (unicode) keys are allowed.
65
66 There are four kinds of slots in the table (slot is index, and
67 DK_ENTRIES(keys)[index] if index >= 0):
68
69 1. Unused. index == DKIX_EMPTY
70 Does not hold an active (key, value) pair now and never did. Unused can
71 transition to Active upon key insertion. This is each slot's initial state.
72
73 2. Active. index >= 0, me_key != NULL and me_value != NULL
74 Holds an active (key, value) pair. Active can transition to Dummy or
75 Pending upon key deletion (for combined and split tables respectively).
76 This is the only case in which me_value != NULL.
77
78 3. Dummy. index == DKIX_DUMMY (combined only)
79 Previously held an active (key, value) pair, but that was deleted and an
80 active pair has not yet overwritten the slot. Dummy can transition to
81 Active upon key insertion. Dummy slots cannot be made Unused again
82 else the probe sequence in case of collision would have no way to know
83 they were once active.
84 In free-threaded builds dummy slots are not re-used to allow lock-free
85 lookups to proceed safely.
86
87 4. Pending. index >= 0, key != NULL, and value == NULL (split only)
88 Not yet inserted in split-table.
89 */
90
91 /*
92 Preserving insertion order
93
94 It's simple for combined table. Since dk_entries is mostly append only, we can
95 get insertion order by just iterating dk_entries.
96
97 One exception is .popitem(). It removes last item in dk_entries and decrement
98 dk_nentries to achieve amortized O(1). Since there are DKIX_DUMMY remains in
99 dk_indices, we can't increment dk_usable even though dk_nentries is
100 decremented.
101
102 To preserve the order in a split table, a bit vector is used to record the
103 insertion order. When a key is inserted the bit vector is shifted up by 4 bits
104 and the index of the key is stored in the low 4 bits.
105 As a consequence of this, split keys have a maximum size of 16.
106 */
107
108 /* PyDict_MINSIZE is the starting size for any new dict.
109 * 8 allows dicts with no more than 5 active entries; experiments suggested
110 * this suffices for the majority of dicts (consisting mostly of usually-small
111 * dicts created to pass keyword arguments).
112 * Making this 8, rather than 4 reduces the number of resizes for most
113 * dictionaries, without any significant extra memory use.
114 */
115 #define PyDict_LOG_MINSIZE 3
116 #define PyDict_MINSIZE 8
117
118 #include "Python.h"
119 #include "pycore_bitutils.h" // _Py_bit_length
120 #include "pycore_call.h" // _PyObject_CallNoArgs()
121 #include "pycore_ceval.h" // _PyEval_GetBuiltin()
122 #include "pycore_code.h" // stats
123 #include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION, Py_END_CRITICAL_SECTION
124 #include "pycore_dict.h" // export _PyDict_SizeOf()
125 #include "pycore_freelist.h" // _PyFreeListState_GET()
126 #include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
127 #include "pycore_object.h" // _PyObject_GC_TRACK(), _PyDebugAllocatorStats()
128 #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_SSIZE_RELAXED
129 #include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
130 #include "pycore_pystate.h" // _PyThreadState_GET()
131 #include "pycore_setobject.h" // _PySet_NextEntry()
132 #include "stringlib/eq.h" // unicode_eq()
133
134 #include <stdbool.h>
135
136 /*[clinic input]
137 class dict "PyDictObject *" "&PyDict_Type"
138 [clinic start generated code]*/
139 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=f157a5a0ce9589d6]*/
140
141
142 /*
143 To ensure the lookup algorithm terminates, there must be at least one Unused
144 slot (NULL key) in the table.
145 To avoid slowing down lookups on a near-full table, we resize the table when
146 it's USABLE_FRACTION (currently two-thirds) full.
147 */
148
149 #ifdef Py_GIL_DISABLED
150
151 static inline void
ASSERT_DICT_LOCKED(PyObject * op)152 ASSERT_DICT_LOCKED(PyObject *op)
153 {
154 _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
155 }
156 #define ASSERT_DICT_LOCKED(op) ASSERT_DICT_LOCKED(_Py_CAST(PyObject*, op))
157 #define ASSERT_WORLD_STOPPED_OR_DICT_LOCKED(op) \
158 if (!_PyInterpreterState_GET()->stoptheworld.world_stopped) { \
159 ASSERT_DICT_LOCKED(op); \
160 }
161 #define ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(op) \
162 if (!_PyInterpreterState_GET()->stoptheworld.world_stopped) { \
163 _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); \
164 }
165
166 #define IS_DICT_SHARED(mp) _PyObject_GC_IS_SHARED(mp)
167 #define SET_DICT_SHARED(mp) _PyObject_GC_SET_SHARED(mp)
168 #define LOAD_INDEX(keys, size, idx) _Py_atomic_load_int##size##_relaxed(&((const int##size##_t*)keys->dk_indices)[idx]);
169 #define STORE_INDEX(keys, size, idx, value) _Py_atomic_store_int##size##_relaxed(&((int##size##_t*)keys->dk_indices)[idx], (int##size##_t)value);
170 #define ASSERT_OWNED_OR_SHARED(mp) \
171 assert(_Py_IsOwnedByCurrentThread((PyObject *)mp) || IS_DICT_SHARED(mp));
172
173 #define LOCK_KEYS_IF_SPLIT(keys, kind) \
174 if (kind == DICT_KEYS_SPLIT) { \
175 LOCK_KEYS(keys); \
176 }
177
178 #define UNLOCK_KEYS_IF_SPLIT(keys, kind) \
179 if (kind == DICT_KEYS_SPLIT) { \
180 UNLOCK_KEYS(keys); \
181 }
182
183 static inline Py_ssize_t
load_keys_nentries(PyDictObject * mp)184 load_keys_nentries(PyDictObject *mp)
185 {
186 PyDictKeysObject *keys = _Py_atomic_load_ptr(&mp->ma_keys);
187 return _Py_atomic_load_ssize(&keys->dk_nentries);
188 }
189
190 static inline void
set_keys(PyDictObject * mp,PyDictKeysObject * keys)191 set_keys(PyDictObject *mp, PyDictKeysObject *keys)
192 {
193 ASSERT_OWNED_OR_SHARED(mp);
194 _Py_atomic_store_ptr_release(&mp->ma_keys, keys);
195 }
196
197 static inline void
set_values(PyDictObject * mp,PyDictValues * values)198 set_values(PyDictObject *mp, PyDictValues *values)
199 {
200 ASSERT_OWNED_OR_SHARED(mp);
201 _Py_atomic_store_ptr_release(&mp->ma_values, values);
202 }
203
204 #define LOCK_KEYS(keys) PyMutex_LockFlags(&keys->dk_mutex, _Py_LOCK_DONT_DETACH)
205 #define UNLOCK_KEYS(keys) PyMutex_Unlock(&keys->dk_mutex)
206
207 #define ASSERT_KEYS_LOCKED(keys) assert(PyMutex_IsLocked(&keys->dk_mutex))
208 #define LOAD_SHARED_KEY(key) _Py_atomic_load_ptr_acquire(&key)
209 #define STORE_SHARED_KEY(key, value) _Py_atomic_store_ptr_release(&key, value)
210 // Inc refs the keys object, giving the previous value
211 #define INCREF_KEYS(dk) _Py_atomic_add_ssize(&dk->dk_refcnt, 1)
212 // Dec refs the keys object, giving the previous value
213 #define DECREF_KEYS(dk) _Py_atomic_add_ssize(&dk->dk_refcnt, -1)
214 #define LOAD_KEYS_NENTRIES(keys) _Py_atomic_load_ssize_relaxed(&keys->dk_nentries)
215
216 #define INCREF_KEYS_FT(dk) dictkeys_incref(dk)
217 #define DECREF_KEYS_FT(dk, shared) dictkeys_decref(_PyInterpreterState_GET(), dk, shared)
218
split_keys_entry_added(PyDictKeysObject * keys)219 static inline void split_keys_entry_added(PyDictKeysObject *keys)
220 {
221 ASSERT_KEYS_LOCKED(keys);
222
223 // We increase before we decrease so we never get too small of a value
224 // when we're racing with reads
225 _Py_atomic_store_ssize_relaxed(&keys->dk_nentries, keys->dk_nentries + 1);
226 _Py_atomic_store_ssize_release(&keys->dk_usable, keys->dk_usable - 1);
227 }
228
229 #else /* Py_GIL_DISABLED */
230
231 #define ASSERT_DICT_LOCKED(op)
232 #define ASSERT_WORLD_STOPPED_OR_DICT_LOCKED(op)
233 #define ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(op)
234 #define LOCK_KEYS(keys)
235 #define UNLOCK_KEYS(keys)
236 #define ASSERT_KEYS_LOCKED(keys)
237 #define LOAD_SHARED_KEY(key) key
238 #define STORE_SHARED_KEY(key, value) key = value
239 #define INCREF_KEYS(dk) dk->dk_refcnt++
240 #define DECREF_KEYS(dk) dk->dk_refcnt--
241 #define LOAD_KEYS_NENTRIES(keys) keys->dk_nentries
242 #define INCREF_KEYS_FT(dk)
243 #define DECREF_KEYS_FT(dk, shared)
244 #define LOCK_KEYS_IF_SPLIT(keys, kind)
245 #define UNLOCK_KEYS_IF_SPLIT(keys, kind)
246 #define IS_DICT_SHARED(mp) (false)
247 #define SET_DICT_SHARED(mp)
248 #define LOAD_INDEX(keys, size, idx) ((const int##size##_t*)(keys->dk_indices))[idx]
249 #define STORE_INDEX(keys, size, idx, value) ((int##size##_t*)(keys->dk_indices))[idx] = (int##size##_t)value
250
split_keys_entry_added(PyDictKeysObject * keys)251 static inline void split_keys_entry_added(PyDictKeysObject *keys)
252 {
253 keys->dk_usable--;
254 keys->dk_nentries++;
255 }
256
257 static inline void
set_keys(PyDictObject * mp,PyDictKeysObject * keys)258 set_keys(PyDictObject *mp, PyDictKeysObject *keys)
259 {
260 mp->ma_keys = keys;
261 }
262
263 static inline void
set_values(PyDictObject * mp,PyDictValues * values)264 set_values(PyDictObject *mp, PyDictValues *values)
265 {
266 mp->ma_values = values;
267 }
268
269 static inline Py_ssize_t
load_keys_nentries(PyDictObject * mp)270 load_keys_nentries(PyDictObject *mp)
271 {
272 return mp->ma_keys->dk_nentries;
273 }
274
275
276 #endif
277
278 #define STORE_KEY(ep, key) FT_ATOMIC_STORE_PTR_RELEASE(ep->me_key, key)
279 #define STORE_VALUE(ep, value) FT_ATOMIC_STORE_PTR_RELEASE(ep->me_value, value)
280 #define STORE_SPLIT_VALUE(mp, idx, value) FT_ATOMIC_STORE_PTR_RELEASE(mp->ma_values->values[idx], value)
281 #define STORE_HASH(ep, hash) FT_ATOMIC_STORE_SSIZE_RELAXED(ep->me_hash, hash)
282 #define STORE_KEYS_USABLE(keys, usable) FT_ATOMIC_STORE_SSIZE_RELAXED(keys->dk_usable, usable)
283 #define STORE_KEYS_NENTRIES(keys, nentries) FT_ATOMIC_STORE_SSIZE_RELAXED(keys->dk_nentries, nentries)
284 #define STORE_USED(mp, used) FT_ATOMIC_STORE_SSIZE_RELAXED(mp->ma_used, used)
285
286 #define PERTURB_SHIFT 5
287
288 /*
289 Major subtleties ahead: Most hash schemes depend on having a "good" hash
290 function, in the sense of simulating randomness. Python doesn't: its most
291 important hash functions (for ints) are very regular in common
292 cases:
293
294 >>>[hash(i) for i in range(4)]
295 [0, 1, 2, 3]
296
297 This isn't necessarily bad! To the contrary, in a table of size 2**i, taking
298 the low-order i bits as the initial table index is extremely fast, and there
299 are no collisions at all for dicts indexed by a contiguous range of ints. So
300 this gives better-than-random behavior in common cases, and that's very
301 desirable.
302
303 OTOH, when collisions occur, the tendency to fill contiguous slices of the
304 hash table makes a good collision resolution strategy crucial. Taking only
305 the last i bits of the hash code is also vulnerable: for example, consider
306 the list [i << 16 for i in range(20000)] as a set of keys. Since ints are
307 their own hash codes, and this fits in a dict of size 2**15, the last 15 bits
308 of every hash code are all 0: they *all* map to the same table index.
309
310 But catering to unusual cases should not slow the usual ones, so we just take
311 the last i bits anyway. It's up to collision resolution to do the rest. If
312 we *usually* find the key we're looking for on the first try (and, it turns
313 out, we usually do -- the table load factor is kept under 2/3, so the odds
314 are solidly in our favor), then it makes best sense to keep the initial index
315 computation dirt cheap.
316
317 The first half of collision resolution is to visit table indices via this
318 recurrence:
319
320 j = ((5*j) + 1) mod 2**i
321
322 For any initial j in range(2**i), repeating that 2**i times generates each
323 int in range(2**i) exactly once (see any text on random-number generation for
324 proof). By itself, this doesn't help much: like linear probing (setting
325 j += 1, or j -= 1, on each loop trip), it scans the table entries in a fixed
326 order. This would be bad, except that's not the only thing we do, and it's
327 actually *good* in the common cases where hash keys are consecutive. In an
328 example that's really too small to make this entirely clear, for a table of
329 size 2**3 the order of indices is:
330
331 0 -> 1 -> 6 -> 7 -> 4 -> 5 -> 2 -> 3 -> 0 [and here it's repeating]
332
333 If two things come in at index 5, the first place we look after is index 2,
334 not 6, so if another comes in at index 6 the collision at 5 didn't hurt it.
335 Linear probing is deadly in this case because there the fixed probe order
336 is the *same* as the order consecutive keys are likely to arrive. But it's
337 extremely unlikely hash codes will follow a 5*j+1 recurrence by accident,
338 and certain that consecutive hash codes do not.
339
340 The other half of the strategy is to get the other bits of the hash code
341 into play. This is done by initializing a (unsigned) vrbl "perturb" to the
342 full hash code, and changing the recurrence to:
343
344 perturb >>= PERTURB_SHIFT;
345 j = (5*j) + 1 + perturb;
346 use j % 2**i as the next table index;
347
348 Now the probe sequence depends (eventually) on every bit in the hash code,
349 and the pseudo-scrambling property of recurring on 5*j+1 is more valuable,
350 because it quickly magnifies small differences in the bits that didn't affect
351 the initial index. Note that because perturb is unsigned, if the recurrence
352 is executed often enough perturb eventually becomes and remains 0. At that
353 point (very rarely reached) the recurrence is on (just) 5*j+1 again, and
354 that's certain to find an empty slot eventually (since it generates every int
355 in range(2**i), and we make sure there's always at least one empty slot).
356
357 Selecting a good value for PERTURB_SHIFT is a balancing act. You want it
358 small so that the high bits of the hash code continue to affect the probe
359 sequence across iterations; but you want it large so that in really bad cases
360 the high-order hash bits have an effect on early iterations. 5 was "the
361 best" in minimizing total collisions across experiments Tim Peters ran (on
362 both normal and pathological cases), but 4 and 6 weren't significantly worse.
363
364 Historical: Reimer Behrends contributed the idea of using a polynomial-based
365 approach, using repeated multiplication by x in GF(2**n) where an irreducible
366 polynomial for each table size was chosen such that x was a primitive root.
367 Christian Tismer later extended that to use division by x instead, as an
368 efficient way to get the high bits of the hash code into play. This scheme
369 also gave excellent collision statistics, but was more expensive: two
370 if-tests were required inside the loop; computing "the next" index took about
371 the same number of operations but without as much potential parallelism
372 (e.g., computing 5*j can go on at the same time as computing 1+perturb in the
373 above, and then shifting perturb can be done while the table index is being
374 masked); and the PyDictObject struct required a member to hold the table's
375 polynomial. In Tim's experiments the current scheme ran faster, produced
376 equally good collision statistics, needed less code & used less memory.
377
378 */
379
380 static int dictresize(PyInterpreterState *interp, PyDictObject *mp,
381 uint8_t log_newsize, int unicode);
382
383 static PyObject* dict_iter(PyObject *dict);
384
385 static int
386 setitem_lock_held(PyDictObject *mp, PyObject *key, PyObject *value);
387 static int
388 dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_value,
389 PyObject **result, int incref_result);
390
391 #ifndef NDEBUG
392 static int _PyObject_InlineValuesConsistencyCheck(PyObject *obj);
393 #endif
394
395 #include "clinic/dictobject.c.h"
396
397
398 #ifdef WITH_FREELISTS
399 static struct _Py_dict_freelist *
get_dict_freelist(void)400 get_dict_freelist(void)
401 {
402 struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
403 return &freelists->dicts;
404 }
405
406 static struct _Py_dictkeys_freelist *
get_dictkeys_freelist(void)407 get_dictkeys_freelist(void)
408 {
409 struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
410 return &freelists->dictkeys;
411 }
412 #endif
413
414
415 void
_PyDict_ClearFreeList(struct _Py_object_freelists * freelists,int is_finalization)416 _PyDict_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization)
417 {
418 #ifdef WITH_FREELISTS
419 struct _Py_dict_freelist *freelist = &freelists->dicts;
420 while (freelist->numfree > 0) {
421 PyDictObject *op = freelist->items[--freelist->numfree];
422 assert(PyDict_CheckExact(op));
423 PyObject_GC_Del(op);
424 }
425 struct _Py_dictkeys_freelist *keys_freelist = &freelists->dictkeys;
426 while (keys_freelist->numfree > 0) {
427 PyMem_Free(keys_freelist->items[--keys_freelist->numfree]);
428 }
429 if (is_finalization) {
430 freelist->numfree = -1;
431 keys_freelist->numfree = -1;
432 }
433 #endif
434 }
435
436 static inline Py_hash_t
unicode_get_hash(PyObject * o)437 unicode_get_hash(PyObject *o)
438 {
439 assert(PyUnicode_CheckExact(o));
440 return FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyASCIIObject_CAST(o)->hash);
441 }
442
443 /* Print summary info about the state of the optimized allocator */
444 void
_PyDict_DebugMallocStats(FILE * out)445 _PyDict_DebugMallocStats(FILE *out)
446 {
447 #ifdef WITH_FREELISTS
448 struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
449 _PyDebugAllocatorStats(out, "free PyDictObject",
450 dict_freelist->numfree, sizeof(PyDictObject));
451 struct _Py_dictkeys_freelist *dictkeys_freelist = get_dictkeys_freelist();
452 _PyDebugAllocatorStats(out, "free PyDictKeysObject",
453 dictkeys_freelist->numfree, sizeof(PyDictKeysObject));
454 #endif
455 }
456
457 #define DK_MASK(dk) (DK_SIZE(dk)-1)
458
459 static void free_keys_object(PyDictKeysObject *keys, bool use_qsbr);
460
461 /* PyDictKeysObject has refcounts like PyObject does, so we have the
462 following two functions to mirror what Py_INCREF() and Py_DECREF() do.
463 (Keep in mind that PyDictKeysObject isn't actually a PyObject.)
464 Likewise a PyDictKeysObject can be immortal (e.g. Py_EMPTY_KEYS),
465 so we apply a naive version of what Py_INCREF() and Py_DECREF() do
466 for immortal objects. */
467
468 static inline void
dictkeys_incref(PyDictKeysObject * dk)469 dictkeys_incref(PyDictKeysObject *dk)
470 {
471 if (FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_refcnt) == _Py_IMMORTAL_REFCNT) {
472 return;
473 }
474 #ifdef Py_REF_DEBUG
475 _Py_IncRefTotal(_PyThreadState_GET());
476 #endif
477 INCREF_KEYS(dk);
478 }
479
480 static inline void
dictkeys_decref(PyInterpreterState * interp,PyDictKeysObject * dk,bool use_qsbr)481 dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk, bool use_qsbr)
482 {
483 if (FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_refcnt) == _Py_IMMORTAL_REFCNT) {
484 return;
485 }
486 assert(FT_ATOMIC_LOAD_SSIZE(dk->dk_refcnt) > 0);
487 #ifdef Py_REF_DEBUG
488 _Py_DecRefTotal(_PyThreadState_GET());
489 #endif
490 if (DECREF_KEYS(dk) == 1) {
491 if (DK_IS_UNICODE(dk)) {
492 PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dk);
493 Py_ssize_t i, n;
494 for (i = 0, n = dk->dk_nentries; i < n; i++) {
495 Py_XDECREF(entries[i].me_key);
496 Py_XDECREF(entries[i].me_value);
497 }
498 }
499 else {
500 PyDictKeyEntry *entries = DK_ENTRIES(dk);
501 Py_ssize_t i, n;
502 for (i = 0, n = dk->dk_nentries; i < n; i++) {
503 Py_XDECREF(entries[i].me_key);
504 Py_XDECREF(entries[i].me_value);
505 }
506 }
507 free_keys_object(dk, use_qsbr);
508 }
509 }
510
511 /* lookup indices. returns DKIX_EMPTY, DKIX_DUMMY, or ix >=0 */
512 static inline Py_ssize_t
dictkeys_get_index(const PyDictKeysObject * keys,Py_ssize_t i)513 dictkeys_get_index(const PyDictKeysObject *keys, Py_ssize_t i)
514 {
515 int log2size = DK_LOG_SIZE(keys);
516 Py_ssize_t ix;
517
518 if (log2size < 8) {
519 ix = LOAD_INDEX(keys, 8, i);
520 }
521 else if (log2size < 16) {
522 ix = LOAD_INDEX(keys, 16, i);
523 }
524 #if SIZEOF_VOID_P > 4
525 else if (log2size >= 32) {
526 ix = LOAD_INDEX(keys, 64, i);
527 }
528 #endif
529 else {
530 ix = LOAD_INDEX(keys, 32, i);
531 }
532 assert(ix >= DKIX_DUMMY);
533 return ix;
534 }
535
536 /* write to indices. */
537 static inline void
dictkeys_set_index(PyDictKeysObject * keys,Py_ssize_t i,Py_ssize_t ix)538 dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix)
539 {
540 int log2size = DK_LOG_SIZE(keys);
541
542 assert(ix >= DKIX_DUMMY);
543 assert(keys->dk_version == 0);
544
545 if (log2size < 8) {
546 assert(ix <= 0x7f);
547 STORE_INDEX(keys, 8, i, ix);
548 }
549 else if (log2size < 16) {
550 assert(ix <= 0x7fff);
551 STORE_INDEX(keys, 16, i, ix);
552 }
553 #if SIZEOF_VOID_P > 4
554 else if (log2size >= 32) {
555 STORE_INDEX(keys, 64, i, ix);
556 }
557 #endif
558 else {
559 assert(ix <= 0x7fffffff);
560 STORE_INDEX(keys, 32, i, ix);
561 }
562 }
563
564
565 /* USABLE_FRACTION is the maximum dictionary load.
566 * Increasing this ratio makes dictionaries more dense resulting in more
567 * collisions. Decreasing it improves sparseness at the expense of spreading
568 * indices over more cache lines and at the cost of total memory consumed.
569 *
570 * USABLE_FRACTION must obey the following:
571 * (0 < USABLE_FRACTION(n) < n) for all n >= 2
572 *
573 * USABLE_FRACTION should be quick to calculate.
574 * Fractions around 1/2 to 2/3 seem to work well in practice.
575 */
576 #define USABLE_FRACTION(n) (((n) << 1)/3)
577
578 /* Find the smallest dk_size >= minsize. */
579 static inline uint8_t
calculate_log2_keysize(Py_ssize_t minsize)580 calculate_log2_keysize(Py_ssize_t minsize)
581 {
582 #if SIZEOF_LONG == SIZEOF_SIZE_T
583 minsize = (minsize | PyDict_MINSIZE) - 1;
584 return _Py_bit_length(minsize | (PyDict_MINSIZE-1));
585 #elif defined(_MSC_VER)
586 // On 64bit Windows, sizeof(long) == 4.
587 minsize = (minsize | PyDict_MINSIZE) - 1;
588 unsigned long msb;
589 _BitScanReverse64(&msb, (uint64_t)minsize);
590 return (uint8_t)(msb + 1);
591 #else
592 uint8_t log2_size;
593 for (log2_size = PyDict_LOG_MINSIZE;
594 (((Py_ssize_t)1) << log2_size) < minsize;
595 log2_size++)
596 ;
597 return log2_size;
598 #endif
599 }
600
601 /* estimate_keysize is reverse function of USABLE_FRACTION.
602 *
603 * This can be used to reserve enough size to insert n entries without
604 * resizing.
605 */
606 static inline uint8_t
estimate_log2_keysize(Py_ssize_t n)607 estimate_log2_keysize(Py_ssize_t n)
608 {
609 return calculate_log2_keysize((n*3 + 1) / 2);
610 }
611
612
613 /* GROWTH_RATE. Growth rate upon hitting maximum load.
614 * Currently set to used*3.
615 * This means that dicts double in size when growing without deletions,
616 * but have more head room when the number of deletions is on a par with the
617 * number of insertions. See also bpo-17563 and bpo-33205.
618 *
619 * GROWTH_RATE was set to used*4 up to version 3.2.
620 * GROWTH_RATE was set to used*2 in version 3.3.0
621 * GROWTH_RATE was set to used*2 + capacity/2 in 3.4.0-3.6.0.
622 */
623 #define GROWTH_RATE(d) ((d)->ma_used*3)
624
625 /* This immutable, empty PyDictKeysObject is used for PyDict_Clear()
626 * (which cannot fail and thus can do no allocation).
627 */
628 static PyDictKeysObject empty_keys_struct = {
629 _Py_IMMORTAL_REFCNT, /* dk_refcnt */
630 0, /* dk_log2_size */
631 0, /* dk_log2_index_bytes */
632 DICT_KEYS_UNICODE, /* dk_kind */
633 #ifdef Py_GIL_DISABLED
634 {0}, /* dk_mutex */
635 #endif
636 1, /* dk_version */
637 0, /* dk_usable (immutable) */
638 0, /* dk_nentries */
639 {DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY,
640 DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY}, /* dk_indices */
641 };
642
643 #define Py_EMPTY_KEYS &empty_keys_struct
644
645 /* Uncomment to check the dict content in _PyDict_CheckConsistency() */
646 // #define DEBUG_PYDICT
647
648 #ifdef DEBUG_PYDICT
649 # define ASSERT_CONSISTENT(op) assert(_PyDict_CheckConsistency((PyObject *)(op), 1))
650 #else
651 # define ASSERT_CONSISTENT(op) assert(_PyDict_CheckConsistency((PyObject *)(op), 0))
652 #endif
653
654 static inline int
get_index_from_order(PyDictObject * mp,Py_ssize_t i)655 get_index_from_order(PyDictObject *mp, Py_ssize_t i)
656 {
657 assert(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
658 assert(i < mp->ma_values->size);
659 uint8_t *array = get_insertion_order_array(mp->ma_values);
660 return array[i];
661 }
662
663 #ifdef DEBUG_PYDICT
664 static void
dump_entries(PyDictKeysObject * dk)665 dump_entries(PyDictKeysObject *dk)
666 {
667 for (Py_ssize_t i = 0; i < dk->dk_nentries; i++) {
668 if (DK_IS_UNICODE(dk)) {
669 PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(dk)[i];
670 printf("key=%p value=%p\n", ep->me_key, ep->me_value);
671 }
672 else {
673 PyDictKeyEntry *ep = &DK_ENTRIES(dk)[i];
674 printf("key=%p hash=%lx value=%p\n", ep->me_key, ep->me_hash, ep->me_value);
675 }
676 }
677 }
678 #endif
679
680 int
_PyDict_CheckConsistency(PyObject * op,int check_content)681 _PyDict_CheckConsistency(PyObject *op, int check_content)
682 {
683 ASSERT_WORLD_STOPPED_OR_DICT_LOCKED(op);
684
685 #define CHECK(expr) \
686 do { if (!(expr)) { _PyObject_ASSERT_FAILED_MSG(op, Py_STRINGIFY(expr)); } } while (0)
687
688 assert(op != NULL);
689 CHECK(PyDict_Check(op));
690 PyDictObject *mp = (PyDictObject *)op;
691
692 PyDictKeysObject *keys = mp->ma_keys;
693 int splitted = _PyDict_HasSplitTable(mp);
694 Py_ssize_t usable = USABLE_FRACTION(DK_SIZE(keys));
695
696 // In the free-threaded build, shared keys may be concurrently modified,
697 // so use atomic loads.
698 Py_ssize_t dk_usable = FT_ATOMIC_LOAD_SSIZE_ACQUIRE(keys->dk_usable);
699 Py_ssize_t dk_nentries = FT_ATOMIC_LOAD_SSIZE_ACQUIRE(keys->dk_nentries);
700
701 CHECK(0 <= mp->ma_used && mp->ma_used <= usable);
702 CHECK(0 <= dk_usable && dk_usable <= usable);
703 CHECK(0 <= dk_nentries && dk_nentries <= usable);
704 CHECK(dk_usable + dk_nentries <= usable);
705
706 if (!splitted) {
707 /* combined table */
708 CHECK(keys->dk_kind != DICT_KEYS_SPLIT);
709 CHECK(keys->dk_refcnt == 1 || keys == Py_EMPTY_KEYS);
710 }
711 else {
712 CHECK(keys->dk_kind == DICT_KEYS_SPLIT);
713 CHECK(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
714 if (mp->ma_values->embedded) {
715 CHECK(mp->ma_values->embedded == 1);
716 CHECK(mp->ma_values->valid == 1);
717 }
718 }
719
720 if (check_content) {
721 LOCK_KEYS_IF_SPLIT(keys, keys->dk_kind);
722 for (Py_ssize_t i=0; i < DK_SIZE(keys); i++) {
723 Py_ssize_t ix = dictkeys_get_index(keys, i);
724 CHECK(DKIX_DUMMY <= ix && ix <= usable);
725 }
726
727 if (keys->dk_kind == DICT_KEYS_GENERAL) {
728 PyDictKeyEntry *entries = DK_ENTRIES(keys);
729 for (Py_ssize_t i=0; i < usable; i++) {
730 PyDictKeyEntry *entry = &entries[i];
731 PyObject *key = entry->me_key;
732
733 if (key != NULL) {
734 /* test_dict fails if PyObject_Hash() is called again */
735 CHECK(entry->me_hash != -1);
736 CHECK(entry->me_value != NULL);
737
738 if (PyUnicode_CheckExact(key)) {
739 Py_hash_t hash = unicode_get_hash(key);
740 CHECK(entry->me_hash == hash);
741 }
742 }
743 }
744 }
745 else {
746 PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
747 for (Py_ssize_t i=0; i < usable; i++) {
748 PyDictUnicodeEntry *entry = &entries[i];
749 PyObject *key = entry->me_key;
750
751 if (key != NULL) {
752 CHECK(PyUnicode_CheckExact(key));
753 Py_hash_t hash = unicode_get_hash(key);
754 CHECK(hash != -1);
755 if (!splitted) {
756 CHECK(entry->me_value != NULL);
757 }
758 }
759
760 if (splitted) {
761 CHECK(entry->me_value == NULL);
762 }
763 }
764 }
765
766 if (splitted) {
767 CHECK(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
768 /* splitted table */
769 int duplicate_check = 0;
770 for (Py_ssize_t i=0; i < mp->ma_used; i++) {
771 int index = get_index_from_order(mp, i);
772 CHECK((duplicate_check & (1<<index)) == 0);
773 duplicate_check |= (1<<index);
774 CHECK(mp->ma_values->values[index] != NULL);
775 }
776 }
777 UNLOCK_KEYS_IF_SPLIT(keys, keys->dk_kind);
778 }
779 return 1;
780
781 #undef CHECK
782 }
783
784
785 static PyDictKeysObject*
new_keys_object(PyInterpreterState * interp,uint8_t log2_size,bool unicode)786 new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode)
787 {
788 PyDictKeysObject *dk;
789 Py_ssize_t usable;
790 int log2_bytes;
791 size_t entry_size = unicode ? sizeof(PyDictUnicodeEntry) : sizeof(PyDictKeyEntry);
792
793 assert(log2_size >= PyDict_LOG_MINSIZE);
794
795 usable = USABLE_FRACTION((size_t)1<<log2_size);
796 if (log2_size < 8) {
797 log2_bytes = log2_size;
798 }
799 else if (log2_size < 16) {
800 log2_bytes = log2_size + 1;
801 }
802 #if SIZEOF_VOID_P > 4
803 else if (log2_size >= 32) {
804 log2_bytes = log2_size + 3;
805 }
806 #endif
807 else {
808 log2_bytes = log2_size + 2;
809 }
810
811 #ifdef WITH_FREELISTS
812 struct _Py_dictkeys_freelist *freelist = get_dictkeys_freelist();
813 if (log2_size == PyDict_LOG_MINSIZE && unicode && freelist->numfree > 0) {
814 dk = freelist->items[--freelist->numfree];
815 OBJECT_STAT_INC(from_freelist);
816 }
817 else
818 #endif
819 {
820 dk = PyMem_Malloc(sizeof(PyDictKeysObject)
821 + ((size_t)1 << log2_bytes)
822 + entry_size * usable);
823 if (dk == NULL) {
824 PyErr_NoMemory();
825 return NULL;
826 }
827 }
828 #ifdef Py_REF_DEBUG
829 _Py_IncRefTotal(_PyThreadState_GET());
830 #endif
831 dk->dk_refcnt = 1;
832 dk->dk_log2_size = log2_size;
833 dk->dk_log2_index_bytes = log2_bytes;
834 dk->dk_kind = unicode ? DICT_KEYS_UNICODE : DICT_KEYS_GENERAL;
835 #ifdef Py_GIL_DISABLED
836 dk->dk_mutex = (PyMutex){0};
837 #endif
838 dk->dk_nentries = 0;
839 dk->dk_usable = usable;
840 dk->dk_version = 0;
841 memset(&dk->dk_indices[0], 0xff, ((size_t)1 << log2_bytes));
842 memset(&dk->dk_indices[(size_t)1 << log2_bytes], 0, entry_size * usable);
843 return dk;
844 }
845
846 static void
free_keys_object(PyDictKeysObject * keys,bool use_qsbr)847 free_keys_object(PyDictKeysObject *keys, bool use_qsbr)
848 {
849 #ifdef Py_GIL_DISABLED
850 if (use_qsbr) {
851 _PyMem_FreeDelayed(keys);
852 return;
853 }
854 #endif
855 #ifdef WITH_FREELISTS
856 struct _Py_dictkeys_freelist *freelist = get_dictkeys_freelist();
857 if (DK_LOG_SIZE(keys) == PyDict_LOG_MINSIZE
858 && freelist->numfree < PyDict_MAXFREELIST
859 && freelist->numfree >= 0
860 && DK_IS_UNICODE(keys)) {
861 freelist->items[freelist->numfree++] = keys;
862 OBJECT_STAT_INC(to_freelist);
863 return;
864 }
865 #endif
866 PyMem_Free(keys);
867 }
868
869 static size_t
values_size_from_count(size_t count)870 values_size_from_count(size_t count)
871 {
872 assert(count >= 1);
873 size_t suffix_size = _Py_SIZE_ROUND_UP(count, sizeof(PyObject *));
874 assert(suffix_size < 128);
875 assert(suffix_size % sizeof(PyObject *) == 0);
876 return (count + 1) * sizeof(PyObject *) + suffix_size;
877 }
878
879 #define CACHED_KEYS(tp) (((PyHeapTypeObject*)tp)->ht_cached_keys)
880
881 static inline PyDictValues*
new_values(size_t size)882 new_values(size_t size)
883 {
884 size_t n = values_size_from_count(size);
885 PyDictValues *res = (PyDictValues *)PyMem_Malloc(n);
886 if (res == NULL) {
887 return NULL;
888 }
889 res->embedded = 0;
890 res->size = 0;
891 assert(size < 256);
892 res->capacity = (uint8_t)size;
893 return res;
894 }
895
896 static inline void
free_values(PyDictValues * values,bool use_qsbr)897 free_values(PyDictValues *values, bool use_qsbr)
898 {
899 assert(values->embedded == 0);
900 #ifdef Py_GIL_DISABLED
901 if (use_qsbr) {
902 _PyMem_FreeDelayed(values);
903 return;
904 }
905 #endif
906 PyMem_Free(values);
907 }
908
909 /* Consumes a reference to the keys object */
910 static PyObject *
new_dict(PyInterpreterState * interp,PyDictKeysObject * keys,PyDictValues * values,Py_ssize_t used,int free_values_on_failure)911 new_dict(PyInterpreterState *interp,
912 PyDictKeysObject *keys, PyDictValues *values,
913 Py_ssize_t used, int free_values_on_failure)
914 {
915 PyDictObject *mp;
916 assert(keys != NULL);
917 #ifdef WITH_FREELISTS
918 struct _Py_dict_freelist *freelist = get_dict_freelist();
919 if (freelist->numfree > 0) {
920 mp = freelist->items[--freelist->numfree];
921 assert (mp != NULL);
922 assert (Py_IS_TYPE(mp, &PyDict_Type));
923 OBJECT_STAT_INC(from_freelist);
924 _Py_NewReference((PyObject *)mp);
925 }
926 else
927 #endif
928 {
929 mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
930 if (mp == NULL) {
931 dictkeys_decref(interp, keys, false);
932 if (free_values_on_failure) {
933 free_values(values, false);
934 }
935 return NULL;
936 }
937 }
938 mp->ma_keys = keys;
939 mp->ma_values = values;
940 mp->ma_used = used;
941 mp->ma_version_tag = DICT_NEXT_VERSION(interp);
942 ASSERT_CONSISTENT(mp);
943 return (PyObject *)mp;
944 }
945
946 static PyObject *
new_dict_with_shared_keys(PyInterpreterState * interp,PyDictKeysObject * keys)947 new_dict_with_shared_keys(PyInterpreterState *interp, PyDictKeysObject *keys)
948 {
949 size_t size = shared_keys_usable_size(keys);
950 PyDictValues *values = new_values(size);
951 if (values == NULL) {
952 return PyErr_NoMemory();
953 }
954 dictkeys_incref(keys);
955 for (size_t i = 0; i < size; i++) {
956 values->values[i] = NULL;
957 }
958 return new_dict(interp, keys, values, 0, 1);
959 }
960
961
962 static PyDictKeysObject *
clone_combined_dict_keys(PyDictObject * orig)963 clone_combined_dict_keys(PyDictObject *orig)
964 {
965 assert(PyDict_Check(orig));
966 assert(Py_TYPE(orig)->tp_iter == dict_iter);
967 assert(orig->ma_values == NULL);
968 assert(orig->ma_keys != Py_EMPTY_KEYS);
969 assert(orig->ma_keys->dk_refcnt == 1);
970
971 ASSERT_DICT_LOCKED(orig);
972
973 size_t keys_size = _PyDict_KeysSize(orig->ma_keys);
974 PyDictKeysObject *keys = PyMem_Malloc(keys_size);
975 if (keys == NULL) {
976 PyErr_NoMemory();
977 return NULL;
978 }
979
980 memcpy(keys, orig->ma_keys, keys_size);
981
982 /* After copying key/value pairs, we need to incref all
983 keys and values and they are about to be co-owned by a
984 new dict object. */
985 PyObject **pkey, **pvalue;
986 size_t offs;
987 if (DK_IS_UNICODE(orig->ma_keys)) {
988 PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(keys);
989 pkey = &ep0->me_key;
990 pvalue = &ep0->me_value;
991 offs = sizeof(PyDictUnicodeEntry) / sizeof(PyObject*);
992 }
993 else {
994 PyDictKeyEntry *ep0 = DK_ENTRIES(keys);
995 pkey = &ep0->me_key;
996 pvalue = &ep0->me_value;
997 offs = sizeof(PyDictKeyEntry) / sizeof(PyObject*);
998 }
999
1000 Py_ssize_t n = keys->dk_nentries;
1001 for (Py_ssize_t i = 0; i < n; i++) {
1002 PyObject *value = *pvalue;
1003 if (value != NULL) {
1004 Py_INCREF(value);
1005 Py_INCREF(*pkey);
1006 }
1007 pvalue += offs;
1008 pkey += offs;
1009 }
1010
1011 /* Since we copied the keys table we now have an extra reference
1012 in the system. Manually call increment _Py_RefTotal to signal that
1013 we have it now; calling dictkeys_incref would be an error as
1014 keys->dk_refcnt is already set to 1 (after memcpy). */
1015 #ifdef Py_REF_DEBUG
1016 _Py_IncRefTotal(_PyThreadState_GET());
1017 #endif
1018 return keys;
1019 }
1020
1021 PyObject *
PyDict_New(void)1022 PyDict_New(void)
1023 {
1024 PyInterpreterState *interp = _PyInterpreterState_GET();
1025 /* We don't incref Py_EMPTY_KEYS here because it is immortal. */
1026 return new_dict(interp, Py_EMPTY_KEYS, NULL, 0, 0);
1027 }
1028
1029 /* Search index of hash table from offset of entry table */
1030 static Py_ssize_t
lookdict_index(PyDictKeysObject * k,Py_hash_t hash,Py_ssize_t index)1031 lookdict_index(PyDictKeysObject *k, Py_hash_t hash, Py_ssize_t index)
1032 {
1033 size_t mask = DK_MASK(k);
1034 size_t perturb = (size_t)hash;
1035 size_t i = (size_t)hash & mask;
1036
1037 for (;;) {
1038 Py_ssize_t ix = dictkeys_get_index(k, i);
1039 if (ix == index) {
1040 return i;
1041 }
1042 if (ix == DKIX_EMPTY) {
1043 return DKIX_EMPTY;
1044 }
1045 perturb >>= PERTURB_SHIFT;
1046 i = mask & (i*5 + perturb + 1);
1047 }
1048 Py_UNREACHABLE();
1049 }
1050
1051 static inline Py_ALWAYS_INLINE Py_ssize_t
do_lookup(PyDictObject * mp,PyDictKeysObject * dk,PyObject * key,Py_hash_t hash,int (* check_lookup)(PyDictObject *,PyDictKeysObject *,void *,Py_ssize_t ix,PyObject * key,Py_hash_t))1052 do_lookup(PyDictObject *mp, PyDictKeysObject *dk, PyObject *key, Py_hash_t hash,
1053 int (*check_lookup)(PyDictObject *, PyDictKeysObject *, void *, Py_ssize_t ix, PyObject *key, Py_hash_t))
1054 {
1055 void *ep0 = _DK_ENTRIES(dk);
1056 size_t mask = DK_MASK(dk);
1057 size_t perturb = hash;
1058 size_t i = (size_t)hash & mask;
1059 Py_ssize_t ix;
1060 for (;;) {
1061 ix = dictkeys_get_index(dk, i);
1062 if (ix >= 0) {
1063 int cmp = check_lookup(mp, dk, ep0, ix, key, hash);
1064 if (cmp < 0) {
1065 return cmp;
1066 } else if (cmp) {
1067 return ix;
1068 }
1069 }
1070 else if (ix == DKIX_EMPTY) {
1071 return DKIX_EMPTY;
1072 }
1073 perturb >>= PERTURB_SHIFT;
1074 i = mask & (i*5 + perturb + 1);
1075
1076 // Manual loop unrolling
1077 ix = dictkeys_get_index(dk, i);
1078 if (ix >= 0) {
1079 int cmp = check_lookup(mp, dk, ep0, ix, key, hash);
1080 if (cmp < 0) {
1081 return cmp;
1082 } else if (cmp) {
1083 return ix;
1084 }
1085 }
1086 else if (ix == DKIX_EMPTY) {
1087 return DKIX_EMPTY;
1088 }
1089 perturb >>= PERTURB_SHIFT;
1090 i = mask & (i*5 + perturb + 1);
1091 }
1092 Py_UNREACHABLE();
1093 }
1094
1095 static inline int
compare_unicode_generic(PyDictObject * mp,PyDictKeysObject * dk,void * ep0,Py_ssize_t ix,PyObject * key,Py_hash_t hash)1096 compare_unicode_generic(PyDictObject *mp, PyDictKeysObject *dk,
1097 void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
1098 {
1099 PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
1100 assert(ep->me_key != NULL);
1101 assert(PyUnicode_CheckExact(ep->me_key));
1102 assert(!PyUnicode_CheckExact(key));
1103
1104 if (unicode_get_hash(ep->me_key) == hash) {
1105 PyObject *startkey = ep->me_key;
1106 Py_INCREF(startkey);
1107 int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
1108 Py_DECREF(startkey);
1109 if (cmp < 0) {
1110 return DKIX_ERROR;
1111 }
1112 if (dk == mp->ma_keys && ep->me_key == startkey) {
1113 return cmp;
1114 }
1115 else {
1116 /* The dict was mutated, restart */
1117 return DKIX_KEY_CHANGED;
1118 }
1119 }
1120 return 0;
1121 }
1122
1123 // Search non-Unicode key from Unicode table
1124 static Py_ssize_t
unicodekeys_lookup_generic(PyDictObject * mp,PyDictKeysObject * dk,PyObject * key,Py_hash_t hash)1125 unicodekeys_lookup_generic(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1126 {
1127 return do_lookup(mp, dk, key, hash, compare_unicode_generic);
1128 }
1129
1130 static inline int
compare_unicode_unicode(PyDictObject * mp,PyDictKeysObject * dk,void * ep0,Py_ssize_t ix,PyObject * key,Py_hash_t hash)1131 compare_unicode_unicode(PyDictObject *mp, PyDictKeysObject *dk,
1132 void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
1133 {
1134 PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
1135 PyObject *ep_key = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key);
1136 assert(ep_key != NULL);
1137 assert(PyUnicode_CheckExact(ep_key));
1138 if (ep_key == key ||
1139 (unicode_get_hash(ep_key) == hash && unicode_eq(ep_key, key))) {
1140 return 1;
1141 }
1142 return 0;
1143 }
1144
1145 static Py_ssize_t _Py_HOT_FUNCTION
unicodekeys_lookup_unicode(PyDictKeysObject * dk,PyObject * key,Py_hash_t hash)1146 unicodekeys_lookup_unicode(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1147 {
1148 return do_lookup(NULL, dk, key, hash, compare_unicode_unicode);
1149 }
1150
1151 static inline int
compare_generic(PyDictObject * mp,PyDictKeysObject * dk,void * ep0,Py_ssize_t ix,PyObject * key,Py_hash_t hash)1152 compare_generic(PyDictObject *mp, PyDictKeysObject *dk,
1153 void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
1154 {
1155 PyDictKeyEntry *ep = &((PyDictKeyEntry *)ep0)[ix];
1156 assert(ep->me_key != NULL);
1157 if (ep->me_key == key) {
1158 return 1;
1159 }
1160 if (ep->me_hash == hash) {
1161 PyObject *startkey = ep->me_key;
1162 Py_INCREF(startkey);
1163 int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
1164 Py_DECREF(startkey);
1165 if (cmp < 0) {
1166 return DKIX_ERROR;
1167 }
1168 if (dk == mp->ma_keys && ep->me_key == startkey) {
1169 return cmp;
1170 }
1171 else {
1172 /* The dict was mutated, restart */
1173 return DKIX_KEY_CHANGED;
1174 }
1175 }
1176 return 0;
1177 }
1178
1179 static Py_ssize_t
dictkeys_generic_lookup(PyDictObject * mp,PyDictKeysObject * dk,PyObject * key,Py_hash_t hash)1180 dictkeys_generic_lookup(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1181 {
1182 return do_lookup(mp, dk, key, hash, compare_generic);
1183 }
1184
1185 /* Lookup a string in a (all unicode) dict keys.
1186 * Returns DKIX_ERROR if key is not a string,
1187 * or if the dict keys is not all strings.
1188 * If the keys is present then return the index of key.
1189 * If the key is not present then return DKIX_EMPTY.
1190 */
1191 Py_ssize_t
_PyDictKeys_StringLookup(PyDictKeysObject * dk,PyObject * key)1192 _PyDictKeys_StringLookup(PyDictKeysObject* dk, PyObject *key)
1193 {
1194 DictKeysKind kind = dk->dk_kind;
1195 if (!PyUnicode_CheckExact(key) || kind == DICT_KEYS_GENERAL) {
1196 return DKIX_ERROR;
1197 }
1198 Py_hash_t hash = unicode_get_hash(key);
1199 if (hash == -1) {
1200 hash = PyUnicode_Type.tp_hash(key);
1201 if (hash == -1) {
1202 PyErr_Clear();
1203 return DKIX_ERROR;
1204 }
1205 }
1206 return unicodekeys_lookup_unicode(dk, key, hash);
1207 }
1208
1209 #ifdef Py_GIL_DISABLED
1210
1211 static Py_ssize_t
1212 unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject* dk, PyObject *key,
1213 Py_hash_t hash);
1214
1215 #endif
1216
1217 /*
1218 The basic lookup function used by all operations.
1219 This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4.
1220 Open addressing is preferred over chaining since the link overhead for
1221 chaining would be substantial (100% with typical malloc overhead).
1222
1223 The initial probe index is computed as hash mod the table size. Subsequent
1224 probe indices are computed as explained earlier.
1225
1226 All arithmetic on hash should ignore overflow.
1227
1228 _Py_dict_lookup() is general-purpose, and may return DKIX_ERROR if (and only if) a
1229 comparison raises an exception.
1230 When the key isn't found a DKIX_EMPTY is returned.
1231 */
1232 Py_ssize_t
_Py_dict_lookup(PyDictObject * mp,PyObject * key,Py_hash_t hash,PyObject ** value_addr)1233 _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr)
1234 {
1235 PyDictKeysObject *dk;
1236 DictKeysKind kind;
1237 Py_ssize_t ix;
1238
1239 _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(mp);
1240 start:
1241 dk = mp->ma_keys;
1242 kind = dk->dk_kind;
1243
1244 if (kind != DICT_KEYS_GENERAL) {
1245 if (PyUnicode_CheckExact(key)) {
1246 #ifdef Py_GIL_DISABLED
1247 if (kind == DICT_KEYS_SPLIT) {
1248 // A split dictionaries keys can be mutated by other
1249 // dictionaries but if we have a unicode key we can avoid
1250 // locking the shared keys.
1251 ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash);
1252 if (ix == DKIX_KEY_CHANGED) {
1253 LOCK_KEYS(dk);
1254 ix = unicodekeys_lookup_unicode(dk, key, hash);
1255 UNLOCK_KEYS(dk);
1256 }
1257 }
1258 else {
1259 ix = unicodekeys_lookup_unicode(dk, key, hash);
1260 }
1261 #else
1262 ix = unicodekeys_lookup_unicode(dk, key, hash);
1263 #endif
1264 }
1265 else {
1266 INCREF_KEYS_FT(dk);
1267 LOCK_KEYS_IF_SPLIT(dk, kind);
1268
1269 ix = unicodekeys_lookup_generic(mp, dk, key, hash);
1270
1271 UNLOCK_KEYS_IF_SPLIT(dk, kind);
1272 DECREF_KEYS_FT(dk, IS_DICT_SHARED(mp));
1273 if (ix == DKIX_KEY_CHANGED) {
1274 goto start;
1275 }
1276 }
1277
1278 if (ix >= 0) {
1279 if (kind == DICT_KEYS_SPLIT) {
1280 *value_addr = mp->ma_values->values[ix];
1281 }
1282 else {
1283 *value_addr = DK_UNICODE_ENTRIES(dk)[ix].me_value;
1284 }
1285 }
1286 else {
1287 *value_addr = NULL;
1288 }
1289 }
1290 else {
1291 ix = dictkeys_generic_lookup(mp, dk, key, hash);
1292 if (ix == DKIX_KEY_CHANGED) {
1293 goto start;
1294 }
1295 if (ix >= 0) {
1296 *value_addr = DK_ENTRIES(dk)[ix].me_value;
1297 }
1298 else {
1299 *value_addr = NULL;
1300 }
1301 }
1302
1303 return ix;
1304 }
1305
1306 #ifdef Py_GIL_DISABLED
1307 static inline void
ensure_shared_on_read(PyDictObject * mp)1308 ensure_shared_on_read(PyDictObject *mp)
1309 {
1310 if (!_Py_IsOwnedByCurrentThread((PyObject *)mp) && !IS_DICT_SHARED(mp)) {
1311 // The first time we access a dict from a non-owning thread we mark it
1312 // as shared. This ensures that a concurrent resize operation will
1313 // delay freeing the old keys or values using QSBR, which is necessary
1314 // to safely allow concurrent reads without locking...
1315 Py_BEGIN_CRITICAL_SECTION(mp);
1316 if (!IS_DICT_SHARED(mp)) {
1317 SET_DICT_SHARED(mp);
1318 }
1319 Py_END_CRITICAL_SECTION();
1320 }
1321 }
1322 #endif
1323
1324 static inline void
ensure_shared_on_resize(PyDictObject * mp)1325 ensure_shared_on_resize(PyDictObject *mp)
1326 {
1327 #ifdef Py_GIL_DISABLED
1328 _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(mp);
1329
1330 if (!_Py_IsOwnedByCurrentThread((PyObject *)mp) && !IS_DICT_SHARED(mp)) {
1331 // We are writing to the dict from another thread that owns
1332 // it and we haven't marked it as shared which will ensure
1333 // that when we re-size ma_keys or ma_values that we will
1334 // free using QSBR. We need to lock the dictionary to
1335 // contend with writes from the owning thread, mark it as
1336 // shared, and then we can continue with lock-free reads.
1337 // Technically this is a little heavy handed, we could just
1338 // free the individual old keys / old-values using qsbr
1339 SET_DICT_SHARED(mp);
1340 }
1341 #endif
1342 }
1343
1344 #ifdef Py_GIL_DISABLED
1345
1346 static inline Py_ALWAYS_INLINE int
compare_unicode_generic_threadsafe(PyDictObject * mp,PyDictKeysObject * dk,void * ep0,Py_ssize_t ix,PyObject * key,Py_hash_t hash)1347 compare_unicode_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
1348 void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
1349 {
1350 PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
1351 PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
1352 assert(startkey == NULL || PyUnicode_CheckExact(ep->me_key));
1353 assert(!PyUnicode_CheckExact(key));
1354
1355 if (startkey != NULL) {
1356 if (!_Py_TryIncrefCompare(&ep->me_key, startkey)) {
1357 return DKIX_KEY_CHANGED;
1358 }
1359
1360 if (unicode_get_hash(startkey) == hash) {
1361 int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
1362 Py_DECREF(startkey);
1363 if (cmp < 0) {
1364 return DKIX_ERROR;
1365 }
1366 if (dk == _Py_atomic_load_ptr_relaxed(&mp->ma_keys) &&
1367 startkey == _Py_atomic_load_ptr_relaxed(&ep->me_key)) {
1368 return cmp;
1369 }
1370 else {
1371 /* The dict was mutated, restart */
1372 return DKIX_KEY_CHANGED;
1373 }
1374 }
1375 else {
1376 Py_DECREF(startkey);
1377 }
1378 }
1379 return 0;
1380 }
1381
1382 // Search non-Unicode key from Unicode table
1383 static Py_ssize_t
unicodekeys_lookup_generic_threadsafe(PyDictObject * mp,PyDictKeysObject * dk,PyObject * key,Py_hash_t hash)1384 unicodekeys_lookup_generic_threadsafe(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1385 {
1386 return do_lookup(mp, dk, key, hash, compare_unicode_generic_threadsafe);
1387 }
1388
1389 static inline Py_ALWAYS_INLINE int
compare_unicode_unicode_threadsafe(PyDictObject * mp,PyDictKeysObject * dk,void * ep0,Py_ssize_t ix,PyObject * key,Py_hash_t hash)1390 compare_unicode_unicode_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
1391 void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
1392 {
1393 PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
1394 PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
1395 assert(startkey == NULL || PyUnicode_CheckExact(startkey));
1396 if (startkey == key) {
1397 return 1;
1398 }
1399 if (startkey != NULL) {
1400 if (_Py_IsImmortal(startkey)) {
1401 return unicode_get_hash(startkey) == hash && unicode_eq(startkey, key);
1402 }
1403 else {
1404 if (!_Py_TryIncrefCompare(&ep->me_key, startkey)) {
1405 return DKIX_KEY_CHANGED;
1406 }
1407 if (unicode_get_hash(startkey) == hash && unicode_eq(startkey, key)) {
1408 Py_DECREF(startkey);
1409 return 1;
1410 }
1411 Py_DECREF(startkey);
1412 }
1413 }
1414 return 0;
1415 }
1416
1417 static Py_ssize_t _Py_HOT_FUNCTION
unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject * dk,PyObject * key,Py_hash_t hash)1418 unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1419 {
1420 return do_lookup(NULL, dk, key, hash, compare_unicode_unicode_threadsafe);
1421 }
1422
1423 static inline Py_ALWAYS_INLINE int
compare_generic_threadsafe(PyDictObject * mp,PyDictKeysObject * dk,void * ep0,Py_ssize_t ix,PyObject * key,Py_hash_t hash)1424 compare_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
1425 void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
1426 {
1427 PyDictKeyEntry *ep = &((PyDictKeyEntry *)ep0)[ix];
1428 PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
1429 if (startkey == key) {
1430 return 1;
1431 }
1432 Py_ssize_t ep_hash = _Py_atomic_load_ssize_relaxed(&ep->me_hash);
1433 if (ep_hash == hash) {
1434 if (startkey == NULL || !_Py_TryIncrefCompare(&ep->me_key, startkey)) {
1435 return DKIX_KEY_CHANGED;
1436 }
1437 int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
1438 Py_DECREF(startkey);
1439 if (cmp < 0) {
1440 return DKIX_ERROR;
1441 }
1442 if (dk == _Py_atomic_load_ptr_relaxed(&mp->ma_keys) &&
1443 startkey == _Py_atomic_load_ptr_relaxed(&ep->me_key)) {
1444 return cmp;
1445 }
1446 else {
1447 /* The dict was mutated, restart */
1448 return DKIX_KEY_CHANGED;
1449 }
1450 }
1451 return 0;
1452 }
1453
1454 static Py_ssize_t
dictkeys_generic_lookup_threadsafe(PyDictObject * mp,PyDictKeysObject * dk,PyObject * key,Py_hash_t hash)1455 dictkeys_generic_lookup_threadsafe(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1456 {
1457 return do_lookup(mp, dk, key, hash, compare_generic_threadsafe);
1458 }
1459
1460 Py_ssize_t
_Py_dict_lookup_threadsafe(PyDictObject * mp,PyObject * key,Py_hash_t hash,PyObject ** value_addr)1461 _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr)
1462 {
1463 PyDictKeysObject *dk;
1464 DictKeysKind kind;
1465 Py_ssize_t ix;
1466 PyObject *value;
1467
1468 ensure_shared_on_read(mp);
1469
1470 dk = _Py_atomic_load_ptr(&mp->ma_keys);
1471 kind = dk->dk_kind;
1472
1473 if (kind != DICT_KEYS_GENERAL) {
1474 if (PyUnicode_CheckExact(key)) {
1475 ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash);
1476 }
1477 else {
1478 ix = unicodekeys_lookup_generic_threadsafe(mp, dk, key, hash);
1479 }
1480 if (ix == DKIX_KEY_CHANGED) {
1481 goto read_failed;
1482 }
1483
1484 if (ix >= 0) {
1485 if (kind == DICT_KEYS_SPLIT) {
1486 PyDictValues *values = _Py_atomic_load_ptr(&mp->ma_values);
1487 if (values == NULL)
1488 goto read_failed;
1489
1490 uint8_t capacity = _Py_atomic_load_uint8_relaxed(&values->capacity);
1491 if (ix >= (Py_ssize_t)capacity)
1492 goto read_failed;
1493
1494 value = _Py_TryXGetRef(&values->values[ix]);
1495 if (value == NULL)
1496 goto read_failed;
1497
1498 if (values != _Py_atomic_load_ptr(&mp->ma_values)) {
1499 Py_DECREF(value);
1500 goto read_failed;
1501 }
1502 }
1503 else {
1504 value = _Py_TryXGetRef(&DK_UNICODE_ENTRIES(dk)[ix].me_value);
1505 if (value == NULL) {
1506 goto read_failed;
1507 }
1508
1509 if (dk != _Py_atomic_load_ptr(&mp->ma_keys)) {
1510 Py_DECREF(value);
1511 goto read_failed;
1512 }
1513 }
1514 }
1515 else {
1516 value = NULL;
1517 }
1518 }
1519 else {
1520 ix = dictkeys_generic_lookup_threadsafe(mp, dk, key, hash);
1521 if (ix == DKIX_KEY_CHANGED) {
1522 goto read_failed;
1523 }
1524 if (ix >= 0) {
1525 value = _Py_TryXGetRef(&DK_ENTRIES(dk)[ix].me_value);
1526 if (value == NULL)
1527 goto read_failed;
1528
1529 if (dk != _Py_atomic_load_ptr(&mp->ma_keys)) {
1530 Py_DECREF(value);
1531 goto read_failed;
1532 }
1533 }
1534 else {
1535 value = NULL;
1536 }
1537 }
1538
1539 *value_addr = value;
1540 return ix;
1541
1542 read_failed:
1543 // In addition to the normal races of the dict being modified the _Py_TryXGetRef
1544 // can all fail if they don't yet have a shared ref count. That can happen here
1545 // or in the *_lookup_* helper. In that case we need to take the lock to avoid
1546 // mutation and do a normal incref which will make them shared.
1547 Py_BEGIN_CRITICAL_SECTION(mp);
1548 ix = _Py_dict_lookup(mp, key, hash, &value);
1549 *value_addr = value;
1550 if (value != NULL) {
1551 assert(ix >= 0);
1552 _Py_NewRefWithLock(value);
1553 }
1554 Py_END_CRITICAL_SECTION();
1555 return ix;
1556 }
1557
1558 #else // Py_GIL_DISABLED
1559
1560 Py_ssize_t
_Py_dict_lookup_threadsafe(PyDictObject * mp,PyObject * key,Py_hash_t hash,PyObject ** value_addr)1561 _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr)
1562 {
1563 Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, value_addr);
1564 Py_XNewRef(*value_addr);
1565 return ix;
1566 }
1567
1568 #endif
1569
1570 int
_PyDict_HasOnlyStringKeys(PyObject * dict)1571 _PyDict_HasOnlyStringKeys(PyObject *dict)
1572 {
1573 Py_ssize_t pos = 0;
1574 PyObject *key, *value;
1575 assert(PyDict_Check(dict));
1576 /* Shortcut */
1577 if (((PyDictObject *)dict)->ma_keys->dk_kind != DICT_KEYS_GENERAL)
1578 return 1;
1579 while (PyDict_Next(dict, &pos, &key, &value))
1580 if (!PyUnicode_Check(key))
1581 return 0;
1582 return 1;
1583 }
1584
1585 #define MAINTAIN_TRACKING(mp, key, value) \
1586 do { \
1587 if (!_PyObject_GC_IS_TRACKED(mp)) { \
1588 if (_PyObject_GC_MAY_BE_TRACKED(key) || \
1589 _PyObject_GC_MAY_BE_TRACKED(value)) { \
1590 _PyObject_GC_TRACK(mp); \
1591 } \
1592 } \
1593 } while(0)
1594
1595 void
_PyDict_MaybeUntrack(PyObject * op)1596 _PyDict_MaybeUntrack(PyObject *op)
1597 {
1598 PyDictObject *mp;
1599 PyObject *value;
1600 Py_ssize_t i, numentries;
1601
1602 ASSERT_WORLD_STOPPED_OR_DICT_LOCKED(op);
1603
1604 if (!PyDict_CheckExact(op) || !_PyObject_GC_IS_TRACKED(op))
1605 return;
1606
1607 mp = (PyDictObject *) op;
1608 ASSERT_CONSISTENT(mp);
1609 numentries = mp->ma_keys->dk_nentries;
1610 if (_PyDict_HasSplitTable(mp)) {
1611 for (i = 0; i < numentries; i++) {
1612 if ((value = mp->ma_values->values[i]) == NULL)
1613 continue;
1614 if (_PyObject_GC_MAY_BE_TRACKED(value)) {
1615 return;
1616 }
1617 }
1618 }
1619 else {
1620 if (DK_IS_UNICODE(mp->ma_keys)) {
1621 PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(mp->ma_keys);
1622 for (i = 0; i < numentries; i++) {
1623 if ((value = ep0[i].me_value) == NULL)
1624 continue;
1625 if (_PyObject_GC_MAY_BE_TRACKED(value))
1626 return;
1627 }
1628 }
1629 else {
1630 PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys);
1631 for (i = 0; i < numentries; i++) {
1632 if ((value = ep0[i].me_value) == NULL)
1633 continue;
1634 if (_PyObject_GC_MAY_BE_TRACKED(value) ||
1635 _PyObject_GC_MAY_BE_TRACKED(ep0[i].me_key))
1636 return;
1637 }
1638 }
1639 }
1640 _PyObject_GC_UNTRACK(op);
1641 }
1642
1643 static inline int
is_unusable_slot(Py_ssize_t ix)1644 is_unusable_slot(Py_ssize_t ix)
1645 {
1646 #ifdef Py_GIL_DISABLED
1647 return ix >= 0 || ix == DKIX_DUMMY;
1648 #else
1649 return ix >= 0;
1650 #endif
1651 }
1652
1653 /* Internal function to find slot for an item from its hash
1654 when it is known that the key is not present in the dict.
1655 */
1656 static Py_ssize_t
find_empty_slot(PyDictKeysObject * keys,Py_hash_t hash)1657 find_empty_slot(PyDictKeysObject *keys, Py_hash_t hash)
1658 {
1659 assert(keys != NULL);
1660
1661 const size_t mask = DK_MASK(keys);
1662 size_t i = hash & mask;
1663 Py_ssize_t ix = dictkeys_get_index(keys, i);
1664 for (size_t perturb = hash; is_unusable_slot(ix);) {
1665 perturb >>= PERTURB_SHIFT;
1666 i = (i*5 + perturb + 1) & mask;
1667 ix = dictkeys_get_index(keys, i);
1668 }
1669 return i;
1670 }
1671
1672 static int
insertion_resize(PyInterpreterState * interp,PyDictObject * mp,int unicode)1673 insertion_resize(PyInterpreterState *interp, PyDictObject *mp, int unicode)
1674 {
1675 return dictresize(interp, mp, calculate_log2_keysize(GROWTH_RATE(mp)), unicode);
1676 }
1677
1678 static inline int
insert_combined_dict(PyInterpreterState * interp,PyDictObject * mp,Py_hash_t hash,PyObject * key,PyObject * value)1679 insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
1680 Py_hash_t hash, PyObject *key, PyObject *value)
1681 {
1682 if (mp->ma_keys->dk_usable <= 0) {
1683 /* Need to resize. */
1684 if (insertion_resize(interp, mp, 1) < 0) {
1685 return -1;
1686 }
1687 }
1688
1689 uint64_t new_version = _PyDict_NotifyEvent(
1690 interp, PyDict_EVENT_ADDED, mp, key, value);
1691 mp->ma_keys->dk_version = 0;
1692
1693 Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash);
1694 dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
1695
1696 if (DK_IS_UNICODE(mp->ma_keys)) {
1697 PyDictUnicodeEntry *ep;
1698 ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
1699 STORE_KEY(ep, key);
1700 STORE_VALUE(ep, value);
1701 }
1702 else {
1703 PyDictKeyEntry *ep;
1704 ep = &DK_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
1705 STORE_KEY(ep, key);
1706 STORE_VALUE(ep, value);
1707 STORE_HASH(ep, hash);
1708 }
1709 mp->ma_version_tag = new_version;
1710 STORE_KEYS_USABLE(mp->ma_keys, mp->ma_keys->dk_usable - 1);
1711 STORE_KEYS_NENTRIES(mp->ma_keys, mp->ma_keys->dk_nentries + 1);
1712 assert(mp->ma_keys->dk_usable >= 0);
1713 return 0;
1714 }
1715
1716 static Py_ssize_t
insert_split_key(PyDictKeysObject * keys,PyObject * key,Py_hash_t hash)1717 insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash)
1718 {
1719 assert(PyUnicode_CheckExact(key));
1720 Py_ssize_t ix;
1721
1722
1723 #ifdef Py_GIL_DISABLED
1724 ix = unicodekeys_lookup_unicode_threadsafe(keys, key, hash);
1725 if (ix >= 0) {
1726 return ix;
1727 }
1728 #endif
1729
1730 LOCK_KEYS(keys);
1731 ix = unicodekeys_lookup_unicode(keys, key, hash);
1732 if (ix == DKIX_EMPTY && keys->dk_usable > 0) {
1733 // Insert into new slot
1734 keys->dk_version = 0;
1735 Py_ssize_t hashpos = find_empty_slot(keys, hash);
1736 ix = keys->dk_nentries;
1737 dictkeys_set_index(keys, hashpos, ix);
1738 PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(keys)[ix];
1739 STORE_SHARED_KEY(ep->me_key, Py_NewRef(key));
1740 split_keys_entry_added(keys);
1741 }
1742 assert (ix < SHARED_KEYS_MAX_SIZE);
1743 UNLOCK_KEYS(keys);
1744 return ix;
1745 }
1746
1747 static void
insert_split_value(PyInterpreterState * interp,PyDictObject * mp,PyObject * key,PyObject * value,Py_ssize_t ix)1748 insert_split_value(PyInterpreterState *interp, PyDictObject *mp, PyObject *key, PyObject *value, Py_ssize_t ix)
1749 {
1750 assert(PyUnicode_CheckExact(key));
1751 ASSERT_DICT_LOCKED(mp);
1752 MAINTAIN_TRACKING(mp, key, value);
1753 PyObject *old_value = mp->ma_values->values[ix];
1754 if (old_value == NULL) {
1755 uint64_t new_version = _PyDict_NotifyEvent(interp, PyDict_EVENT_ADDED, mp, key, value);
1756 STORE_SPLIT_VALUE(mp, ix, Py_NewRef(value));
1757 _PyDictValues_AddToInsertionOrder(mp->ma_values, ix);
1758 STORE_USED(mp, mp->ma_used + 1);
1759 mp->ma_version_tag = new_version;
1760 }
1761 else {
1762 uint64_t new_version = _PyDict_NotifyEvent(interp, PyDict_EVENT_MODIFIED, mp, key, value);
1763 STORE_SPLIT_VALUE(mp, ix, Py_NewRef(value));
1764 mp->ma_version_tag = new_version;
1765 // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault,
1766 // when dict only holds the strong reference to value in ep->me_value.
1767 Py_DECREF(old_value);
1768 }
1769 ASSERT_CONSISTENT(mp);
1770 }
1771
1772 /*
1773 Internal routine to insert a new item into the table.
1774 Used both by the internal resize routine and by the public insert routine.
1775 Returns -1 if an error occurred, or 0 on success.
1776 Consumes key and value references.
1777 */
1778 static int
insertdict(PyInterpreterState * interp,PyDictObject * mp,PyObject * key,Py_hash_t hash,PyObject * value)1779 insertdict(PyInterpreterState *interp, PyDictObject *mp,
1780 PyObject *key, Py_hash_t hash, PyObject *value)
1781 {
1782 PyObject *old_value;
1783
1784 ASSERT_DICT_LOCKED(mp);
1785
1786 if (DK_IS_UNICODE(mp->ma_keys) && !PyUnicode_CheckExact(key)) {
1787 if (insertion_resize(interp, mp, 0) < 0)
1788 goto Fail;
1789 assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
1790 }
1791
1792 if (_PyDict_HasSplitTable(mp)) {
1793 Py_ssize_t ix = insert_split_key(mp->ma_keys, key, hash);
1794 if (ix != DKIX_EMPTY) {
1795 insert_split_value(interp, mp, key, value, ix);
1796 Py_DECREF(key);
1797 Py_DECREF(value);
1798 return 0;
1799 }
1800
1801 /* No space in shared keys. Resize and continue below. */
1802 if (insertion_resize(interp, mp, 1) < 0) {
1803 goto Fail;
1804 }
1805 }
1806
1807 Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &old_value);
1808 if (ix == DKIX_ERROR)
1809 goto Fail;
1810
1811 MAINTAIN_TRACKING(mp, key, value);
1812
1813 if (ix == DKIX_EMPTY) {
1814 assert(!_PyDict_HasSplitTable(mp));
1815 /* Insert into new slot. */
1816 assert(old_value == NULL);
1817 if (insert_combined_dict(interp, mp, hash, key, value) < 0) {
1818 goto Fail;
1819 }
1820 STORE_USED(mp, mp->ma_used + 1);
1821 ASSERT_CONSISTENT(mp);
1822 return 0;
1823 }
1824
1825 if (old_value != value) {
1826 uint64_t new_version = _PyDict_NotifyEvent(
1827 interp, PyDict_EVENT_MODIFIED, mp, key, value);
1828 assert(old_value != NULL);
1829 assert(!_PyDict_HasSplitTable(mp));
1830 if (DK_IS_UNICODE(mp->ma_keys)) {
1831 PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[ix];
1832 STORE_VALUE(ep, value);
1833 }
1834 else {
1835 PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[ix];
1836 STORE_VALUE(ep, value);
1837 }
1838 mp->ma_version_tag = new_version;
1839 }
1840 Py_XDECREF(old_value); /* which **CAN** re-enter (see issue #22653) */
1841 ASSERT_CONSISTENT(mp);
1842 Py_DECREF(key);
1843 return 0;
1844
1845 Fail:
1846 Py_DECREF(value);
1847 Py_DECREF(key);
1848 return -1;
1849 }
1850
1851 // Same as insertdict but specialized for ma_keys == Py_EMPTY_KEYS.
1852 // Consumes key and value references.
1853 static int
insert_to_emptydict(PyInterpreterState * interp,PyDictObject * mp,PyObject * key,Py_hash_t hash,PyObject * value)1854 insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp,
1855 PyObject *key, Py_hash_t hash, PyObject *value)
1856 {
1857 assert(mp->ma_keys == Py_EMPTY_KEYS);
1858 ASSERT_DICT_LOCKED(mp);
1859
1860 int unicode = PyUnicode_CheckExact(key);
1861 PyDictKeysObject *newkeys = new_keys_object(
1862 interp, PyDict_LOG_MINSIZE, unicode);
1863 if (newkeys == NULL) {
1864 Py_DECREF(key);
1865 Py_DECREF(value);
1866 return -1;
1867 }
1868 uint64_t new_version = _PyDict_NotifyEvent(
1869 interp, PyDict_EVENT_ADDED, mp, key, value);
1870
1871 /* We don't decref Py_EMPTY_KEYS here because it is immortal. */
1872 assert(mp->ma_values == NULL);
1873
1874 MAINTAIN_TRACKING(mp, key, value);
1875
1876 size_t hashpos = (size_t)hash & (PyDict_MINSIZE-1);
1877 dictkeys_set_index(newkeys, hashpos, 0);
1878 if (unicode) {
1879 PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(newkeys);
1880 ep->me_key = key;
1881 STORE_VALUE(ep, value);
1882 }
1883 else {
1884 PyDictKeyEntry *ep = DK_ENTRIES(newkeys);
1885 ep->me_key = key;
1886 ep->me_hash = hash;
1887 STORE_VALUE(ep, value);
1888 }
1889 STORE_USED(mp, mp->ma_used + 1);
1890 mp->ma_version_tag = new_version;
1891 newkeys->dk_usable--;
1892 newkeys->dk_nentries++;
1893 // We store the keys last so no one can see them in a partially inconsistent
1894 // state so that we don't need to switch the keys to being shared yet for
1895 // the case where we're inserting from the non-owner thread. We don't use
1896 // set_keys here because the transition from empty to non-empty is safe
1897 // as the empty keys will never be freed.
1898 FT_ATOMIC_STORE_PTR_RELEASE(mp->ma_keys, newkeys);
1899 return 0;
1900 }
1901
1902 /*
1903 Internal routine used by dictresize() to build a hashtable of entries.
1904 */
1905 static void
build_indices_generic(PyDictKeysObject * keys,PyDictKeyEntry * ep,Py_ssize_t n)1906 build_indices_generic(PyDictKeysObject *keys, PyDictKeyEntry *ep, Py_ssize_t n)
1907 {
1908 size_t mask = DK_MASK(keys);
1909 for (Py_ssize_t ix = 0; ix != n; ix++, ep++) {
1910 Py_hash_t hash = ep->me_hash;
1911 size_t i = hash & mask;
1912 for (size_t perturb = hash; dictkeys_get_index(keys, i) != DKIX_EMPTY;) {
1913 perturb >>= PERTURB_SHIFT;
1914 i = mask & (i*5 + perturb + 1);
1915 }
1916 dictkeys_set_index(keys, i, ix);
1917 }
1918 }
1919
1920 static void
build_indices_unicode(PyDictKeysObject * keys,PyDictUnicodeEntry * ep,Py_ssize_t n)1921 build_indices_unicode(PyDictKeysObject *keys, PyDictUnicodeEntry *ep, Py_ssize_t n)
1922 {
1923 size_t mask = DK_MASK(keys);
1924 for (Py_ssize_t ix = 0; ix != n; ix++, ep++) {
1925 Py_hash_t hash = unicode_get_hash(ep->me_key);
1926 assert(hash != -1);
1927 size_t i = hash & mask;
1928 for (size_t perturb = hash; dictkeys_get_index(keys, i) != DKIX_EMPTY;) {
1929 perturb >>= PERTURB_SHIFT;
1930 i = mask & (i*5 + perturb + 1);
1931 }
1932 dictkeys_set_index(keys, i, ix);
1933 }
1934 }
1935
1936 /*
1937 Restructure the table by allocating a new table and reinserting all
1938 items again. When entries have been deleted, the new table may
1939 actually be smaller than the old one.
1940 If a table is split (its keys and hashes are shared, its values are not),
1941 then the values are temporarily copied into the table, it is resized as
1942 a combined table, then the me_value slots in the old table are NULLed out.
1943 After resizing, a table is always combined.
1944
1945 This function supports:
1946 - Unicode split -> Unicode combined or Generic
1947 - Unicode combined -> Unicode combined or Generic
1948 - Generic -> Generic
1949 */
1950 static int
dictresize(PyInterpreterState * interp,PyDictObject * mp,uint8_t log2_newsize,int unicode)1951 dictresize(PyInterpreterState *interp, PyDictObject *mp,
1952 uint8_t log2_newsize, int unicode)
1953 {
1954 PyDictKeysObject *oldkeys, *newkeys;
1955 PyDictValues *oldvalues;
1956
1957 ASSERT_DICT_LOCKED(mp);
1958
1959 if (log2_newsize >= SIZEOF_SIZE_T*8) {
1960 PyErr_NoMemory();
1961 return -1;
1962 }
1963 assert(log2_newsize >= PyDict_LOG_MINSIZE);
1964
1965 oldkeys = mp->ma_keys;
1966 oldvalues = mp->ma_values;
1967
1968 if (!DK_IS_UNICODE(oldkeys)) {
1969 unicode = 0;
1970 }
1971
1972 ensure_shared_on_resize(mp);
1973 /* NOTE: Current odict checks mp->ma_keys to detect resize happen.
1974 * So we can't reuse oldkeys even if oldkeys->dk_size == newsize.
1975 * TODO: Try reusing oldkeys when reimplement odict.
1976 */
1977
1978 /* Allocate a new table. */
1979 newkeys = new_keys_object(interp, log2_newsize, unicode);
1980 if (newkeys == NULL) {
1981 return -1;
1982 }
1983 // New table must be large enough.
1984 assert(newkeys->dk_usable >= mp->ma_used);
1985
1986 Py_ssize_t numentries = mp->ma_used;
1987
1988 if (oldvalues != NULL) {
1989 LOCK_KEYS(oldkeys);
1990 PyDictUnicodeEntry *oldentries = DK_UNICODE_ENTRIES(oldkeys);
1991 /* Convert split table into new combined table.
1992 * We must incref keys; we can transfer values.
1993 */
1994 if (newkeys->dk_kind == DICT_KEYS_GENERAL) {
1995 // split -> generic
1996 PyDictKeyEntry *newentries = DK_ENTRIES(newkeys);
1997
1998 for (Py_ssize_t i = 0; i < numentries; i++) {
1999 int index = get_index_from_order(mp, i);
2000 PyDictUnicodeEntry *ep = &oldentries[index];
2001 assert(oldvalues->values[index] != NULL);
2002 newentries[i].me_key = Py_NewRef(ep->me_key);
2003 newentries[i].me_hash = unicode_get_hash(ep->me_key);
2004 newentries[i].me_value = oldvalues->values[index];
2005 }
2006 build_indices_generic(newkeys, newentries, numentries);
2007 }
2008 else { // split -> combined unicode
2009 PyDictUnicodeEntry *newentries = DK_UNICODE_ENTRIES(newkeys);
2010
2011 for (Py_ssize_t i = 0; i < numentries; i++) {
2012 int index = get_index_from_order(mp, i);
2013 PyDictUnicodeEntry *ep = &oldentries[index];
2014 assert(oldvalues->values[index] != NULL);
2015 newentries[i].me_key = Py_NewRef(ep->me_key);
2016 newentries[i].me_value = oldvalues->values[index];
2017 }
2018 build_indices_unicode(newkeys, newentries, numentries);
2019 }
2020 UNLOCK_KEYS(oldkeys);
2021 set_keys(mp, newkeys);
2022 dictkeys_decref(interp, oldkeys, IS_DICT_SHARED(mp));
2023 set_values(mp, NULL);
2024 if (oldvalues->embedded) {
2025 assert(oldvalues->embedded == 1);
2026 assert(oldvalues->valid == 1);
2027 FT_ATOMIC_STORE_UINT8(oldvalues->valid, 0);
2028 }
2029 else {
2030 free_values(oldvalues, IS_DICT_SHARED(mp));
2031 }
2032 }
2033 else { // oldkeys is combined.
2034 if (oldkeys->dk_kind == DICT_KEYS_GENERAL) {
2035 // generic -> generic
2036 assert(newkeys->dk_kind == DICT_KEYS_GENERAL);
2037 PyDictKeyEntry *oldentries = DK_ENTRIES(oldkeys);
2038 PyDictKeyEntry *newentries = DK_ENTRIES(newkeys);
2039 if (oldkeys->dk_nentries == numentries) {
2040 memcpy(newentries, oldentries, numentries * sizeof(PyDictKeyEntry));
2041 }
2042 else {
2043 PyDictKeyEntry *ep = oldentries;
2044 for (Py_ssize_t i = 0; i < numentries; i++) {
2045 while (ep->me_value == NULL)
2046 ep++;
2047 newentries[i] = *ep++;
2048 }
2049 }
2050 build_indices_generic(newkeys, newentries, numentries);
2051 }
2052 else { // oldkeys is combined unicode
2053 PyDictUnicodeEntry *oldentries = DK_UNICODE_ENTRIES(oldkeys);
2054 if (unicode) { // combined unicode -> combined unicode
2055 PyDictUnicodeEntry *newentries = DK_UNICODE_ENTRIES(newkeys);
2056 if (oldkeys->dk_nentries == numentries && mp->ma_keys->dk_kind == DICT_KEYS_UNICODE) {
2057 memcpy(newentries, oldentries, numentries * sizeof(PyDictUnicodeEntry));
2058 }
2059 else {
2060 PyDictUnicodeEntry *ep = oldentries;
2061 for (Py_ssize_t i = 0; i < numentries; i++) {
2062 while (ep->me_value == NULL)
2063 ep++;
2064 newentries[i] = *ep++;
2065 }
2066 }
2067 build_indices_unicode(newkeys, newentries, numentries);
2068 }
2069 else { // combined unicode -> generic
2070 PyDictKeyEntry *newentries = DK_ENTRIES(newkeys);
2071 PyDictUnicodeEntry *ep = oldentries;
2072 for (Py_ssize_t i = 0; i < numentries; i++) {
2073 while (ep->me_value == NULL)
2074 ep++;
2075 newentries[i].me_key = ep->me_key;
2076 newentries[i].me_hash = unicode_get_hash(ep->me_key);
2077 newentries[i].me_value = ep->me_value;
2078 ep++;
2079 }
2080 build_indices_generic(newkeys, newentries, numentries);
2081 }
2082 }
2083
2084 set_keys(mp, newkeys);
2085
2086 if (oldkeys != Py_EMPTY_KEYS) {
2087 #ifdef Py_REF_DEBUG
2088 _Py_DecRefTotal(_PyThreadState_GET());
2089 #endif
2090 assert(oldkeys->dk_kind != DICT_KEYS_SPLIT);
2091 assert(oldkeys->dk_refcnt == 1);
2092 free_keys_object(oldkeys, IS_DICT_SHARED(mp));
2093 }
2094 }
2095
2096 STORE_KEYS_USABLE(mp->ma_keys, mp->ma_keys->dk_usable - numentries);
2097 STORE_KEYS_NENTRIES(mp->ma_keys, numentries);
2098 ASSERT_CONSISTENT(mp);
2099 return 0;
2100 }
2101
2102 static PyObject *
dict_new_presized(PyInterpreterState * interp,Py_ssize_t minused,bool unicode)2103 dict_new_presized(PyInterpreterState *interp, Py_ssize_t minused, bool unicode)
2104 {
2105 const uint8_t log2_max_presize = 17;
2106 const Py_ssize_t max_presize = ((Py_ssize_t)1) << log2_max_presize;
2107 uint8_t log2_newsize;
2108 PyDictKeysObject *new_keys;
2109
2110 if (minused <= USABLE_FRACTION(PyDict_MINSIZE)) {
2111 return PyDict_New();
2112 }
2113 /* There are no strict guarantee that returned dict can contain minused
2114 * items without resize. So we create medium size dict instead of very
2115 * large dict or MemoryError.
2116 */
2117 if (minused > USABLE_FRACTION(max_presize)) {
2118 log2_newsize = log2_max_presize;
2119 }
2120 else {
2121 log2_newsize = estimate_log2_keysize(minused);
2122 }
2123
2124 new_keys = new_keys_object(interp, log2_newsize, unicode);
2125 if (new_keys == NULL)
2126 return NULL;
2127 return new_dict(interp, new_keys, NULL, 0, 0);
2128 }
2129
2130 PyObject *
_PyDict_NewPresized(Py_ssize_t minused)2131 _PyDict_NewPresized(Py_ssize_t minused)
2132 {
2133 PyInterpreterState *interp = _PyInterpreterState_GET();
2134 return dict_new_presized(interp, minused, false);
2135 }
2136
2137 PyObject *
_PyDict_FromItems(PyObject * const * keys,Py_ssize_t keys_offset,PyObject * const * values,Py_ssize_t values_offset,Py_ssize_t length)2138 _PyDict_FromItems(PyObject *const *keys, Py_ssize_t keys_offset,
2139 PyObject *const *values, Py_ssize_t values_offset,
2140 Py_ssize_t length)
2141 {
2142 bool unicode = true;
2143 PyObject *const *ks = keys;
2144 PyInterpreterState *interp = _PyInterpreterState_GET();
2145
2146 for (Py_ssize_t i = 0; i < length; i++) {
2147 if (!PyUnicode_CheckExact(*ks)) {
2148 unicode = false;
2149 break;
2150 }
2151 ks += keys_offset;
2152 }
2153
2154 PyObject *dict = dict_new_presized(interp, length, unicode);
2155 if (dict == NULL) {
2156 return NULL;
2157 }
2158
2159 ks = keys;
2160 PyObject *const *vs = values;
2161
2162 for (Py_ssize_t i = 0; i < length; i++) {
2163 PyObject *key = *ks;
2164 PyObject *value = *vs;
2165 if (setitem_lock_held((PyDictObject *)dict, key, value) < 0) {
2166 Py_DECREF(dict);
2167 return NULL;
2168 }
2169 ks += keys_offset;
2170 vs += values_offset;
2171 }
2172
2173 return dict;
2174 }
2175
2176 /* Note that, for historical reasons, PyDict_GetItem() suppresses all errors
2177 * that may occur (originally dicts supported only string keys, and exceptions
2178 * weren't possible). So, while the original intent was that a NULL return
2179 * meant the key wasn't present, in reality it can mean that, or that an error
2180 * (suppressed) occurred while computing the key's hash, or that some error
2181 * (suppressed) occurred when comparing keys in the dict's internal probe
2182 * sequence. A nasty example of the latter is when a Python-coded comparison
2183 * function hits a stack-depth error, which can cause this to return NULL
2184 * even if the key is present.
2185 */
2186 static PyObject *
dict_getitem(PyObject * op,PyObject * key,const char * warnmsg)2187 dict_getitem(PyObject *op, PyObject *key, const char *warnmsg)
2188 {
2189 if (!PyDict_Check(op)) {
2190 return NULL;
2191 }
2192 PyDictObject *mp = (PyDictObject *)op;
2193
2194 Py_hash_t hash = _PyObject_HashFast(key);
2195 if (hash == -1) {
2196 PyErr_FormatUnraisable(warnmsg);
2197 return NULL;
2198 }
2199
2200 PyThreadState *tstate = _PyThreadState_GET();
2201 #ifdef Py_DEBUG
2202 // bpo-40839: Before Python 3.10, it was possible to call PyDict_GetItem()
2203 // with the GIL released.
2204 _Py_EnsureTstateNotNULL(tstate);
2205 #endif
2206
2207 /* Preserve the existing exception */
2208 PyObject *value;
2209 Py_ssize_t ix; (void)ix;
2210
2211 PyObject *exc = _PyErr_GetRaisedException(tstate);
2212 #ifdef Py_GIL_DISABLED
2213 ix = _Py_dict_lookup_threadsafe(mp, key, hash, &value);
2214 Py_XDECREF(value);
2215 #else
2216 ix = _Py_dict_lookup(mp, key, hash, &value);
2217 #endif
2218
2219 /* Ignore any exception raised by the lookup */
2220 PyObject *exc2 = _PyErr_Occurred(tstate);
2221 if (exc2 && !PyErr_GivenExceptionMatches(exc2, PyExc_KeyError)) {
2222 PyErr_FormatUnraisable(warnmsg);
2223 }
2224 _PyErr_SetRaisedException(tstate, exc);
2225
2226 assert(ix >= 0 || value == NULL);
2227 return value; // borrowed reference
2228 }
2229
2230 PyObject *
PyDict_GetItem(PyObject * op,PyObject * key)2231 PyDict_GetItem(PyObject *op, PyObject *key)
2232 {
2233 return dict_getitem(op, key,
2234 "Exception ignored in PyDict_GetItem(); consider using "
2235 "PyDict_GetItemRef() or PyDict_GetItemWithError()");
2236 }
2237
2238 Py_ssize_t
_PyDict_LookupIndex(PyDictObject * mp,PyObject * key)2239 _PyDict_LookupIndex(PyDictObject *mp, PyObject *key)
2240 {
2241 // TODO: Thread safety
2242 PyObject *value;
2243 assert(PyDict_CheckExact((PyObject*)mp));
2244 assert(PyUnicode_CheckExact(key));
2245
2246 Py_hash_t hash = _PyObject_HashFast(key);
2247 if (hash == -1) {
2248 return -1;
2249 }
2250
2251 return _Py_dict_lookup(mp, key, hash, &value);
2252 }
2253
2254 /* Same as PyDict_GetItemWithError() but with hash supplied by caller.
2255 This returns NULL *with* an exception set if an exception occurred.
2256 It returns NULL *without* an exception set if the key wasn't present.
2257 */
2258 PyObject *
_PyDict_GetItem_KnownHash(PyObject * op,PyObject * key,Py_hash_t hash)2259 _PyDict_GetItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
2260 {
2261 Py_ssize_t ix; (void)ix;
2262 PyDictObject *mp = (PyDictObject *)op;
2263 PyObject *value;
2264
2265 if (!PyDict_Check(op)) {
2266 PyErr_BadInternalCall();
2267 return NULL;
2268 }
2269
2270 #ifdef Py_GIL_DISABLED
2271 ix = _Py_dict_lookup_threadsafe(mp, key, hash, &value);
2272 Py_XDECREF(value);
2273 #else
2274 ix = _Py_dict_lookup(mp, key, hash, &value);
2275 #endif
2276 assert(ix >= 0 || value == NULL);
2277 return value; // borrowed reference
2278 }
2279
2280 /* Gets an item and provides a new reference if the value is present.
2281 * Returns 1 if the key is present, 0 if the key is missing, and -1 if an
2282 * exception occurred.
2283 */
2284 int
_PyDict_GetItemRef_KnownHash_LockHeld(PyDictObject * op,PyObject * key,Py_hash_t hash,PyObject ** result)2285 _PyDict_GetItemRef_KnownHash_LockHeld(PyDictObject *op, PyObject *key,
2286 Py_hash_t hash, PyObject **result)
2287 {
2288 PyObject *value;
2289 Py_ssize_t ix = _Py_dict_lookup(op, key, hash, &value);
2290 assert(ix >= 0 || value == NULL);
2291 if (ix == DKIX_ERROR) {
2292 *result = NULL;
2293 return -1;
2294 }
2295 if (value == NULL) {
2296 *result = NULL;
2297 return 0; // missing key
2298 }
2299 *result = Py_NewRef(value);
2300 return 1; // key is present
2301 }
2302
2303 /* Gets an item and provides a new reference if the value is present.
2304 * Returns 1 if the key is present, 0 if the key is missing, and -1 if an
2305 * exception occurred.
2306 */
2307 int
_PyDict_GetItemRef_KnownHash(PyDictObject * op,PyObject * key,Py_hash_t hash,PyObject ** result)2308 _PyDict_GetItemRef_KnownHash(PyDictObject *op, PyObject *key, Py_hash_t hash, PyObject **result)
2309 {
2310 PyObject *value;
2311 #ifdef Py_GIL_DISABLED
2312 Py_ssize_t ix = _Py_dict_lookup_threadsafe(op, key, hash, &value);
2313 #else
2314 Py_ssize_t ix = _Py_dict_lookup(op, key, hash, &value);
2315 #endif
2316 assert(ix >= 0 || value == NULL);
2317 if (ix == DKIX_ERROR) {
2318 *result = NULL;
2319 return -1;
2320 }
2321 if (value == NULL) {
2322 *result = NULL;
2323 return 0; // missing key
2324 }
2325 #ifdef Py_GIL_DISABLED
2326 *result = value;
2327 #else
2328 *result = Py_NewRef(value);
2329 #endif
2330 return 1; // key is present
2331 }
2332
2333 int
PyDict_GetItemRef(PyObject * op,PyObject * key,PyObject ** result)2334 PyDict_GetItemRef(PyObject *op, PyObject *key, PyObject **result)
2335 {
2336 if (!PyDict_Check(op)) {
2337 PyErr_BadInternalCall();
2338 *result = NULL;
2339 return -1;
2340 }
2341
2342 Py_hash_t hash = _PyObject_HashFast(key);
2343 if (hash == -1) {
2344 *result = NULL;
2345 return -1;
2346 }
2347
2348 return _PyDict_GetItemRef_KnownHash((PyDictObject *)op, key, hash, result);
2349 }
2350
2351 int
_PyDict_GetItemRef_Unicode_LockHeld(PyDictObject * op,PyObject * key,PyObject ** result)2352 _PyDict_GetItemRef_Unicode_LockHeld(PyDictObject *op, PyObject *key, PyObject **result)
2353 {
2354 ASSERT_DICT_LOCKED(op);
2355 assert(PyUnicode_CheckExact(key));
2356
2357 Py_hash_t hash = _PyObject_HashFast(key);
2358 if (hash == -1) {
2359 *result = NULL;
2360 return -1;
2361 }
2362
2363 PyObject *value;
2364 Py_ssize_t ix = _Py_dict_lookup(op, key, hash, &value);
2365 assert(ix >= 0 || value == NULL);
2366 if (ix == DKIX_ERROR) {
2367 *result = NULL;
2368 return -1;
2369 }
2370 if (value == NULL) {
2371 *result = NULL;
2372 return 0; // missing key
2373 }
2374 *result = Py_NewRef(value);
2375 return 1; // key is present
2376 }
2377
2378 /* Variant of PyDict_GetItem() that doesn't suppress exceptions.
2379 This returns NULL *with* an exception set if an exception occurred.
2380 It returns NULL *without* an exception set if the key wasn't present.
2381 */
2382 PyObject *
PyDict_GetItemWithError(PyObject * op,PyObject * key)2383 PyDict_GetItemWithError(PyObject *op, PyObject *key)
2384 {
2385 Py_ssize_t ix; (void)ix;
2386 Py_hash_t hash;
2387 PyDictObject*mp = (PyDictObject *)op;
2388 PyObject *value;
2389
2390 if (!PyDict_Check(op)) {
2391 PyErr_BadInternalCall();
2392 return NULL;
2393 }
2394 hash = _PyObject_HashFast(key);
2395 if (hash == -1) {
2396 return NULL;
2397 }
2398
2399 #ifdef Py_GIL_DISABLED
2400 ix = _Py_dict_lookup_threadsafe(mp, key, hash, &value);
2401 Py_XDECREF(value);
2402 #else
2403 ix = _Py_dict_lookup(mp, key, hash, &value);
2404 #endif
2405 assert(ix >= 0 || value == NULL);
2406 return value; // borrowed reference
2407 }
2408
2409 PyObject *
_PyDict_GetItemWithError(PyObject * dp,PyObject * kv)2410 _PyDict_GetItemWithError(PyObject *dp, PyObject *kv)
2411 {
2412 assert(PyUnicode_CheckExact(kv));
2413 Py_hash_t hash = kv->ob_type->tp_hash(kv);
2414 if (hash == -1) {
2415 return NULL;
2416 }
2417 return _PyDict_GetItem_KnownHash(dp, kv, hash); // borrowed reference
2418 }
2419
2420 PyObject *
_PyDict_GetItemIdWithError(PyObject * dp,_Py_Identifier * key)2421 _PyDict_GetItemIdWithError(PyObject *dp, _Py_Identifier *key)
2422 {
2423 PyObject *kv;
2424 kv = _PyUnicode_FromId(key); /* borrowed */
2425 if (kv == NULL)
2426 return NULL;
2427 Py_hash_t hash = unicode_get_hash(kv);
2428 assert (hash != -1); /* interned strings have their hash value initialised */
2429 return _PyDict_GetItem_KnownHash(dp, kv, hash); // borrowed reference
2430 }
2431
2432 PyObject *
_PyDict_GetItemStringWithError(PyObject * v,const char * key)2433 _PyDict_GetItemStringWithError(PyObject *v, const char *key)
2434 {
2435 PyObject *kv, *rv;
2436 kv = PyUnicode_FromString(key);
2437 if (kv == NULL) {
2438 return NULL;
2439 }
2440 rv = PyDict_GetItemWithError(v, kv);
2441 Py_DECREF(kv);
2442 return rv;
2443 }
2444
2445 /* Fast version of global value lookup (LOAD_GLOBAL).
2446 * Lookup in globals, then builtins.
2447 *
2448 *
2449 *
2450 *
2451 * Raise an exception and return NULL if an error occurred (ex: computing the
2452 * key hash failed, key comparison failed, ...). Return NULL if the key doesn't
2453 * exist. Return the value if the key exists.
2454 *
2455 * Returns a new reference.
2456 */
2457 PyObject *
_PyDict_LoadGlobal(PyDictObject * globals,PyDictObject * builtins,PyObject * key)2458 _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
2459 {
2460 Py_ssize_t ix;
2461 Py_hash_t hash;
2462 PyObject *value;
2463
2464 hash = _PyObject_HashFast(key);
2465 if (hash == -1) {
2466 return NULL;
2467 }
2468
2469 /* namespace 1: globals */
2470 ix = _Py_dict_lookup_threadsafe(globals, key, hash, &value);
2471 if (ix == DKIX_ERROR)
2472 return NULL;
2473 if (ix != DKIX_EMPTY && value != NULL)
2474 return value;
2475
2476 /* namespace 2: builtins */
2477 ix = _Py_dict_lookup_threadsafe(builtins, key, hash, &value);
2478 assert(ix >= 0 || value == NULL);
2479 return value;
2480 }
2481
2482 /* Consumes references to key and value */
2483 static int
setitem_take2_lock_held(PyDictObject * mp,PyObject * key,PyObject * value)2484 setitem_take2_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
2485 {
2486 ASSERT_DICT_LOCKED(mp);
2487
2488 assert(key);
2489 assert(value);
2490 assert(PyDict_Check(mp));
2491 Py_hash_t hash = _PyObject_HashFast(key);
2492 if (hash == -1) {
2493 Py_DECREF(key);
2494 Py_DECREF(value);
2495 return -1;
2496 }
2497
2498 PyInterpreterState *interp = _PyInterpreterState_GET();
2499
2500 if (mp->ma_keys == Py_EMPTY_KEYS) {
2501 return insert_to_emptydict(interp, mp, key, hash, value);
2502 }
2503 /* insertdict() handles any resizing that might be necessary */
2504 return insertdict(interp, mp, key, hash, value);
2505 }
2506
2507 int
_PyDict_SetItem_Take2(PyDictObject * mp,PyObject * key,PyObject * value)2508 _PyDict_SetItem_Take2(PyDictObject *mp, PyObject *key, PyObject *value)
2509 {
2510 int res;
2511 Py_BEGIN_CRITICAL_SECTION(mp);
2512 res = setitem_take2_lock_held(mp, key, value);
2513 Py_END_CRITICAL_SECTION();
2514 return res;
2515 }
2516
2517 /* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
2518 * dictionary if it's merely replacing the value for an existing key.
2519 * This means that it's safe to loop over a dictionary with PyDict_Next()
2520 * and occasionally replace a value -- but you can't insert new keys or
2521 * remove them.
2522 */
2523 int
PyDict_SetItem(PyObject * op,PyObject * key,PyObject * value)2524 PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value)
2525 {
2526 if (!PyDict_Check(op)) {
2527 PyErr_BadInternalCall();
2528 return -1;
2529 }
2530 assert(key);
2531 assert(value);
2532 return _PyDict_SetItem_Take2((PyDictObject *)op,
2533 Py_NewRef(key), Py_NewRef(value));
2534 }
2535
2536 static int
setitem_lock_held(PyDictObject * mp,PyObject * key,PyObject * value)2537 setitem_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
2538 {
2539 assert(key);
2540 assert(value);
2541 return setitem_take2_lock_held(mp,
2542 Py_NewRef(key), Py_NewRef(value));
2543 }
2544
2545
2546 int
_PyDict_SetItem_KnownHash_LockHeld(PyDictObject * mp,PyObject * key,PyObject * value,Py_hash_t hash)2547 _PyDict_SetItem_KnownHash_LockHeld(PyDictObject *mp, PyObject *key, PyObject *value,
2548 Py_hash_t hash)
2549 {
2550 PyInterpreterState *interp = _PyInterpreterState_GET();
2551 if (mp->ma_keys == Py_EMPTY_KEYS) {
2552 return insert_to_emptydict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value));
2553 }
2554 /* insertdict() handles any resizing that might be necessary */
2555 return insertdict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value));
2556 }
2557
2558 int
_PyDict_SetItem_KnownHash(PyObject * op,PyObject * key,PyObject * value,Py_hash_t hash)2559 _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
2560 Py_hash_t hash)
2561 {
2562 if (!PyDict_Check(op)) {
2563 PyErr_BadInternalCall();
2564 return -1;
2565 }
2566 assert(key);
2567 assert(value);
2568 assert(hash != -1);
2569
2570 int res;
2571 Py_BEGIN_CRITICAL_SECTION(op);
2572 res = _PyDict_SetItem_KnownHash_LockHeld((PyDictObject *)op, key, value, hash);
2573 Py_END_CRITICAL_SECTION();
2574 return res;
2575 }
2576
2577 static void
delete_index_from_values(PyDictValues * values,Py_ssize_t ix)2578 delete_index_from_values(PyDictValues *values, Py_ssize_t ix)
2579 {
2580 uint8_t *array = get_insertion_order_array(values);
2581 int size = values->size;
2582 assert(size <= values->capacity);
2583 int i;
2584 for (i = 0; array[i] != ix; i++) {
2585 assert(i < size);
2586 }
2587 assert(i < size);
2588 size--;
2589 for (; i < size; i++) {
2590 array[i] = array[i+1];
2591 }
2592 values->size = size;
2593 }
2594
2595 static void
delitem_common(PyDictObject * mp,Py_hash_t hash,Py_ssize_t ix,PyObject * old_value,uint64_t new_version)2596 delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
2597 PyObject *old_value, uint64_t new_version)
2598 {
2599 PyObject *old_key;
2600
2601 ASSERT_DICT_LOCKED(mp);
2602
2603 Py_ssize_t hashpos = lookdict_index(mp->ma_keys, hash, ix);
2604 assert(hashpos >= 0);
2605
2606 STORE_USED(mp, mp->ma_used - 1);
2607 mp->ma_version_tag = new_version;
2608 if (_PyDict_HasSplitTable(mp)) {
2609 assert(old_value == mp->ma_values->values[ix]);
2610 STORE_SPLIT_VALUE(mp, ix, NULL);
2611 assert(ix < SHARED_KEYS_MAX_SIZE);
2612 /* Update order */
2613 delete_index_from_values(mp->ma_values, ix);
2614 ASSERT_CONSISTENT(mp);
2615 }
2616 else {
2617 mp->ma_keys->dk_version = 0;
2618 dictkeys_set_index(mp->ma_keys, hashpos, DKIX_DUMMY);
2619 if (DK_IS_UNICODE(mp->ma_keys)) {
2620 PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[ix];
2621 old_key = ep->me_key;
2622 STORE_KEY(ep, NULL);
2623 STORE_VALUE(ep, NULL);
2624 }
2625 else {
2626 PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[ix];
2627 old_key = ep->me_key;
2628 STORE_KEY(ep, NULL);
2629 STORE_VALUE(ep, NULL);
2630 STORE_HASH(ep, 0);
2631 }
2632 Py_DECREF(old_key);
2633 }
2634 Py_DECREF(old_value);
2635
2636 ASSERT_CONSISTENT(mp);
2637 }
2638
2639 int
PyDict_DelItem(PyObject * op,PyObject * key)2640 PyDict_DelItem(PyObject *op, PyObject *key)
2641 {
2642 assert(key);
2643 Py_hash_t hash = _PyObject_HashFast(key);
2644 if (hash == -1) {
2645 return -1;
2646 }
2647
2648 return _PyDict_DelItem_KnownHash(op, key, hash);
2649 }
2650
2651 static int
delitem_knownhash_lock_held(PyObject * op,PyObject * key,Py_hash_t hash)2652 delitem_knownhash_lock_held(PyObject *op, PyObject *key, Py_hash_t hash)
2653 {
2654 Py_ssize_t ix;
2655 PyDictObject *mp;
2656 PyObject *old_value;
2657
2658 if (!PyDict_Check(op)) {
2659 PyErr_BadInternalCall();
2660 return -1;
2661 }
2662
2663 ASSERT_DICT_LOCKED(op);
2664
2665 assert(key);
2666 assert(hash != -1);
2667 mp = (PyDictObject *)op;
2668 ix = _Py_dict_lookup(mp, key, hash, &old_value);
2669 if (ix == DKIX_ERROR)
2670 return -1;
2671 if (ix == DKIX_EMPTY || old_value == NULL) {
2672 _PyErr_SetKeyError(key);
2673 return -1;
2674 }
2675
2676 PyInterpreterState *interp = _PyInterpreterState_GET();
2677 uint64_t new_version = _PyDict_NotifyEvent(
2678 interp, PyDict_EVENT_DELETED, mp, key, NULL);
2679 delitem_common(mp, hash, ix, old_value, new_version);
2680 return 0;
2681 }
2682
2683 int
_PyDict_DelItem_KnownHash(PyObject * op,PyObject * key,Py_hash_t hash)2684 _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
2685 {
2686 int res;
2687 Py_BEGIN_CRITICAL_SECTION(op);
2688 res = delitem_knownhash_lock_held(op, key, hash);
2689 Py_END_CRITICAL_SECTION();
2690 return res;
2691 }
2692
2693 static int
delitemif_lock_held(PyObject * op,PyObject * key,int (* predicate)(PyObject * value,void * arg),void * arg)2694 delitemif_lock_held(PyObject *op, PyObject *key,
2695 int (*predicate)(PyObject *value, void *arg),
2696 void *arg)
2697 {
2698 Py_ssize_t ix;
2699 PyDictObject *mp;
2700 Py_hash_t hash;
2701 PyObject *old_value;
2702 int res;
2703
2704 ASSERT_DICT_LOCKED(op);
2705
2706 assert(key);
2707 hash = PyObject_Hash(key);
2708 if (hash == -1)
2709 return -1;
2710 mp = (PyDictObject *)op;
2711 ix = _Py_dict_lookup(mp, key, hash, &old_value);
2712 if (ix == DKIX_ERROR) {
2713 return -1;
2714 }
2715 if (ix == DKIX_EMPTY || old_value == NULL) {
2716 return 0;
2717 }
2718
2719 res = predicate(old_value, arg);
2720 if (res == -1)
2721 return -1;
2722
2723 if (res > 0) {
2724 PyInterpreterState *interp = _PyInterpreterState_GET();
2725 uint64_t new_version = _PyDict_NotifyEvent(
2726 interp, PyDict_EVENT_DELETED, mp, key, NULL);
2727 delitem_common(mp, hash, ix, old_value, new_version);
2728 return 1;
2729 } else {
2730 return 0;
2731 }
2732 }
2733 /* This function promises that the predicate -> deletion sequence is atomic
2734 * (i.e. protected by the GIL or the per-dict mutex in free threaded builds),
2735 * assuming the predicate itself doesn't release the GIL (or cause re-entrancy
2736 * which would release the per-dict mutex)
2737 */
2738 int
_PyDict_DelItemIf(PyObject * op,PyObject * key,int (* predicate)(PyObject * value,void * arg),void * arg)2739 _PyDict_DelItemIf(PyObject *op, PyObject *key,
2740 int (*predicate)(PyObject *value, void *arg),
2741 void *arg)
2742 {
2743 assert(PyDict_Check(op));
2744 int res;
2745 Py_BEGIN_CRITICAL_SECTION(op);
2746 res = delitemif_lock_held(op, key, predicate, arg);
2747 Py_END_CRITICAL_SECTION();
2748 return res;
2749 }
2750
2751 static void
clear_lock_held(PyObject * op)2752 clear_lock_held(PyObject *op)
2753 {
2754 PyDictObject *mp;
2755 PyDictKeysObject *oldkeys;
2756 PyDictValues *oldvalues;
2757 Py_ssize_t i, n;
2758
2759 ASSERT_DICT_LOCKED(op);
2760
2761 if (!PyDict_Check(op))
2762 return;
2763 mp = ((PyDictObject *)op);
2764 oldkeys = mp->ma_keys;
2765 oldvalues = mp->ma_values;
2766 if (oldkeys == Py_EMPTY_KEYS) {
2767 return;
2768 }
2769 /* Empty the dict... */
2770 PyInterpreterState *interp = _PyInterpreterState_GET();
2771 uint64_t new_version = _PyDict_NotifyEvent(
2772 interp, PyDict_EVENT_CLEARED, mp, NULL, NULL);
2773 // We don't inc ref empty keys because they're immortal
2774 ensure_shared_on_resize(mp);
2775 mp->ma_version_tag = new_version;
2776 STORE_USED(mp, 0);
2777 if (oldvalues == NULL) {
2778 set_keys(mp, Py_EMPTY_KEYS);
2779 assert(oldkeys->dk_refcnt == 1);
2780 dictkeys_decref(interp, oldkeys, IS_DICT_SHARED(mp));
2781 }
2782 else {
2783 n = oldkeys->dk_nentries;
2784 for (i = 0; i < n; i++) {
2785 Py_CLEAR(oldvalues->values[i]);
2786 }
2787 if (oldvalues->embedded) {
2788 oldvalues->size = 0;
2789 }
2790 else {
2791 set_values(mp, NULL);
2792 set_keys(mp, Py_EMPTY_KEYS);
2793 free_values(oldvalues, IS_DICT_SHARED(mp));
2794 dictkeys_decref(interp, oldkeys, false);
2795 }
2796 }
2797 ASSERT_CONSISTENT(mp);
2798 }
2799
2800 void
PyDict_Clear(PyObject * op)2801 PyDict_Clear(PyObject *op)
2802 {
2803 Py_BEGIN_CRITICAL_SECTION(op);
2804 clear_lock_held(op);
2805 Py_END_CRITICAL_SECTION();
2806 }
2807
2808 /* Internal version of PyDict_Next that returns a hash value in addition
2809 * to the key and value.
2810 * Return 1 on success, return 0 when the reached the end of the dictionary
2811 * (or if op is not a dictionary)
2812 */
2813 int
_PyDict_Next(PyObject * op,Py_ssize_t * ppos,PyObject ** pkey,PyObject ** pvalue,Py_hash_t * phash)2814 _PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
2815 PyObject **pvalue, Py_hash_t *phash)
2816 {
2817 Py_ssize_t i;
2818 PyDictObject *mp;
2819 PyObject *key, *value;
2820 Py_hash_t hash;
2821
2822 if (!PyDict_Check(op))
2823 return 0;
2824
2825 mp = (PyDictObject *)op;
2826 i = *ppos;
2827 if (_PyDict_HasSplitTable(mp)) {
2828 assert(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
2829 if (i < 0 || i >= mp->ma_used)
2830 return 0;
2831 int index = get_index_from_order(mp, i);
2832 value = mp->ma_values->values[index];
2833 key = LOAD_SHARED_KEY(DK_UNICODE_ENTRIES(mp->ma_keys)[index].me_key);
2834 hash = unicode_get_hash(key);
2835 assert(value != NULL);
2836 }
2837 else {
2838 Py_ssize_t n = mp->ma_keys->dk_nentries;
2839 if (i < 0 || i >= n)
2840 return 0;
2841 if (DK_IS_UNICODE(mp->ma_keys)) {
2842 PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(mp->ma_keys)[i];
2843 while (i < n && entry_ptr->me_value == NULL) {
2844 entry_ptr++;
2845 i++;
2846 }
2847 if (i >= n)
2848 return 0;
2849 key = entry_ptr->me_key;
2850 hash = unicode_get_hash(entry_ptr->me_key);
2851 value = entry_ptr->me_value;
2852 }
2853 else {
2854 PyDictKeyEntry *entry_ptr = &DK_ENTRIES(mp->ma_keys)[i];
2855 while (i < n && entry_ptr->me_value == NULL) {
2856 entry_ptr++;
2857 i++;
2858 }
2859 if (i >= n)
2860 return 0;
2861 key = entry_ptr->me_key;
2862 hash = entry_ptr->me_hash;
2863 value = entry_ptr->me_value;
2864 }
2865 }
2866 *ppos = i+1;
2867 if (pkey)
2868 *pkey = key;
2869 if (pvalue)
2870 *pvalue = value;
2871 if (phash)
2872 *phash = hash;
2873 return 1;
2874 }
2875
2876 /*
2877 * Iterate over a dict. Use like so:
2878 *
2879 * Py_ssize_t i;
2880 * PyObject *key, *value;
2881 * i = 0; # important! i should not otherwise be changed by you
2882 * while (PyDict_Next(yourdict, &i, &key, &value)) {
2883 * Refer to borrowed references in key and value.
2884 * }
2885 *
2886 * Return 1 on success, return 0 when the reached the end of the dictionary
2887 * (or if op is not a dictionary)
2888 *
2889 * CAUTION: In general, it isn't safe to use PyDict_Next in a loop that
2890 * mutates the dict. One exception: it is safe if the loop merely changes
2891 * the values associated with the keys (but doesn't insert new keys or
2892 * delete keys), via PyDict_SetItem().
2893 */
2894 int
PyDict_Next(PyObject * op,Py_ssize_t * ppos,PyObject ** pkey,PyObject ** pvalue)2895 PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue)
2896 {
2897 return _PyDict_Next(op, ppos, pkey, pvalue, NULL);
2898 }
2899
2900
2901 /* Internal version of dict.pop(). */
2902 int
_PyDict_Pop_KnownHash(PyDictObject * mp,PyObject * key,Py_hash_t hash,PyObject ** result)2903 _PyDict_Pop_KnownHash(PyDictObject *mp, PyObject *key, Py_hash_t hash,
2904 PyObject **result)
2905 {
2906 assert(PyDict_Check(mp));
2907
2908 ASSERT_DICT_LOCKED(mp);
2909
2910 if (mp->ma_used == 0) {
2911 if (result) {
2912 *result = NULL;
2913 }
2914 return 0;
2915 }
2916
2917 PyObject *old_value;
2918 Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &old_value);
2919 if (ix == DKIX_ERROR) {
2920 if (result) {
2921 *result = NULL;
2922 }
2923 return -1;
2924 }
2925
2926 if (ix == DKIX_EMPTY || old_value == NULL) {
2927 if (result) {
2928 *result = NULL;
2929 }
2930 return 0;
2931 }
2932
2933 assert(old_value != NULL);
2934 PyInterpreterState *interp = _PyInterpreterState_GET();
2935 uint64_t new_version = _PyDict_NotifyEvent(
2936 interp, PyDict_EVENT_DELETED, mp, key, NULL);
2937 delitem_common(mp, hash, ix, Py_NewRef(old_value), new_version);
2938
2939 ASSERT_CONSISTENT(mp);
2940 if (result) {
2941 *result = old_value;
2942 }
2943 else {
2944 Py_DECREF(old_value);
2945 }
2946 return 1;
2947 }
2948
2949 static int
pop_lock_held(PyObject * op,PyObject * key,PyObject ** result)2950 pop_lock_held(PyObject *op, PyObject *key, PyObject **result)
2951 {
2952 ASSERT_DICT_LOCKED(op);
2953
2954 if (!PyDict_Check(op)) {
2955 if (result) {
2956 *result = NULL;
2957 }
2958 PyErr_BadInternalCall();
2959 return -1;
2960 }
2961 PyDictObject *dict = (PyDictObject *)op;
2962
2963 if (dict->ma_used == 0) {
2964 if (result) {
2965 *result = NULL;
2966 }
2967 return 0;
2968 }
2969
2970 Py_hash_t hash = _PyObject_HashFast(key);
2971 if (hash == -1) {
2972 if (result) {
2973 *result = NULL;
2974 }
2975 return -1;
2976 }
2977 return _PyDict_Pop_KnownHash(dict, key, hash, result);
2978 }
2979
2980 int
PyDict_Pop(PyObject * op,PyObject * key,PyObject ** result)2981 PyDict_Pop(PyObject *op, PyObject *key, PyObject **result)
2982 {
2983 int err;
2984 Py_BEGIN_CRITICAL_SECTION(op);
2985 err = pop_lock_held(op, key, result);
2986 Py_END_CRITICAL_SECTION();
2987
2988 return err;
2989 }
2990
2991
2992 int
PyDict_PopString(PyObject * op,const char * key,PyObject ** result)2993 PyDict_PopString(PyObject *op, const char *key, PyObject **result)
2994 {
2995 PyObject *key_obj = PyUnicode_FromString(key);
2996 if (key_obj == NULL) {
2997 if (result != NULL) {
2998 *result = NULL;
2999 }
3000 return -1;
3001 }
3002
3003 int res = PyDict_Pop(op, key_obj, result);
3004 Py_DECREF(key_obj);
3005 return res;
3006 }
3007
3008
3009 PyObject *
_PyDict_Pop(PyObject * dict,PyObject * key,PyObject * default_value)3010 _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value)
3011 {
3012 PyObject *result;
3013 if (PyDict_Pop(dict, key, &result) == 0) {
3014 if (default_value != NULL) {
3015 return Py_NewRef(default_value);
3016 }
3017 _PyErr_SetKeyError(key);
3018 return NULL;
3019 }
3020 return result;
3021 }
3022
3023 static PyDictObject *
dict_dict_fromkeys(PyInterpreterState * interp,PyDictObject * mp,PyObject * iterable,PyObject * value)3024 dict_dict_fromkeys(PyInterpreterState *interp, PyDictObject *mp,
3025 PyObject *iterable, PyObject *value)
3026 {
3027 PyObject *oldvalue;
3028 Py_ssize_t pos = 0;
3029 PyObject *key;
3030 Py_hash_t hash;
3031 int unicode = DK_IS_UNICODE(((PyDictObject*)iterable)->ma_keys);
3032 uint8_t new_size = Py_MAX(
3033 estimate_log2_keysize(PyDict_GET_SIZE(iterable)),
3034 DK_LOG_SIZE(mp->ma_keys));
3035 if (dictresize(interp, mp, new_size, unicode)) {
3036 Py_DECREF(mp);
3037 return NULL;
3038 }
3039
3040 while (_PyDict_Next(iterable, &pos, &key, &oldvalue, &hash)) {
3041 if (insertdict(interp, mp,
3042 Py_NewRef(key), hash, Py_NewRef(value))) {
3043 Py_DECREF(mp);
3044 return NULL;
3045 }
3046 }
3047 return mp;
3048 }
3049
3050 static PyDictObject *
dict_set_fromkeys(PyInterpreterState * interp,PyDictObject * mp,PyObject * iterable,PyObject * value)3051 dict_set_fromkeys(PyInterpreterState *interp, PyDictObject *mp,
3052 PyObject *iterable, PyObject *value)
3053 {
3054 Py_ssize_t pos = 0;
3055 PyObject *key;
3056 Py_hash_t hash;
3057
3058 if (dictresize(interp, mp,
3059 estimate_log2_keysize(PySet_GET_SIZE(iterable)), 0)) {
3060 Py_DECREF(mp);
3061 return NULL;
3062 }
3063
3064 _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(iterable);
3065 while (_PySet_NextEntryRef(iterable, &pos, &key, &hash)) {
3066 if (insertdict(interp, mp, key, hash, Py_NewRef(value))) {
3067 Py_DECREF(mp);
3068 return NULL;
3069 }
3070 }
3071 return mp;
3072 }
3073
3074 /* Internal version of dict.from_keys(). It is subclass-friendly. */
3075 PyObject *
_PyDict_FromKeys(PyObject * cls,PyObject * iterable,PyObject * value)3076 _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
3077 {
3078 PyObject *it; /* iter(iterable) */
3079 PyObject *key;
3080 PyObject *d;
3081 int status;
3082 PyInterpreterState *interp = _PyInterpreterState_GET();
3083
3084 d = _PyObject_CallNoArgs(cls);
3085 if (d == NULL)
3086 return NULL;
3087
3088
3089 if (PyDict_CheckExact(d)) {
3090 if (PyDict_CheckExact(iterable)) {
3091 PyDictObject *mp = (PyDictObject *)d;
3092
3093 Py_BEGIN_CRITICAL_SECTION2(d, iterable);
3094 d = (PyObject *)dict_dict_fromkeys(interp, mp, iterable, value);
3095 Py_END_CRITICAL_SECTION2();
3096 return d;
3097 }
3098 else if (PyAnySet_CheckExact(iterable)) {
3099 PyDictObject *mp = (PyDictObject *)d;
3100
3101 Py_BEGIN_CRITICAL_SECTION2(d, iterable);
3102 d = (PyObject *)dict_set_fromkeys(interp, mp, iterable, value);
3103 Py_END_CRITICAL_SECTION2();
3104 return d;
3105 }
3106 }
3107
3108 it = PyObject_GetIter(iterable);
3109 if (it == NULL){
3110 Py_DECREF(d);
3111 return NULL;
3112 }
3113
3114 if (PyDict_CheckExact(d)) {
3115 Py_BEGIN_CRITICAL_SECTION(d);
3116 while ((key = PyIter_Next(it)) != NULL) {
3117 status = setitem_lock_held((PyDictObject *)d, key, value);
3118 Py_DECREF(key);
3119 if (status < 0) {
3120 assert(PyErr_Occurred());
3121 goto dict_iter_exit;
3122 }
3123 }
3124 dict_iter_exit:;
3125 Py_END_CRITICAL_SECTION();
3126 } else {
3127 while ((key = PyIter_Next(it)) != NULL) {
3128 status = PyObject_SetItem(d, key, value);
3129 Py_DECREF(key);
3130 if (status < 0)
3131 goto Fail;
3132 }
3133 }
3134
3135 if (PyErr_Occurred())
3136 goto Fail;
3137 Py_DECREF(it);
3138 return d;
3139
3140 Fail:
3141 Py_DECREF(it);
3142 Py_DECREF(d);
3143 return NULL;
3144 }
3145
3146 /* Methods */
3147
3148 static void
dict_dealloc(PyObject * self)3149 dict_dealloc(PyObject *self)
3150 {
3151 PyDictObject *mp = (PyDictObject *)self;
3152 PyInterpreterState *interp = _PyInterpreterState_GET();
3153 assert(Py_REFCNT(mp) == 0);
3154 Py_SET_REFCNT(mp, 1);
3155 _PyDict_NotifyEvent(interp, PyDict_EVENT_DEALLOCATED, mp, NULL, NULL);
3156 if (Py_REFCNT(mp) > 1) {
3157 Py_SET_REFCNT(mp, Py_REFCNT(mp) - 1);
3158 return;
3159 }
3160 Py_SET_REFCNT(mp, 0);
3161 PyDictValues *values = mp->ma_values;
3162 PyDictKeysObject *keys = mp->ma_keys;
3163 Py_ssize_t i, n;
3164
3165 /* bpo-31095: UnTrack is needed before calling any callbacks */
3166 PyObject_GC_UnTrack(mp);
3167 Py_TRASHCAN_BEGIN(mp, dict_dealloc)
3168 if (values != NULL) {
3169 if (values->embedded == 0) {
3170 for (i = 0, n = mp->ma_keys->dk_nentries; i < n; i++) {
3171 Py_XDECREF(values->values[i]);
3172 }
3173 free_values(values, false);
3174 }
3175 dictkeys_decref(interp, keys, false);
3176 }
3177 else if (keys != NULL) {
3178 assert(keys->dk_refcnt == 1 || keys == Py_EMPTY_KEYS);
3179 dictkeys_decref(interp, keys, false);
3180 }
3181 #ifdef WITH_FREELISTS
3182 struct _Py_dict_freelist *freelist = get_dict_freelist();
3183 if (freelist->numfree < PyDict_MAXFREELIST && freelist->numfree >=0 &&
3184 Py_IS_TYPE(mp, &PyDict_Type)) {
3185 freelist->items[freelist->numfree++] = mp;
3186 OBJECT_STAT_INC(to_freelist);
3187 }
3188 else
3189 #endif
3190 {
3191 Py_TYPE(mp)->tp_free((PyObject *)mp);
3192 }
3193 Py_TRASHCAN_END
3194 }
3195
3196
3197 static PyObject *
dict_repr_lock_held(PyObject * self)3198 dict_repr_lock_held(PyObject *self)
3199 {
3200 PyDictObject *mp = (PyDictObject *)self;
3201 Py_ssize_t i;
3202 PyObject *key = NULL, *value = NULL;
3203 _PyUnicodeWriter writer;
3204 int first;
3205
3206 ASSERT_DICT_LOCKED(mp);
3207
3208 i = Py_ReprEnter((PyObject *)mp);
3209 if (i != 0) {
3210 return i > 0 ? PyUnicode_FromString("{...}") : NULL;
3211 }
3212
3213 if (mp->ma_used == 0) {
3214 Py_ReprLeave((PyObject *)mp);
3215 return PyUnicode_FromString("{}");
3216 }
3217
3218 _PyUnicodeWriter_Init(&writer);
3219 writer.overallocate = 1;
3220 /* "{" + "1: 2" + ", 3: 4" * (len - 1) + "}" */
3221 writer.min_length = 1 + 4 + (2 + 4) * (mp->ma_used - 1) + 1;
3222
3223 if (_PyUnicodeWriter_WriteChar(&writer, '{') < 0)
3224 goto error;
3225
3226 /* Do repr() on each key+value pair, and insert ": " between them.
3227 Note that repr may mutate the dict. */
3228 i = 0;
3229 first = 1;
3230 while (_PyDict_Next((PyObject *)mp, &i, &key, &value, NULL)) {
3231 PyObject *s;
3232 int res;
3233
3234 /* Prevent repr from deleting key or value during key format. */
3235 Py_INCREF(key);
3236 Py_INCREF(value);
3237
3238 if (!first) {
3239 if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0)
3240 goto error;
3241 }
3242 first = 0;
3243
3244 s = PyObject_Repr(key);
3245 if (s == NULL)
3246 goto error;
3247 res = _PyUnicodeWriter_WriteStr(&writer, s);
3248 Py_DECREF(s);
3249 if (res < 0)
3250 goto error;
3251
3252 if (_PyUnicodeWriter_WriteASCIIString(&writer, ": ", 2) < 0)
3253 goto error;
3254
3255 s = PyObject_Repr(value);
3256 if (s == NULL)
3257 goto error;
3258 res = _PyUnicodeWriter_WriteStr(&writer, s);
3259 Py_DECREF(s);
3260 if (res < 0)
3261 goto error;
3262
3263 Py_CLEAR(key);
3264 Py_CLEAR(value);
3265 }
3266
3267 writer.overallocate = 0;
3268 if (_PyUnicodeWriter_WriteChar(&writer, '}') < 0)
3269 goto error;
3270
3271 Py_ReprLeave((PyObject *)mp);
3272
3273 return _PyUnicodeWriter_Finish(&writer);
3274
3275 error:
3276 Py_ReprLeave((PyObject *)mp);
3277 _PyUnicodeWriter_Dealloc(&writer);
3278 Py_XDECREF(key);
3279 Py_XDECREF(value);
3280 return NULL;
3281 }
3282
3283 static PyObject *
dict_repr(PyObject * self)3284 dict_repr(PyObject *self)
3285 {
3286 PyObject *res;
3287 Py_BEGIN_CRITICAL_SECTION(self);
3288 res = dict_repr_lock_held(self);
3289 Py_END_CRITICAL_SECTION();
3290 return res;
3291 }
3292
3293 static Py_ssize_t
dict_length(PyObject * self)3294 dict_length(PyObject *self)
3295 {
3296 return FT_ATOMIC_LOAD_SSIZE_RELAXED(((PyDictObject *)self)->ma_used);
3297 }
3298
3299 static PyObject *
dict_subscript(PyObject * self,PyObject * key)3300 dict_subscript(PyObject *self, PyObject *key)
3301 {
3302 PyDictObject *mp = (PyDictObject *)self;
3303 Py_ssize_t ix;
3304 Py_hash_t hash;
3305 PyObject *value;
3306
3307 hash = _PyObject_HashFast(key);
3308 if (hash == -1) {
3309 return NULL;
3310 }
3311 ix = _Py_dict_lookup_threadsafe(mp, key, hash, &value);
3312 if (ix == DKIX_ERROR)
3313 return NULL;
3314 if (ix == DKIX_EMPTY || value == NULL) {
3315 if (!PyDict_CheckExact(mp)) {
3316 /* Look up __missing__ method if we're a subclass. */
3317 PyObject *missing, *res;
3318 missing = _PyObject_LookupSpecial(
3319 (PyObject *)mp, &_Py_ID(__missing__));
3320 if (missing != NULL) {
3321 res = PyObject_CallOneArg(missing, key);
3322 Py_DECREF(missing);
3323 return res;
3324 }
3325 else if (PyErr_Occurred())
3326 return NULL;
3327 }
3328 _PyErr_SetKeyError(key);
3329 return NULL;
3330 }
3331 return value;
3332 }
3333
3334 static int
dict_ass_sub(PyObject * mp,PyObject * v,PyObject * w)3335 dict_ass_sub(PyObject *mp, PyObject *v, PyObject *w)
3336 {
3337 if (w == NULL)
3338 return PyDict_DelItem(mp, v);
3339 else
3340 return PyDict_SetItem(mp, v, w);
3341 }
3342
3343 static PyMappingMethods dict_as_mapping = {
3344 dict_length, /*mp_length*/
3345 dict_subscript, /*mp_subscript*/
3346 dict_ass_sub, /*mp_ass_subscript*/
3347 };
3348
3349 static PyObject *
keys_lock_held(PyObject * dict)3350 keys_lock_held(PyObject *dict)
3351 {
3352 ASSERT_DICT_LOCKED(dict);
3353
3354 if (dict == NULL || !PyDict_Check(dict)) {
3355 PyErr_BadInternalCall();
3356 return NULL;
3357 }
3358 PyDictObject *mp = (PyDictObject *)dict;
3359 PyObject *v;
3360 Py_ssize_t n;
3361
3362 again:
3363 n = mp->ma_used;
3364 v = PyList_New(n);
3365 if (v == NULL)
3366 return NULL;
3367 if (n != mp->ma_used) {
3368 /* Durnit. The allocations caused the dict to resize.
3369 * Just start over, this shouldn't normally happen.
3370 */
3371 Py_DECREF(v);
3372 goto again;
3373 }
3374
3375 /* Nothing we do below makes any function calls. */
3376 Py_ssize_t j = 0, pos = 0;
3377 PyObject *key;
3378 while (_PyDict_Next((PyObject*)mp, &pos, &key, NULL, NULL)) {
3379 assert(j < n);
3380 PyList_SET_ITEM(v, j, Py_NewRef(key));
3381 j++;
3382 }
3383 assert(j == n);
3384 return v;
3385 }
3386
3387 PyObject *
PyDict_Keys(PyObject * dict)3388 PyDict_Keys(PyObject *dict)
3389 {
3390 PyObject *res;
3391 Py_BEGIN_CRITICAL_SECTION(dict);
3392 res = keys_lock_held(dict);
3393 Py_END_CRITICAL_SECTION();
3394
3395 return res;
3396 }
3397
3398 static PyObject *
values_lock_held(PyObject * dict)3399 values_lock_held(PyObject *dict)
3400 {
3401 ASSERT_DICT_LOCKED(dict);
3402
3403 if (dict == NULL || !PyDict_Check(dict)) {
3404 PyErr_BadInternalCall();
3405 return NULL;
3406 }
3407 PyDictObject *mp = (PyDictObject *)dict;
3408 PyObject *v;
3409 Py_ssize_t n;
3410
3411 again:
3412 n = mp->ma_used;
3413 v = PyList_New(n);
3414 if (v == NULL)
3415 return NULL;
3416 if (n != mp->ma_used) {
3417 /* Durnit. The allocations caused the dict to resize.
3418 * Just start over, this shouldn't normally happen.
3419 */
3420 Py_DECREF(v);
3421 goto again;
3422 }
3423
3424 /* Nothing we do below makes any function calls. */
3425 Py_ssize_t j = 0, pos = 0;
3426 PyObject *value;
3427 while (_PyDict_Next((PyObject*)mp, &pos, NULL, &value, NULL)) {
3428 assert(j < n);
3429 PyList_SET_ITEM(v, j, Py_NewRef(value));
3430 j++;
3431 }
3432 assert(j == n);
3433 return v;
3434 }
3435
3436 PyObject *
PyDict_Values(PyObject * dict)3437 PyDict_Values(PyObject *dict)
3438 {
3439 PyObject *res;
3440 Py_BEGIN_CRITICAL_SECTION(dict);
3441 res = values_lock_held(dict);
3442 Py_END_CRITICAL_SECTION();
3443 return res;
3444 }
3445
3446 static PyObject *
items_lock_held(PyObject * dict)3447 items_lock_held(PyObject *dict)
3448 {
3449 ASSERT_DICT_LOCKED(dict);
3450
3451 if (dict == NULL || !PyDict_Check(dict)) {
3452 PyErr_BadInternalCall();
3453 return NULL;
3454 }
3455 PyDictObject *mp = (PyDictObject *)dict;
3456 PyObject *v;
3457 Py_ssize_t i, n;
3458 PyObject *item;
3459
3460 /* Preallocate the list of tuples, to avoid allocations during
3461 * the loop over the items, which could trigger GC, which
3462 * could resize the dict. :-(
3463 */
3464 again:
3465 n = mp->ma_used;
3466 v = PyList_New(n);
3467 if (v == NULL)
3468 return NULL;
3469 for (i = 0; i < n; i++) {
3470 item = PyTuple_New(2);
3471 if (item == NULL) {
3472 Py_DECREF(v);
3473 return NULL;
3474 }
3475 PyList_SET_ITEM(v, i, item);
3476 }
3477 if (n != mp->ma_used) {
3478 /* Durnit. The allocations caused the dict to resize.
3479 * Just start over, this shouldn't normally happen.
3480 */
3481 Py_DECREF(v);
3482 goto again;
3483 }
3484
3485 /* Nothing we do below makes any function calls. */
3486 Py_ssize_t j = 0, pos = 0;
3487 PyObject *key, *value;
3488 while (_PyDict_Next((PyObject*)mp, &pos, &key, &value, NULL)) {
3489 assert(j < n);
3490 PyObject *item = PyList_GET_ITEM(v, j);
3491 PyTuple_SET_ITEM(item, 0, Py_NewRef(key));
3492 PyTuple_SET_ITEM(item, 1, Py_NewRef(value));
3493 j++;
3494 }
3495 assert(j == n);
3496 return v;
3497 }
3498
3499 PyObject *
PyDict_Items(PyObject * dict)3500 PyDict_Items(PyObject *dict)
3501 {
3502 PyObject *res;
3503 Py_BEGIN_CRITICAL_SECTION(dict);
3504 res = items_lock_held(dict);
3505 Py_END_CRITICAL_SECTION();
3506
3507 return res;
3508 }
3509
3510 /*[clinic input]
3511 @classmethod
3512 dict.fromkeys
3513 iterable: object
3514 value: object=None
3515 /
3516
3517 Create a new dictionary with keys from iterable and values set to value.
3518 [clinic start generated code]*/
3519
3520 static PyObject *
dict_fromkeys_impl(PyTypeObject * type,PyObject * iterable,PyObject * value)3521 dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value)
3522 /*[clinic end generated code: output=8fb98e4b10384999 input=382ba4855d0f74c3]*/
3523 {
3524 return _PyDict_FromKeys((PyObject *)type, iterable, value);
3525 }
3526
3527 /* Single-arg dict update; used by dict_update_common and operators. */
3528 static int
dict_update_arg(PyObject * self,PyObject * arg)3529 dict_update_arg(PyObject *self, PyObject *arg)
3530 {
3531 if (PyDict_CheckExact(arg)) {
3532 return PyDict_Merge(self, arg, 1);
3533 }
3534 int has_keys = PyObject_HasAttrWithError(arg, &_Py_ID(keys));
3535 if (has_keys < 0) {
3536 return -1;
3537 }
3538 if (has_keys) {
3539 return PyDict_Merge(self, arg, 1);
3540 }
3541 return PyDict_MergeFromSeq2(self, arg, 1);
3542 }
3543
3544 static int
dict_update_common(PyObject * self,PyObject * args,PyObject * kwds,const char * methname)3545 dict_update_common(PyObject *self, PyObject *args, PyObject *kwds,
3546 const char *methname)
3547 {
3548 PyObject *arg = NULL;
3549 int result = 0;
3550
3551 if (!PyArg_UnpackTuple(args, methname, 0, 1, &arg)) {
3552 result = -1;
3553 }
3554 else if (arg != NULL) {
3555 result = dict_update_arg(self, arg);
3556 }
3557
3558 if (result == 0 && kwds != NULL) {
3559 if (PyArg_ValidateKeywordArguments(kwds))
3560 result = PyDict_Merge(self, kwds, 1);
3561 else
3562 result = -1;
3563 }
3564 return result;
3565 }
3566
3567 /* Note: dict.update() uses the METH_VARARGS|METH_KEYWORDS calling convention.
3568 Using METH_FASTCALL|METH_KEYWORDS would make dict.update(**dict2) calls
3569 slower, see the issue #29312. */
3570 static PyObject *
dict_update(PyObject * self,PyObject * args,PyObject * kwds)3571 dict_update(PyObject *self, PyObject *args, PyObject *kwds)
3572 {
3573 if (dict_update_common(self, args, kwds, "update") != -1)
3574 Py_RETURN_NONE;
3575 return NULL;
3576 }
3577
3578 /* Update unconditionally replaces existing items.
3579 Merge has a 3rd argument 'override'; if set, it acts like Update,
3580 otherwise it leaves existing items unchanged.
3581
3582 PyDict_{Update,Merge} update/merge from a mapping object.
3583
3584 PyDict_MergeFromSeq2 updates/merges from any iterable object
3585 producing iterable objects of length 2.
3586 */
3587
3588 static int
merge_from_seq2_lock_held(PyObject * d,PyObject * seq2,int override)3589 merge_from_seq2_lock_held(PyObject *d, PyObject *seq2, int override)
3590 {
3591 PyObject *it; /* iter(seq2) */
3592 Py_ssize_t i; /* index into seq2 of current element */
3593 PyObject *item; /* seq2[i] */
3594 PyObject *fast; /* item as a 2-tuple or 2-list */
3595
3596 assert(d != NULL);
3597 assert(PyDict_Check(d));
3598 assert(seq2 != NULL);
3599
3600 it = PyObject_GetIter(seq2);
3601 if (it == NULL)
3602 return -1;
3603
3604 for (i = 0; ; ++i) {
3605 PyObject *key, *value;
3606 Py_ssize_t n;
3607
3608 fast = NULL;
3609 item = PyIter_Next(it);
3610 if (item == NULL) {
3611 if (PyErr_Occurred())
3612 goto Fail;
3613 break;
3614 }
3615
3616 /* Convert item to sequence, and verify length 2. */
3617 fast = PySequence_Fast(item, "");
3618 if (fast == NULL) {
3619 if (PyErr_ExceptionMatches(PyExc_TypeError))
3620 PyErr_Format(PyExc_TypeError,
3621 "cannot convert dictionary update "
3622 "sequence element #%zd to a sequence",
3623 i);
3624 goto Fail;
3625 }
3626 n = PySequence_Fast_GET_SIZE(fast);
3627 if (n != 2) {
3628 PyErr_Format(PyExc_ValueError,
3629 "dictionary update sequence element #%zd "
3630 "has length %zd; 2 is required",
3631 i, n);
3632 goto Fail;
3633 }
3634
3635 /* Update/merge with this (key, value) pair. */
3636 key = PySequence_Fast_GET_ITEM(fast, 0);
3637 value = PySequence_Fast_GET_ITEM(fast, 1);
3638 Py_INCREF(key);
3639 Py_INCREF(value);
3640 if (override) {
3641 if (setitem_lock_held((PyDictObject *)d, key, value) < 0) {
3642 Py_DECREF(key);
3643 Py_DECREF(value);
3644 goto Fail;
3645 }
3646 }
3647 else {
3648 if (dict_setdefault_ref_lock_held(d, key, value, NULL, 0) < 0) {
3649 Py_DECREF(key);
3650 Py_DECREF(value);
3651 goto Fail;
3652 }
3653 }
3654
3655 Py_DECREF(key);
3656 Py_DECREF(value);
3657 Py_DECREF(fast);
3658 Py_DECREF(item);
3659 }
3660
3661 i = 0;
3662 ASSERT_CONSISTENT(d);
3663 goto Return;
3664 Fail:
3665 Py_XDECREF(item);
3666 Py_XDECREF(fast);
3667 i = -1;
3668 Return:
3669 Py_DECREF(it);
3670 return Py_SAFE_DOWNCAST(i, Py_ssize_t, int);
3671 }
3672
3673 int
PyDict_MergeFromSeq2(PyObject * d,PyObject * seq2,int override)3674 PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override)
3675 {
3676 int res;
3677 Py_BEGIN_CRITICAL_SECTION(d);
3678 res = merge_from_seq2_lock_held(d, seq2, override);
3679 Py_END_CRITICAL_SECTION();
3680
3681 return res;
3682 }
3683
3684 static int
dict_dict_merge(PyInterpreterState * interp,PyDictObject * mp,PyDictObject * other,int override)3685 dict_dict_merge(PyInterpreterState *interp, PyDictObject *mp, PyDictObject *other, int override)
3686 {
3687 ASSERT_DICT_LOCKED(mp);
3688 ASSERT_DICT_LOCKED(other);
3689
3690 if (other == mp || other->ma_used == 0)
3691 /* a.update(a) or a.update({}); nothing to do */
3692 return 0;
3693 if (mp->ma_used == 0) {
3694 /* Since the target dict is empty, PyDict_GetItem()
3695 * always returns NULL. Setting override to 1
3696 * skips the unnecessary test.
3697 */
3698 override = 1;
3699 PyDictKeysObject *okeys = other->ma_keys;
3700
3701 // If other is clean, combined, and just allocated, just clone it.
3702 if (mp->ma_values == NULL &&
3703 other->ma_values == NULL &&
3704 other->ma_used == okeys->dk_nentries &&
3705 (DK_LOG_SIZE(okeys) == PyDict_LOG_MINSIZE ||
3706 USABLE_FRACTION(DK_SIZE(okeys)/2) < other->ma_used)
3707 ) {
3708 uint64_t new_version = _PyDict_NotifyEvent(
3709 interp, PyDict_EVENT_CLONED, mp, (PyObject *)other, NULL);
3710 PyDictKeysObject *keys = clone_combined_dict_keys(other);
3711 if (keys == NULL)
3712 return -1;
3713
3714 ensure_shared_on_resize(mp);
3715 dictkeys_decref(interp, mp->ma_keys, IS_DICT_SHARED(mp));
3716 mp->ma_keys = keys;
3717 STORE_USED(mp, other->ma_used);
3718 mp->ma_version_tag = new_version;
3719 ASSERT_CONSISTENT(mp);
3720
3721 if (_PyObject_GC_IS_TRACKED(other) && !_PyObject_GC_IS_TRACKED(mp)) {
3722 /* Maintain tracking. */
3723 _PyObject_GC_TRACK(mp);
3724 }
3725
3726 return 0;
3727 }
3728 }
3729 /* Do one big resize at the start, rather than
3730 * incrementally resizing as we insert new items. Expect
3731 * that there will be no (or few) overlapping keys.
3732 */
3733 if (USABLE_FRACTION(DK_SIZE(mp->ma_keys)) < other->ma_used) {
3734 int unicode = DK_IS_UNICODE(other->ma_keys);
3735 if (dictresize(interp, mp,
3736 estimate_log2_keysize(mp->ma_used + other->ma_used),
3737 unicode)) {
3738 return -1;
3739 }
3740 }
3741
3742 Py_ssize_t orig_size = other->ma_keys->dk_nentries;
3743 Py_ssize_t pos = 0;
3744 Py_hash_t hash;
3745 PyObject *key, *value;
3746
3747 while (_PyDict_Next((PyObject*)other, &pos, &key, &value, &hash)) {
3748 int err = 0;
3749 Py_INCREF(key);
3750 Py_INCREF(value);
3751 if (override == 1) {
3752 err = insertdict(interp, mp,
3753 Py_NewRef(key), hash, Py_NewRef(value));
3754 }
3755 else {
3756 err = _PyDict_Contains_KnownHash((PyObject *)mp, key, hash);
3757 if (err == 0) {
3758 err = insertdict(interp, mp,
3759 Py_NewRef(key), hash, Py_NewRef(value));
3760 }
3761 else if (err > 0) {
3762 if (override != 0) {
3763 _PyErr_SetKeyError(key);
3764 Py_DECREF(value);
3765 Py_DECREF(key);
3766 return -1;
3767 }
3768 err = 0;
3769 }
3770 }
3771 Py_DECREF(value);
3772 Py_DECREF(key);
3773 if (err != 0)
3774 return -1;
3775
3776 if (orig_size != other->ma_keys->dk_nentries) {
3777 PyErr_SetString(PyExc_RuntimeError,
3778 "dict mutated during update");
3779 return -1;
3780 }
3781 }
3782 return 0;
3783 }
3784
3785 static int
dict_merge(PyInterpreterState * interp,PyObject * a,PyObject * b,int override)3786 dict_merge(PyInterpreterState *interp, PyObject *a, PyObject *b, int override)
3787 {
3788 PyDictObject *mp, *other;
3789
3790 assert(0 <= override && override <= 2);
3791
3792 /* We accept for the argument either a concrete dictionary object,
3793 * or an abstract "mapping" object. For the former, we can do
3794 * things quite efficiently. For the latter, we only require that
3795 * PyMapping_Keys() and PyObject_GetItem() be supported.
3796 */
3797 if (a == NULL || !PyDict_Check(a) || b == NULL) {
3798 PyErr_BadInternalCall();
3799 return -1;
3800 }
3801 mp = (PyDictObject*)a;
3802 int res = 0;
3803 if (PyDict_Check(b) && (Py_TYPE(b)->tp_iter == dict_iter)) {
3804 other = (PyDictObject*)b;
3805 int res;
3806 Py_BEGIN_CRITICAL_SECTION2(a, b);
3807 res = dict_dict_merge(interp, (PyDictObject *)a, other, override);
3808 ASSERT_CONSISTENT(a);
3809 Py_END_CRITICAL_SECTION2();
3810 return res;
3811 }
3812 else {
3813 /* Do it the generic, slower way */
3814 Py_BEGIN_CRITICAL_SECTION(a);
3815 PyObject *keys = PyMapping_Keys(b);
3816 PyObject *iter;
3817 PyObject *key, *value;
3818 int status;
3819
3820 if (keys == NULL) {
3821 /* Docstring says this is equivalent to E.keys() so
3822 * if E doesn't have a .keys() method we want
3823 * AttributeError to percolate up. Might as well
3824 * do the same for any other error.
3825 */
3826 res = -1;
3827 goto slow_exit;
3828 }
3829
3830 iter = PyObject_GetIter(keys);
3831 Py_DECREF(keys);
3832 if (iter == NULL) {
3833 res = -1;
3834 goto slow_exit;
3835 }
3836
3837 for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) {
3838 if (override != 1) {
3839 status = PyDict_Contains(a, key);
3840 if (status != 0) {
3841 if (status > 0) {
3842 if (override == 0) {
3843 Py_DECREF(key);
3844 continue;
3845 }
3846 _PyErr_SetKeyError(key);
3847 }
3848 Py_DECREF(key);
3849 Py_DECREF(iter);
3850 res = -1;
3851 goto slow_exit;
3852 }
3853 }
3854 value = PyObject_GetItem(b, key);
3855 if (value == NULL) {
3856 Py_DECREF(iter);
3857 Py_DECREF(key);
3858 res = -1;
3859 goto slow_exit;
3860 }
3861 status = setitem_lock_held(mp, key, value);
3862 Py_DECREF(key);
3863 Py_DECREF(value);
3864 if (status < 0) {
3865 Py_DECREF(iter);
3866 res = -1;
3867 goto slow_exit;
3868 return -1;
3869 }
3870 }
3871 Py_DECREF(iter);
3872 if (PyErr_Occurred()) {
3873 /* Iterator completed, via error */
3874 res = -1;
3875 goto slow_exit;
3876 }
3877
3878 slow_exit:
3879 ASSERT_CONSISTENT(a);
3880 Py_END_CRITICAL_SECTION();
3881 return res;
3882 }
3883 }
3884
3885 int
PyDict_Update(PyObject * a,PyObject * b)3886 PyDict_Update(PyObject *a, PyObject *b)
3887 {
3888 PyInterpreterState *interp = _PyInterpreterState_GET();
3889 return dict_merge(interp, a, b, 1);
3890 }
3891
3892 int
PyDict_Merge(PyObject * a,PyObject * b,int override)3893 PyDict_Merge(PyObject *a, PyObject *b, int override)
3894 {
3895 PyInterpreterState *interp = _PyInterpreterState_GET();
3896 /* XXX Deprecate override not in (0, 1). */
3897 return dict_merge(interp, a, b, override != 0);
3898 }
3899
3900 int
_PyDict_MergeEx(PyObject * a,PyObject * b,int override)3901 _PyDict_MergeEx(PyObject *a, PyObject *b, int override)
3902 {
3903 PyInterpreterState *interp = _PyInterpreterState_GET();
3904 return dict_merge(interp, a, b, override);
3905 }
3906
3907 /*[clinic input]
3908 dict.copy
3909
3910 Return a shallow copy of the dict.
3911 [clinic start generated code]*/
3912
3913 static PyObject *
dict_copy_impl(PyDictObject * self)3914 dict_copy_impl(PyDictObject *self)
3915 /*[clinic end generated code: output=ffb782cf970a5c39 input=73935f042b639de4]*/
3916 {
3917 return PyDict_Copy((PyObject *)self);
3918 }
3919
3920 /* Copies the values, but does not change the reference
3921 * counts of the objects in the array.
3922 * Return NULL, but does *not* set an exception on failure */
3923 static PyDictValues *
copy_values(PyDictValues * values)3924 copy_values(PyDictValues *values)
3925 {
3926 PyDictValues *newvalues = new_values(values->capacity);
3927 if (newvalues == NULL) {
3928 return NULL;
3929 }
3930 newvalues->size = values->size;
3931 uint8_t *values_order = get_insertion_order_array(values);
3932 uint8_t *new_values_order = get_insertion_order_array(newvalues);
3933 memcpy(new_values_order, values_order, values->capacity);
3934 for (int i = 0; i < values->capacity; i++) {
3935 newvalues->values[i] = values->values[i];
3936 }
3937 assert(newvalues->embedded == 0);
3938 return newvalues;
3939 }
3940
3941 static PyObject *
copy_lock_held(PyObject * o)3942 copy_lock_held(PyObject *o)
3943 {
3944 PyObject *copy;
3945 PyDictObject *mp;
3946 PyInterpreterState *interp = _PyInterpreterState_GET();
3947
3948 ASSERT_DICT_LOCKED(o);
3949
3950 mp = (PyDictObject *)o;
3951 if (mp->ma_used == 0) {
3952 /* The dict is empty; just return a new dict. */
3953 return PyDict_New();
3954 }
3955
3956 if (_PyDict_HasSplitTable(mp)) {
3957 PyDictObject *split_copy;
3958 PyDictValues *newvalues = copy_values(mp->ma_values);
3959 if (newvalues == NULL) {
3960 return PyErr_NoMemory();
3961 }
3962 split_copy = PyObject_GC_New(PyDictObject, &PyDict_Type);
3963 if (split_copy == NULL) {
3964 free_values(newvalues, false);
3965 return NULL;
3966 }
3967 for (size_t i = 0; i < newvalues->capacity; i++) {
3968 Py_XINCREF(newvalues->values[i]);
3969 }
3970 split_copy->ma_values = newvalues;
3971 split_copy->ma_keys = mp->ma_keys;
3972 split_copy->ma_used = mp->ma_used;
3973 split_copy->ma_version_tag = DICT_NEXT_VERSION(interp);
3974 dictkeys_incref(mp->ma_keys);
3975 if (_PyObject_GC_IS_TRACKED(mp))
3976 _PyObject_GC_TRACK(split_copy);
3977 return (PyObject *)split_copy;
3978 }
3979
3980 if (Py_TYPE(mp)->tp_iter == dict_iter &&
3981 mp->ma_values == NULL &&
3982 (mp->ma_used >= (mp->ma_keys->dk_nentries * 2) / 3))
3983 {
3984 /* Use fast-copy if:
3985
3986 (1) type(mp) doesn't override tp_iter; and
3987
3988 (2) 'mp' is not a split-dict; and
3989
3990 (3) if 'mp' is non-compact ('del' operation does not resize dicts),
3991 do fast-copy only if it has at most 1/3 non-used keys.
3992
3993 The last condition (3) is important to guard against a pathological
3994 case when a large dict is almost emptied with multiple del/pop
3995 operations and copied after that. In cases like this, we defer to
3996 PyDict_Merge, which produces a compacted copy.
3997 */
3998 PyDictKeysObject *keys = clone_combined_dict_keys(mp);
3999 if (keys == NULL) {
4000 return NULL;
4001 }
4002 PyDictObject *new = (PyDictObject *)new_dict(interp, keys, NULL, 0, 0);
4003 if (new == NULL) {
4004 /* In case of an error, `new_dict()` takes care of
4005 cleaning up `keys`. */
4006 return NULL;
4007 }
4008
4009 new->ma_used = mp->ma_used;
4010 ASSERT_CONSISTENT(new);
4011 if (_PyObject_GC_IS_TRACKED(mp)) {
4012 /* Maintain tracking. */
4013 _PyObject_GC_TRACK(new);
4014 }
4015
4016 return (PyObject *)new;
4017 }
4018
4019 copy = PyDict_New();
4020 if (copy == NULL)
4021 return NULL;
4022 if (dict_merge(interp, copy, o, 1) == 0)
4023 return copy;
4024 Py_DECREF(copy);
4025 return NULL;
4026 }
4027
4028 PyObject *
PyDict_Copy(PyObject * o)4029 PyDict_Copy(PyObject *o)
4030 {
4031 if (o == NULL || !PyDict_Check(o)) {
4032 PyErr_BadInternalCall();
4033 return NULL;
4034 }
4035
4036 PyObject *res;
4037 Py_BEGIN_CRITICAL_SECTION(o);
4038
4039 res = copy_lock_held(o);
4040
4041 Py_END_CRITICAL_SECTION();
4042 return res;
4043 }
4044
4045 Py_ssize_t
PyDict_Size(PyObject * mp)4046 PyDict_Size(PyObject *mp)
4047 {
4048 if (mp == NULL || !PyDict_Check(mp)) {
4049 PyErr_BadInternalCall();
4050 return -1;
4051 }
4052 return FT_ATOMIC_LOAD_SSIZE_RELAXED(((PyDictObject *)mp)->ma_used);
4053 }
4054
4055 /* Return 1 if dicts equal, 0 if not, -1 if error.
4056 * Gets out as soon as any difference is detected.
4057 * Uses only Py_EQ comparison.
4058 */
4059 static int
dict_equal_lock_held(PyDictObject * a,PyDictObject * b)4060 dict_equal_lock_held(PyDictObject *a, PyDictObject *b)
4061 {
4062 Py_ssize_t i;
4063
4064 ASSERT_DICT_LOCKED(a);
4065 ASSERT_DICT_LOCKED(b);
4066
4067 if (a->ma_used != b->ma_used)
4068 /* can't be equal if # of entries differ */
4069 return 0;
4070 /* Same # of entries -- check all of 'em. Exit early on any diff. */
4071 for (i = 0; i < LOAD_KEYS_NENTRIES(a->ma_keys); i++) {
4072 PyObject *key, *aval;
4073 Py_hash_t hash;
4074 if (DK_IS_UNICODE(a->ma_keys)) {
4075 PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(a->ma_keys)[i];
4076 key = ep->me_key;
4077 if (key == NULL) {
4078 continue;
4079 }
4080 hash = unicode_get_hash(key);
4081 if (_PyDict_HasSplitTable(a))
4082 aval = a->ma_values->values[i];
4083 else
4084 aval = ep->me_value;
4085 }
4086 else {
4087 PyDictKeyEntry *ep = &DK_ENTRIES(a->ma_keys)[i];
4088 key = ep->me_key;
4089 aval = ep->me_value;
4090 hash = ep->me_hash;
4091 }
4092 if (aval != NULL) {
4093 int cmp;
4094 PyObject *bval;
4095 /* temporarily bump aval's refcount to ensure it stays
4096 alive until we're done with it */
4097 Py_INCREF(aval);
4098 /* ditto for key */
4099 Py_INCREF(key);
4100 /* reuse the known hash value */
4101 _Py_dict_lookup(b, key, hash, &bval);
4102 if (bval == NULL) {
4103 Py_DECREF(key);
4104 Py_DECREF(aval);
4105 if (PyErr_Occurred())
4106 return -1;
4107 return 0;
4108 }
4109 Py_INCREF(bval);
4110 cmp = PyObject_RichCompareBool(aval, bval, Py_EQ);
4111 Py_DECREF(key);
4112 Py_DECREF(aval);
4113 Py_DECREF(bval);
4114 if (cmp <= 0) /* error or not equal */
4115 return cmp;
4116 }
4117 }
4118 return 1;
4119 }
4120
4121 static int
dict_equal(PyDictObject * a,PyDictObject * b)4122 dict_equal(PyDictObject *a, PyDictObject *b)
4123 {
4124 int res;
4125 Py_BEGIN_CRITICAL_SECTION2(a, b);
4126 res = dict_equal_lock_held(a, b);
4127 Py_END_CRITICAL_SECTION2();
4128
4129 return res;
4130 }
4131
4132 static PyObject *
dict_richcompare(PyObject * v,PyObject * w,int op)4133 dict_richcompare(PyObject *v, PyObject *w, int op)
4134 {
4135 int cmp;
4136 PyObject *res;
4137
4138 if (!PyDict_Check(v) || !PyDict_Check(w)) {
4139 res = Py_NotImplemented;
4140 }
4141 else if (op == Py_EQ || op == Py_NE) {
4142 cmp = dict_equal((PyDictObject *)v, (PyDictObject *)w);
4143 if (cmp < 0)
4144 return NULL;
4145 res = (cmp == (op == Py_EQ)) ? Py_True : Py_False;
4146 }
4147 else
4148 res = Py_NotImplemented;
4149 return Py_NewRef(res);
4150 }
4151
4152 /*[clinic input]
4153
4154 @coexist
4155 dict.__contains__
4156
4157 key: object
4158 /
4159
4160 True if the dictionary has the specified key, else False.
4161 [clinic start generated code]*/
4162
4163 static PyObject *
dict___contains__(PyDictObject * self,PyObject * key)4164 dict___contains__(PyDictObject *self, PyObject *key)
4165 /*[clinic end generated code: output=a3d03db709ed6e6b input=fe1cb42ad831e820]*/
4166 {
4167 int contains = PyDict_Contains((PyObject *)self, key);
4168 if (contains < 0) {
4169 return NULL;
4170 }
4171 if (contains) {
4172 Py_RETURN_TRUE;
4173 }
4174 Py_RETURN_FALSE;
4175 }
4176
4177 /*[clinic input]
4178 @critical_section
4179 dict.get
4180
4181 key: object
4182 default: object = None
4183 /
4184
4185 Return the value for key if key is in the dictionary, else default.
4186 [clinic start generated code]*/
4187
4188 static PyObject *
dict_get_impl(PyDictObject * self,PyObject * key,PyObject * default_value)4189 dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
4190 /*[clinic end generated code: output=bba707729dee05bf input=a631d3f18f584c60]*/
4191 {
4192 PyObject *val = NULL;
4193 Py_hash_t hash;
4194 Py_ssize_t ix;
4195
4196 hash = _PyObject_HashFast(key);
4197 if (hash == -1) {
4198 return NULL;
4199 }
4200 ix = _Py_dict_lookup_threadsafe(self, key, hash, &val);
4201 if (ix == DKIX_ERROR)
4202 return NULL;
4203 if (ix == DKIX_EMPTY || val == NULL) {
4204 val = Py_NewRef(default_value);
4205 }
4206 return val;
4207 }
4208
4209 static int
dict_setdefault_ref_lock_held(PyObject * d,PyObject * key,PyObject * default_value,PyObject ** result,int incref_result)4210 dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_value,
4211 PyObject **result, int incref_result)
4212 {
4213 PyDictObject *mp = (PyDictObject *)d;
4214 PyObject *value;
4215 Py_hash_t hash;
4216 PyInterpreterState *interp = _PyInterpreterState_GET();
4217
4218 ASSERT_DICT_LOCKED(d);
4219
4220 if (!PyDict_Check(d)) {
4221 PyErr_BadInternalCall();
4222 if (result) {
4223 *result = NULL;
4224 }
4225 return -1;
4226 }
4227
4228 hash = _PyObject_HashFast(key);
4229 if (hash == -1) {
4230 if (result) {
4231 *result = NULL;
4232 }
4233 return -1;
4234 }
4235
4236 if (mp->ma_keys == Py_EMPTY_KEYS) {
4237 if (insert_to_emptydict(interp, mp, Py_NewRef(key), hash,
4238 Py_NewRef(default_value)) < 0) {
4239 if (result) {
4240 *result = NULL;
4241 }
4242 return -1;
4243 }
4244 if (result) {
4245 *result = incref_result ? Py_NewRef(default_value) : default_value;
4246 }
4247 return 0;
4248 }
4249
4250 if (!PyUnicode_CheckExact(key) && DK_IS_UNICODE(mp->ma_keys)) {
4251 if (insertion_resize(interp, mp, 0) < 0) {
4252 if (result) {
4253 *result = NULL;
4254 }
4255 return -1;
4256 }
4257 }
4258
4259 if (_PyDict_HasSplitTable(mp)) {
4260 Py_ssize_t ix = insert_split_key(mp->ma_keys, key, hash);
4261 if (ix != DKIX_EMPTY) {
4262 PyObject *value = mp->ma_values->values[ix];
4263 int already_present = value != NULL;
4264 if (!already_present) {
4265 insert_split_value(interp, mp, key, default_value, ix);
4266 value = default_value;
4267 }
4268 if (result) {
4269 *result = incref_result ? Py_NewRef(value) : value;
4270 }
4271 return already_present;
4272 }
4273
4274 /* No space in shared keys. Resize and continue below. */
4275 if (insertion_resize(interp, mp, 1) < 0) {
4276 goto error;
4277 }
4278 }
4279
4280 assert(!_PyDict_HasSplitTable(mp));
4281
4282 Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &value);
4283 if (ix == DKIX_ERROR) {
4284 if (result) {
4285 *result = NULL;
4286 }
4287 return -1;
4288 }
4289
4290 if (ix == DKIX_EMPTY) {
4291 assert(!_PyDict_HasSplitTable(mp));
4292 value = default_value;
4293
4294 if (insert_combined_dict(interp, mp, hash, Py_NewRef(key), Py_NewRef(value)) < 0) {
4295 Py_DECREF(key);
4296 Py_DECREF(value);
4297 if (result) {
4298 *result = NULL;
4299 }
4300 }
4301
4302 MAINTAIN_TRACKING(mp, key, value);
4303 STORE_USED(mp, mp->ma_used + 1);
4304 assert(mp->ma_keys->dk_usable >= 0);
4305 ASSERT_CONSISTENT(mp);
4306 if (result) {
4307 *result = incref_result ? Py_NewRef(value) : value;
4308 }
4309 return 0;
4310 }
4311
4312 assert(value != NULL);
4313 ASSERT_CONSISTENT(mp);
4314 if (result) {
4315 *result = incref_result ? Py_NewRef(value) : value;
4316 }
4317 return 1;
4318
4319 error:
4320 if (result) {
4321 *result = NULL;
4322 }
4323 return -1;
4324 }
4325
4326 int
PyDict_SetDefaultRef(PyObject * d,PyObject * key,PyObject * default_value,PyObject ** result)4327 PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value,
4328 PyObject **result)
4329 {
4330 int res;
4331 Py_BEGIN_CRITICAL_SECTION(d);
4332 res = dict_setdefault_ref_lock_held(d, key, default_value, result, 1);
4333 Py_END_CRITICAL_SECTION();
4334 return res;
4335 }
4336
4337 PyObject *
PyDict_SetDefault(PyObject * d,PyObject * key,PyObject * defaultobj)4338 PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
4339 {
4340 PyObject *result;
4341 Py_BEGIN_CRITICAL_SECTION(d);
4342 dict_setdefault_ref_lock_held(d, key, defaultobj, &result, 0);
4343 Py_END_CRITICAL_SECTION();
4344 return result;
4345 }
4346
4347 /*[clinic input]
4348 @critical_section
4349 dict.setdefault
4350
4351 key: object
4352 default: object = None
4353 /
4354
4355 Insert key with a value of default if key is not in the dictionary.
4356
4357 Return the value for key if key is in the dictionary, else default.
4358 [clinic start generated code]*/
4359
4360 static PyObject *
dict_setdefault_impl(PyDictObject * self,PyObject * key,PyObject * default_value)4361 dict_setdefault_impl(PyDictObject *self, PyObject *key,
4362 PyObject *default_value)
4363 /*[clinic end generated code: output=f8c1101ebf69e220 input=9237af9a0a224302]*/
4364 {
4365 PyObject *val;
4366 dict_setdefault_ref_lock_held((PyObject *)self, key, default_value, &val, 1);
4367 return val;
4368 }
4369
4370
4371 /*[clinic input]
4372 dict.clear
4373
4374 Remove all items from the dict.
4375 [clinic start generated code]*/
4376
4377 static PyObject *
dict_clear_impl(PyDictObject * self)4378 dict_clear_impl(PyDictObject *self)
4379 /*[clinic end generated code: output=5139a830df00830a input=0bf729baba97a4c2]*/
4380 {
4381 PyDict_Clear((PyObject *)self);
4382 Py_RETURN_NONE;
4383 }
4384
4385 /*[clinic input]
4386 dict.pop
4387
4388 key: object
4389 default: object = NULL
4390 /
4391
4392 D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
4393
4394 If the key is not found, return the default if given; otherwise,
4395 raise a KeyError.
4396 [clinic start generated code]*/
4397
4398 static PyObject *
dict_pop_impl(PyDictObject * self,PyObject * key,PyObject * default_value)4399 dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
4400 /*[clinic end generated code: output=3abb47b89f24c21c input=e221baa01044c44c]*/
4401 {
4402 return _PyDict_Pop((PyObject*)self, key, default_value);
4403 }
4404
4405 /*[clinic input]
4406 @critical_section
4407 dict.popitem
4408
4409 Remove and return a (key, value) pair as a 2-tuple.
4410
4411 Pairs are returned in LIFO (last-in, first-out) order.
4412 Raises KeyError if the dict is empty.
4413 [clinic start generated code]*/
4414
4415 static PyObject *
dict_popitem_impl(PyDictObject * self)4416 dict_popitem_impl(PyDictObject *self)
4417 /*[clinic end generated code: output=e65fcb04420d230d input=ef28b4da5f0f762e]*/
4418 {
4419 Py_ssize_t i, j;
4420 PyObject *res;
4421 uint64_t new_version;
4422 PyInterpreterState *interp = _PyInterpreterState_GET();
4423
4424 ASSERT_DICT_LOCKED(self);
4425
4426 /* Allocate the result tuple before checking the size. Believe it
4427 * or not, this allocation could trigger a garbage collection which
4428 * could empty the dict, so if we checked the size first and that
4429 * happened, the result would be an infinite loop (searching for an
4430 * entry that no longer exists). Note that the usual popitem()
4431 * idiom is "while d: k, v = d.popitem()". so needing to throw the
4432 * tuple away if the dict *is* empty isn't a significant
4433 * inefficiency -- possible, but unlikely in practice.
4434 */
4435 res = PyTuple_New(2);
4436 if (res == NULL)
4437 return NULL;
4438 if (self->ma_used == 0) {
4439 Py_DECREF(res);
4440 PyErr_SetString(PyExc_KeyError, "popitem(): dictionary is empty");
4441 return NULL;
4442 }
4443 /* Convert split table to combined table */
4444 if (_PyDict_HasSplitTable(self)) {
4445 if (dictresize(interp, self, DK_LOG_SIZE(self->ma_keys), 1) < 0) {
4446 Py_DECREF(res);
4447 return NULL;
4448 }
4449 }
4450 self->ma_keys->dk_version = 0;
4451
4452 /* Pop last item */
4453 PyObject *key, *value;
4454 Py_hash_t hash;
4455 if (DK_IS_UNICODE(self->ma_keys)) {
4456 PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(self->ma_keys);
4457 i = self->ma_keys->dk_nentries - 1;
4458 while (i >= 0 && ep0[i].me_value == NULL) {
4459 i--;
4460 }
4461 assert(i >= 0);
4462
4463 key = ep0[i].me_key;
4464 new_version = _PyDict_NotifyEvent(
4465 interp, PyDict_EVENT_DELETED, self, key, NULL);
4466 hash = unicode_get_hash(key);
4467 value = ep0[i].me_value;
4468 ep0[i].me_key = NULL;
4469 ep0[i].me_value = NULL;
4470 }
4471 else {
4472 PyDictKeyEntry *ep0 = DK_ENTRIES(self->ma_keys);
4473 i = self->ma_keys->dk_nentries - 1;
4474 while (i >= 0 && ep0[i].me_value == NULL) {
4475 i--;
4476 }
4477 assert(i >= 0);
4478
4479 key = ep0[i].me_key;
4480 new_version = _PyDict_NotifyEvent(
4481 interp, PyDict_EVENT_DELETED, self, key, NULL);
4482 hash = ep0[i].me_hash;
4483 value = ep0[i].me_value;
4484 ep0[i].me_key = NULL;
4485 ep0[i].me_hash = -1;
4486 ep0[i].me_value = NULL;
4487 }
4488
4489 j = lookdict_index(self->ma_keys, hash, i);
4490 assert(j >= 0);
4491 assert(dictkeys_get_index(self->ma_keys, j) == i);
4492 dictkeys_set_index(self->ma_keys, j, DKIX_DUMMY);
4493
4494 PyTuple_SET_ITEM(res, 0, key);
4495 PyTuple_SET_ITEM(res, 1, value);
4496 /* We can't dk_usable++ since there is DKIX_DUMMY in indices */
4497 STORE_KEYS_NENTRIES(self->ma_keys, i);
4498 STORE_USED(self, self->ma_used - 1);
4499 self->ma_version_tag = new_version;
4500 ASSERT_CONSISTENT(self);
4501 return res;
4502 }
4503
4504 static int
dict_traverse(PyObject * op,visitproc visit,void * arg)4505 dict_traverse(PyObject *op, visitproc visit, void *arg)
4506 {
4507 PyDictObject *mp = (PyDictObject *)op;
4508 PyDictKeysObject *keys = mp->ma_keys;
4509 Py_ssize_t i, n = keys->dk_nentries;
4510
4511 if (DK_IS_UNICODE(keys)) {
4512 if (_PyDict_HasSplitTable(mp)) {
4513 if (!mp->ma_values->embedded) {
4514 for (i = 0; i < n; i++) {
4515 Py_VISIT(mp->ma_values->values[i]);
4516 }
4517 }
4518 }
4519 else {
4520 PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
4521 for (i = 0; i < n; i++) {
4522 Py_VISIT(entries[i].me_value);
4523 }
4524 }
4525 }
4526 else {
4527 PyDictKeyEntry *entries = DK_ENTRIES(keys);
4528 for (i = 0; i < n; i++) {
4529 if (entries[i].me_value != NULL) {
4530 Py_VISIT(entries[i].me_value);
4531 Py_VISIT(entries[i].me_key);
4532 }
4533 }
4534 }
4535 return 0;
4536 }
4537
4538 static int
dict_tp_clear(PyObject * op)4539 dict_tp_clear(PyObject *op)
4540 {
4541 PyDict_Clear(op);
4542 return 0;
4543 }
4544
4545 static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
4546
4547 static Py_ssize_t
sizeof_lock_held(PyDictObject * mp)4548 sizeof_lock_held(PyDictObject *mp)
4549 {
4550 size_t res = _PyObject_SIZE(Py_TYPE(mp));
4551 if (_PyDict_HasSplitTable(mp)) {
4552 res += shared_keys_usable_size(mp->ma_keys) * sizeof(PyObject*);
4553 }
4554 /* If the dictionary is split, the keys portion is accounted-for
4555 in the type object. */
4556 if (mp->ma_keys->dk_refcnt == 1) {
4557 res += _PyDict_KeysSize(mp->ma_keys);
4558 }
4559 assert(res <= (size_t)PY_SSIZE_T_MAX);
4560 return (Py_ssize_t)res;
4561 }
4562
4563 Py_ssize_t
_PyDict_SizeOf(PyDictObject * mp)4564 _PyDict_SizeOf(PyDictObject *mp)
4565 {
4566 Py_ssize_t res;
4567 Py_BEGIN_CRITICAL_SECTION(mp);
4568 res = sizeof_lock_held(mp);
4569 Py_END_CRITICAL_SECTION();
4570
4571 return res;
4572 }
4573
4574 size_t
_PyDict_KeysSize(PyDictKeysObject * keys)4575 _PyDict_KeysSize(PyDictKeysObject *keys)
4576 {
4577 size_t es = (keys->dk_kind == DICT_KEYS_GENERAL
4578 ? sizeof(PyDictKeyEntry) : sizeof(PyDictUnicodeEntry));
4579 size_t size = sizeof(PyDictKeysObject);
4580 size += (size_t)1 << keys->dk_log2_index_bytes;
4581 size += USABLE_FRACTION((size_t)DK_SIZE(keys)) * es;
4582 return size;
4583 }
4584
4585 /*[clinic input]
4586 dict.__sizeof__
4587
4588 Return the size of the dict in memory, in bytes.
4589 [clinic start generated code]*/
4590
4591 static PyObject *
dict___sizeof___impl(PyDictObject * self)4592 dict___sizeof___impl(PyDictObject *self)
4593 /*[clinic end generated code: output=44279379b3824bda input=4fec4ddfc44a4d1a]*/
4594 {
4595 return PyLong_FromSsize_t(_PyDict_SizeOf(self));
4596 }
4597
4598 static PyObject *
dict_or(PyObject * self,PyObject * other)4599 dict_or(PyObject *self, PyObject *other)
4600 {
4601 if (!PyDict_Check(self) || !PyDict_Check(other)) {
4602 Py_RETURN_NOTIMPLEMENTED;
4603 }
4604 PyObject *new = PyDict_Copy(self);
4605 if (new == NULL) {
4606 return NULL;
4607 }
4608 if (dict_update_arg(new, other)) {
4609 Py_DECREF(new);
4610 return NULL;
4611 }
4612 return new;
4613 }
4614
4615 static PyObject *
dict_ior(PyObject * self,PyObject * other)4616 dict_ior(PyObject *self, PyObject *other)
4617 {
4618 if (dict_update_arg(self, other)) {
4619 return NULL;
4620 }
4621 return Py_NewRef(self);
4622 }
4623
4624 PyDoc_STRVAR(getitem__doc__,
4625 "__getitem__($self, key, /)\n--\n\nReturn self[key].");
4626
4627 PyDoc_STRVAR(update__doc__,
4628 "D.update([E, ]**F) -> None. Update D from mapping/iterable E and F.\n\
4629 If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k]\n\
4630 If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v\n\
4631 In either case, this is followed by: for k in F: D[k] = F[k]");
4632
4633 /* Forward */
4634
4635 static PyMethodDef mapp_methods[] = {
4636 DICT___CONTAINS___METHODDEF
4637 {"__getitem__", dict_subscript, METH_O | METH_COEXIST,
4638 getitem__doc__},
4639 DICT___SIZEOF___METHODDEF
4640 DICT_GET_METHODDEF
4641 DICT_SETDEFAULT_METHODDEF
4642 DICT_POP_METHODDEF
4643 DICT_POPITEM_METHODDEF
4644 DICT_KEYS_METHODDEF
4645 DICT_ITEMS_METHODDEF
4646 DICT_VALUES_METHODDEF
4647 {"update", _PyCFunction_CAST(dict_update), METH_VARARGS | METH_KEYWORDS,
4648 update__doc__},
4649 DICT_FROMKEYS_METHODDEF
4650 DICT_CLEAR_METHODDEF
4651 DICT_COPY_METHODDEF
4652 DICT___REVERSED___METHODDEF
4653 {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
4654 {NULL, NULL} /* sentinel */
4655 };
4656
4657 /* Return 1 if `key` is in dict `op`, 0 if not, and -1 on error. */
4658 int
PyDict_Contains(PyObject * op,PyObject * key)4659 PyDict_Contains(PyObject *op, PyObject *key)
4660 {
4661 Py_hash_t hash = _PyObject_HashFast(key);
4662
4663 if (hash == -1) {
4664 return -1;
4665 }
4666
4667 return _PyDict_Contains_KnownHash(op, key, hash);
4668 }
4669
4670 int
PyDict_ContainsString(PyObject * op,const char * key)4671 PyDict_ContainsString(PyObject *op, const char *key)
4672 {
4673 PyObject *key_obj = PyUnicode_FromString(key);
4674 if (key_obj == NULL) {
4675 return -1;
4676 }
4677 int res = PyDict_Contains(op, key_obj);
4678 Py_DECREF(key_obj);
4679 return res;
4680 }
4681
4682 /* Internal version of PyDict_Contains used when the hash value is already known */
4683 int
_PyDict_Contains_KnownHash(PyObject * op,PyObject * key,Py_hash_t hash)4684 _PyDict_Contains_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
4685 {
4686 PyDictObject *mp = (PyDictObject *)op;
4687 PyObject *value;
4688 Py_ssize_t ix;
4689
4690 #ifdef Py_GIL_DISABLED
4691 ix = _Py_dict_lookup_threadsafe(mp, key, hash, &value);
4692 #else
4693 ix = _Py_dict_lookup(mp, key, hash, &value);
4694 #endif
4695 if (ix == DKIX_ERROR)
4696 return -1;
4697 if (ix != DKIX_EMPTY && value != NULL) {
4698 #ifdef Py_GIL_DISABLED
4699 Py_DECREF(value);
4700 #endif
4701 return 1;
4702 }
4703 return 0;
4704 }
4705
4706 int
_PyDict_ContainsId(PyObject * op,_Py_Identifier * key)4707 _PyDict_ContainsId(PyObject *op, _Py_Identifier *key)
4708 {
4709 PyObject *kv = _PyUnicode_FromId(key); /* borrowed */
4710 if (kv == NULL) {
4711 return -1;
4712 }
4713 return PyDict_Contains(op, kv);
4714 }
4715
4716 /* Hack to implement "key in dict" */
4717 static PySequenceMethods dict_as_sequence = {
4718 0, /* sq_length */
4719 0, /* sq_concat */
4720 0, /* sq_repeat */
4721 0, /* sq_item */
4722 0, /* sq_slice */
4723 0, /* sq_ass_item */
4724 0, /* sq_ass_slice */
4725 PyDict_Contains, /* sq_contains */
4726 0, /* sq_inplace_concat */
4727 0, /* sq_inplace_repeat */
4728 };
4729
4730 static PyNumberMethods dict_as_number = {
4731 .nb_or = dict_or,
4732 .nb_inplace_or = dict_ior,
4733 };
4734
4735 static PyObject *
dict_new(PyTypeObject * type,PyObject * args,PyObject * kwds)4736 dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
4737 {
4738 assert(type != NULL);
4739 assert(type->tp_alloc != NULL);
4740 // dict subclasses must implement the GC protocol
4741 assert(_PyType_IS_GC(type));
4742
4743 PyObject *self = type->tp_alloc(type, 0);
4744 if (self == NULL) {
4745 return NULL;
4746 }
4747 PyDictObject *d = (PyDictObject *)self;
4748
4749 d->ma_used = 0;
4750 d->ma_version_tag = DICT_NEXT_VERSION(
4751 _PyInterpreterState_GET());
4752 dictkeys_incref(Py_EMPTY_KEYS);
4753 d->ma_keys = Py_EMPTY_KEYS;
4754 d->ma_values = NULL;
4755 ASSERT_CONSISTENT(d);
4756
4757 if (type != &PyDict_Type) {
4758 // Don't track if a subclass tp_alloc is PyType_GenericAlloc()
4759 if (!_PyObject_GC_IS_TRACKED(d)) {
4760 _PyObject_GC_TRACK(d);
4761 }
4762 }
4763 else {
4764 // _PyType_AllocNoTrack() does not track the created object
4765 assert(!_PyObject_GC_IS_TRACKED(d));
4766 }
4767 return self;
4768 }
4769
4770 static int
dict_init(PyObject * self,PyObject * args,PyObject * kwds)4771 dict_init(PyObject *self, PyObject *args, PyObject *kwds)
4772 {
4773 return dict_update_common(self, args, kwds, "dict");
4774 }
4775
4776 static PyObject *
dict_vectorcall(PyObject * type,PyObject * const * args,size_t nargsf,PyObject * kwnames)4777 dict_vectorcall(PyObject *type, PyObject * const*args,
4778 size_t nargsf, PyObject *kwnames)
4779 {
4780 Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
4781 if (!_PyArg_CheckPositional("dict", nargs, 0, 1)) {
4782 return NULL;
4783 }
4784
4785 PyObject *self = dict_new(_PyType_CAST(type), NULL, NULL);
4786 if (self == NULL) {
4787 return NULL;
4788 }
4789 if (nargs == 1) {
4790 if (dict_update_arg(self, args[0]) < 0) {
4791 Py_DECREF(self);
4792 return NULL;
4793 }
4794 args++;
4795 }
4796 if (kwnames != NULL) {
4797 for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(kwnames); i++) {
4798 if (PyDict_SetItem(self, PyTuple_GET_ITEM(kwnames, i), args[i]) < 0) {
4799 Py_DECREF(self);
4800 return NULL;
4801 }
4802 }
4803 }
4804 return self;
4805 }
4806
4807 static PyObject *
dict_iter(PyObject * self)4808 dict_iter(PyObject *self)
4809 {
4810 PyDictObject *dict = (PyDictObject *)self;
4811 return dictiter_new(dict, &PyDictIterKey_Type);
4812 }
4813
4814 PyDoc_STRVAR(dictionary_doc,
4815 "dict() -> new empty dictionary\n"
4816 "dict(mapping) -> new dictionary initialized from a mapping object's\n"
4817 " (key, value) pairs\n"
4818 "dict(iterable) -> new dictionary initialized as if via:\n"
4819 " d = {}\n"
4820 " for k, v in iterable:\n"
4821 " d[k] = v\n"
4822 "dict(**kwargs) -> new dictionary initialized with the name=value pairs\n"
4823 " in the keyword argument list. For example: dict(one=1, two=2)");
4824
4825 PyTypeObject PyDict_Type = {
4826 PyVarObject_HEAD_INIT(&PyType_Type, 0)
4827 "dict",
4828 sizeof(PyDictObject),
4829 0,
4830 dict_dealloc, /* tp_dealloc */
4831 0, /* tp_vectorcall_offset */
4832 0, /* tp_getattr */
4833 0, /* tp_setattr */
4834 0, /* tp_as_async */
4835 dict_repr, /* tp_repr */
4836 &dict_as_number, /* tp_as_number */
4837 &dict_as_sequence, /* tp_as_sequence */
4838 &dict_as_mapping, /* tp_as_mapping */
4839 PyObject_HashNotImplemented, /* tp_hash */
4840 0, /* tp_call */
4841 0, /* tp_str */
4842 PyObject_GenericGetAttr, /* tp_getattro */
4843 0, /* tp_setattro */
4844 0, /* tp_as_buffer */
4845 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
4846 Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DICT_SUBCLASS |
4847 _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_MAPPING, /* tp_flags */
4848 dictionary_doc, /* tp_doc */
4849 dict_traverse, /* tp_traverse */
4850 dict_tp_clear, /* tp_clear */
4851 dict_richcompare, /* tp_richcompare */
4852 0, /* tp_weaklistoffset */
4853 dict_iter, /* tp_iter */
4854 0, /* tp_iternext */
4855 mapp_methods, /* tp_methods */
4856 0, /* tp_members */
4857 0, /* tp_getset */
4858 0, /* tp_base */
4859 0, /* tp_dict */
4860 0, /* tp_descr_get */
4861 0, /* tp_descr_set */
4862 0, /* tp_dictoffset */
4863 dict_init, /* tp_init */
4864 _PyType_AllocNoTrack, /* tp_alloc */
4865 dict_new, /* tp_new */
4866 PyObject_GC_Del, /* tp_free */
4867 .tp_vectorcall = dict_vectorcall,
4868 };
4869
4870 /* For backward compatibility with old dictionary interface */
4871
4872 PyObject *
PyDict_GetItemString(PyObject * v,const char * key)4873 PyDict_GetItemString(PyObject *v, const char *key)
4874 {
4875 PyObject *kv, *rv;
4876 kv = PyUnicode_FromString(key);
4877 if (kv == NULL) {
4878 PyErr_FormatUnraisable(
4879 "Exception ignored in PyDict_GetItemString(); consider using "
4880 "PyDict_GetItemRefString()");
4881 return NULL;
4882 }
4883 rv = dict_getitem(v, kv,
4884 "Exception ignored in PyDict_GetItemString(); consider using "
4885 "PyDict_GetItemRefString()");
4886 Py_DECREF(kv);
4887 return rv; // borrowed reference
4888 }
4889
4890 int
PyDict_GetItemStringRef(PyObject * v,const char * key,PyObject ** result)4891 PyDict_GetItemStringRef(PyObject *v, const char *key, PyObject **result)
4892 {
4893 PyObject *key_obj = PyUnicode_FromString(key);
4894 if (key_obj == NULL) {
4895 *result = NULL;
4896 return -1;
4897 }
4898 int res = PyDict_GetItemRef(v, key_obj, result);
4899 Py_DECREF(key_obj);
4900 return res;
4901 }
4902
4903 int
_PyDict_SetItemId(PyObject * v,_Py_Identifier * key,PyObject * item)4904 _PyDict_SetItemId(PyObject *v, _Py_Identifier *key, PyObject *item)
4905 {
4906 PyObject *kv;
4907 kv = _PyUnicode_FromId(key); /* borrowed */
4908 if (kv == NULL)
4909 return -1;
4910 return PyDict_SetItem(v, kv, item);
4911 }
4912
4913 int
PyDict_SetItemString(PyObject * v,const char * key,PyObject * item)4914 PyDict_SetItemString(PyObject *v, const char *key, PyObject *item)
4915 {
4916 PyObject *kv;
4917 int err;
4918 kv = PyUnicode_FromString(key);
4919 if (kv == NULL)
4920 return -1;
4921 PyInterpreterState *interp = _PyInterpreterState_GET();
4922 _PyUnicode_InternImmortal(interp, &kv); /* XXX Should we really? */
4923 err = PyDict_SetItem(v, kv, item);
4924 Py_DECREF(kv);
4925 return err;
4926 }
4927
4928 int
_PyDict_DelItemId(PyObject * v,_Py_Identifier * key)4929 _PyDict_DelItemId(PyObject *v, _Py_Identifier *key)
4930 {
4931 PyObject *kv = _PyUnicode_FromId(key); /* borrowed */
4932 if (kv == NULL)
4933 return -1;
4934 return PyDict_DelItem(v, kv);
4935 }
4936
4937 int
PyDict_DelItemString(PyObject * v,const char * key)4938 PyDict_DelItemString(PyObject *v, const char *key)
4939 {
4940 PyObject *kv;
4941 int err;
4942 kv = PyUnicode_FromString(key);
4943 if (kv == NULL)
4944 return -1;
4945 err = PyDict_DelItem(v, kv);
4946 Py_DECREF(kv);
4947 return err;
4948 }
4949
4950 /* Dictionary iterator types */
4951
4952 typedef struct {
4953 PyObject_HEAD
4954 PyDictObject *di_dict; /* Set to NULL when iterator is exhausted */
4955 Py_ssize_t di_used;
4956 Py_ssize_t di_pos;
4957 PyObject* di_result; /* reusable result tuple for iteritems */
4958 Py_ssize_t len;
4959 } dictiterobject;
4960
4961 static PyObject *
dictiter_new(PyDictObject * dict,PyTypeObject * itertype)4962 dictiter_new(PyDictObject *dict, PyTypeObject *itertype)
4963 {
4964 Py_ssize_t used;
4965 dictiterobject *di;
4966 di = PyObject_GC_New(dictiterobject, itertype);
4967 if (di == NULL) {
4968 return NULL;
4969 }
4970 di->di_dict = (PyDictObject*)Py_NewRef(dict);
4971 used = FT_ATOMIC_LOAD_SSIZE_RELAXED(dict->ma_used);
4972 di->di_used = used;
4973 di->len = used;
4974 if (itertype == &PyDictRevIterKey_Type ||
4975 itertype == &PyDictRevIterItem_Type ||
4976 itertype == &PyDictRevIterValue_Type) {
4977 if (_PyDict_HasSplitTable(dict)) {
4978 di->di_pos = used - 1;
4979 }
4980 else {
4981 di->di_pos = load_keys_nentries(dict) - 1;
4982 }
4983 }
4984 else {
4985 di->di_pos = 0;
4986 }
4987 if (itertype == &PyDictIterItem_Type ||
4988 itertype == &PyDictRevIterItem_Type) {
4989 di->di_result = PyTuple_Pack(2, Py_None, Py_None);
4990 if (di->di_result == NULL) {
4991 Py_DECREF(di);
4992 return NULL;
4993 }
4994 }
4995 else {
4996 di->di_result = NULL;
4997 }
4998 _PyObject_GC_TRACK(di);
4999 return (PyObject *)di;
5000 }
5001
5002 static void
dictiter_dealloc(PyObject * self)5003 dictiter_dealloc(PyObject *self)
5004 {
5005 dictiterobject *di = (dictiterobject *)self;
5006 /* bpo-31095: UnTrack is needed before calling any callbacks */
5007 _PyObject_GC_UNTRACK(di);
5008 Py_XDECREF(di->di_dict);
5009 Py_XDECREF(di->di_result);
5010 PyObject_GC_Del(di);
5011 }
5012
5013 static int
dictiter_traverse(PyObject * self,visitproc visit,void * arg)5014 dictiter_traverse(PyObject *self, visitproc visit, void *arg)
5015 {
5016 dictiterobject *di = (dictiterobject *)self;
5017 Py_VISIT(di->di_dict);
5018 Py_VISIT(di->di_result);
5019 return 0;
5020 }
5021
5022 static PyObject *
dictiter_len(PyObject * self,PyObject * Py_UNUSED (ignored))5023 dictiter_len(PyObject *self, PyObject *Py_UNUSED(ignored))
5024 {
5025 dictiterobject *di = (dictiterobject *)self;
5026 Py_ssize_t len = 0;
5027 if (di->di_dict != NULL && di->di_used == FT_ATOMIC_LOAD_SSIZE_RELAXED(di->di_dict->ma_used))
5028 len = FT_ATOMIC_LOAD_SSIZE_RELAXED(di->len);
5029 return PyLong_FromSize_t(len);
5030 }
5031
5032 PyDoc_STRVAR(length_hint_doc,
5033 "Private method returning an estimate of len(list(it)).");
5034
5035 static PyObject *
5036 dictiter_reduce(PyObject *di, PyObject *Py_UNUSED(ignored));
5037
5038 PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
5039
5040 static PyMethodDef dictiter_methods[] = {
5041 {"__length_hint__", dictiter_len, METH_NOARGS,
5042 length_hint_doc},
5043 {"__reduce__", dictiter_reduce, METH_NOARGS,
5044 reduce_doc},
5045 {NULL, NULL} /* sentinel */
5046 };
5047
5048 #ifdef Py_GIL_DISABLED
5049
5050 static int
5051 dictiter_iternext_threadsafe(PyDictObject *d, PyObject *self,
5052 PyObject **out_key, PyObject **out_value);
5053
5054 #else /* Py_GIL_DISABLED */
5055
5056 static PyObject*
dictiter_iternextkey_lock_held(PyDictObject * d,PyObject * self)5057 dictiter_iternextkey_lock_held(PyDictObject *d, PyObject *self)
5058 {
5059 dictiterobject *di = (dictiterobject *)self;
5060 PyObject *key;
5061 Py_ssize_t i;
5062 PyDictKeysObject *k;
5063
5064 assert (PyDict_Check(d));
5065 ASSERT_DICT_LOCKED(d);
5066
5067 if (di->di_used != d->ma_used) {
5068 PyErr_SetString(PyExc_RuntimeError,
5069 "dictionary changed size during iteration");
5070 di->di_used = -1; /* Make this state sticky */
5071 return NULL;
5072 }
5073
5074 i = di->di_pos;
5075 k = d->ma_keys;
5076 assert(i >= 0);
5077 if (_PyDict_HasSplitTable(d)) {
5078 if (i >= d->ma_used)
5079 goto fail;
5080 int index = get_index_from_order(d, i);
5081 key = LOAD_SHARED_KEY(DK_UNICODE_ENTRIES(k)[index].me_key);
5082 assert(d->ma_values->values[index] != NULL);
5083 }
5084 else {
5085 Py_ssize_t n = k->dk_nentries;
5086 if (DK_IS_UNICODE(k)) {
5087 PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
5088 while (i < n && entry_ptr->me_value == NULL) {
5089 entry_ptr++;
5090 i++;
5091 }
5092 if (i >= n)
5093 goto fail;
5094 key = entry_ptr->me_key;
5095 }
5096 else {
5097 PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
5098 while (i < n && entry_ptr->me_value == NULL) {
5099 entry_ptr++;
5100 i++;
5101 }
5102 if (i >= n)
5103 goto fail;
5104 key = entry_ptr->me_key;
5105 }
5106 }
5107 // We found an element (key), but did not expect it
5108 if (di->len == 0) {
5109 PyErr_SetString(PyExc_RuntimeError,
5110 "dictionary keys changed during iteration");
5111 goto fail;
5112 }
5113 di->di_pos = i+1;
5114 di->len--;
5115 return Py_NewRef(key);
5116
5117 fail:
5118 di->di_dict = NULL;
5119 Py_DECREF(d);
5120 return NULL;
5121 }
5122
5123 #endif /* Py_GIL_DISABLED */
5124
5125 static PyObject*
dictiter_iternextkey(PyObject * self)5126 dictiter_iternextkey(PyObject *self)
5127 {
5128 dictiterobject *di = (dictiterobject *)self;
5129 PyDictObject *d = di->di_dict;
5130
5131 if (d == NULL)
5132 return NULL;
5133
5134 PyObject *value;
5135 #ifdef Py_GIL_DISABLED
5136 if (dictiter_iternext_threadsafe(d, self, &value, NULL) < 0) {
5137 value = NULL;
5138 }
5139 #else
5140 value = dictiter_iternextkey_lock_held(d, self);
5141 #endif
5142
5143 return value;
5144 }
5145
5146 PyTypeObject PyDictIterKey_Type = {
5147 PyVarObject_HEAD_INIT(&PyType_Type, 0)
5148 "dict_keyiterator", /* tp_name */
5149 sizeof(dictiterobject), /* tp_basicsize */
5150 0, /* tp_itemsize */
5151 /* methods */
5152 dictiter_dealloc, /* tp_dealloc */
5153 0, /* tp_vectorcall_offset */
5154 0, /* tp_getattr */
5155 0, /* tp_setattr */
5156 0, /* tp_as_async */
5157 0, /* tp_repr */
5158 0, /* tp_as_number */
5159 0, /* tp_as_sequence */
5160 0, /* tp_as_mapping */
5161 0, /* tp_hash */
5162 0, /* tp_call */
5163 0, /* tp_str */
5164 PyObject_GenericGetAttr, /* tp_getattro */
5165 0, /* tp_setattro */
5166 0, /* tp_as_buffer */
5167 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
5168 0, /* tp_doc */
5169 dictiter_traverse, /* tp_traverse */
5170 0, /* tp_clear */
5171 0, /* tp_richcompare */
5172 0, /* tp_weaklistoffset */
5173 PyObject_SelfIter, /* tp_iter */
5174 dictiter_iternextkey, /* tp_iternext */
5175 dictiter_methods, /* tp_methods */
5176 0,
5177 };
5178
5179 #ifndef Py_GIL_DISABLED
5180
5181 static PyObject *
dictiter_iternextvalue_lock_held(PyDictObject * d,PyObject * self)5182 dictiter_iternextvalue_lock_held(PyDictObject *d, PyObject *self)
5183 {
5184 dictiterobject *di = (dictiterobject *)self;
5185 PyObject *value;
5186 Py_ssize_t i;
5187
5188 assert (PyDict_Check(d));
5189 ASSERT_DICT_LOCKED(d);
5190
5191 if (di->di_used != d->ma_used) {
5192 PyErr_SetString(PyExc_RuntimeError,
5193 "dictionary changed size during iteration");
5194 di->di_used = -1; /* Make this state sticky */
5195 return NULL;
5196 }
5197
5198 i = di->di_pos;
5199 assert(i >= 0);
5200 if (_PyDict_HasSplitTable(d)) {
5201 if (i >= d->ma_used)
5202 goto fail;
5203 int index = get_index_from_order(d, i);
5204 value = d->ma_values->values[index];
5205 assert(value != NULL);
5206 }
5207 else {
5208 Py_ssize_t n = d->ma_keys->dk_nentries;
5209 if (DK_IS_UNICODE(d->ma_keys)) {
5210 PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(d->ma_keys)[i];
5211 while (i < n && entry_ptr->me_value == NULL) {
5212 entry_ptr++;
5213 i++;
5214 }
5215 if (i >= n)
5216 goto fail;
5217 value = entry_ptr->me_value;
5218 }
5219 else {
5220 PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i];
5221 while (i < n && entry_ptr->me_value == NULL) {
5222 entry_ptr++;
5223 i++;
5224 }
5225 if (i >= n)
5226 goto fail;
5227 value = entry_ptr->me_value;
5228 }
5229 }
5230 // We found an element, but did not expect it
5231 if (di->len == 0) {
5232 PyErr_SetString(PyExc_RuntimeError,
5233 "dictionary keys changed during iteration");
5234 goto fail;
5235 }
5236 di->di_pos = i+1;
5237 di->len--;
5238 return Py_NewRef(value);
5239
5240 fail:
5241 di->di_dict = NULL;
5242 Py_DECREF(d);
5243 return NULL;
5244 }
5245
5246 #endif /* Py_GIL_DISABLED */
5247
5248 static PyObject *
dictiter_iternextvalue(PyObject * self)5249 dictiter_iternextvalue(PyObject *self)
5250 {
5251 dictiterobject *di = (dictiterobject *)self;
5252 PyDictObject *d = di->di_dict;
5253
5254 if (d == NULL)
5255 return NULL;
5256
5257 PyObject *value;
5258 #ifdef Py_GIL_DISABLED
5259 if (dictiter_iternext_threadsafe(d, self, NULL, &value) < 0) {
5260 value = NULL;
5261 }
5262 #else
5263 value = dictiter_iternextvalue_lock_held(d, self);
5264 #endif
5265
5266 return value;
5267 }
5268
5269 PyTypeObject PyDictIterValue_Type = {
5270 PyVarObject_HEAD_INIT(&PyType_Type, 0)
5271 "dict_valueiterator", /* tp_name */
5272 sizeof(dictiterobject), /* tp_basicsize */
5273 0, /* tp_itemsize */
5274 /* methods */
5275 dictiter_dealloc, /* tp_dealloc */
5276 0, /* tp_vectorcall_offset */
5277 0, /* tp_getattr */
5278 0, /* tp_setattr */
5279 0, /* tp_as_async */
5280 0, /* tp_repr */
5281 0, /* tp_as_number */
5282 0, /* tp_as_sequence */
5283 0, /* tp_as_mapping */
5284 0, /* tp_hash */
5285 0, /* tp_call */
5286 0, /* tp_str */
5287 PyObject_GenericGetAttr, /* tp_getattro */
5288 0, /* tp_setattro */
5289 0, /* tp_as_buffer */
5290 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
5291 0, /* tp_doc */
5292 dictiter_traverse, /* tp_traverse */
5293 0, /* tp_clear */
5294 0, /* tp_richcompare */
5295 0, /* tp_weaklistoffset */
5296 PyObject_SelfIter, /* tp_iter */
5297 dictiter_iternextvalue, /* tp_iternext */
5298 dictiter_methods, /* tp_methods */
5299 0,
5300 };
5301
5302 static int
dictiter_iternextitem_lock_held(PyDictObject * d,PyObject * self,PyObject ** out_key,PyObject ** out_value)5303 dictiter_iternextitem_lock_held(PyDictObject *d, PyObject *self,
5304 PyObject **out_key, PyObject **out_value)
5305 {
5306 dictiterobject *di = (dictiterobject *)self;
5307 PyObject *key, *value;
5308 Py_ssize_t i;
5309
5310 assert (PyDict_Check(d));
5311 ASSERT_DICT_LOCKED(d);
5312
5313 if (di->di_used != d->ma_used) {
5314 PyErr_SetString(PyExc_RuntimeError,
5315 "dictionary changed size during iteration");
5316 di->di_used = -1; /* Make this state sticky */
5317 return -1;
5318 }
5319
5320 i = FT_ATOMIC_LOAD_SSIZE_RELAXED(di->di_pos);
5321
5322 assert(i >= 0);
5323 if (_PyDict_HasSplitTable(d)) {
5324 if (i >= d->ma_used)
5325 goto fail;
5326 int index = get_index_from_order(d, i);
5327 key = LOAD_SHARED_KEY(DK_UNICODE_ENTRIES(d->ma_keys)[index].me_key);
5328 value = d->ma_values->values[index];
5329 assert(value != NULL);
5330 }
5331 else {
5332 Py_ssize_t n = d->ma_keys->dk_nentries;
5333 if (DK_IS_UNICODE(d->ma_keys)) {
5334 PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(d->ma_keys)[i];
5335 while (i < n && entry_ptr->me_value == NULL) {
5336 entry_ptr++;
5337 i++;
5338 }
5339 if (i >= n)
5340 goto fail;
5341 key = entry_ptr->me_key;
5342 value = entry_ptr->me_value;
5343 }
5344 else {
5345 PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i];
5346 while (i < n && entry_ptr->me_value == NULL) {
5347 entry_ptr++;
5348 i++;
5349 }
5350 if (i >= n)
5351 goto fail;
5352 key = entry_ptr->me_key;
5353 value = entry_ptr->me_value;
5354 }
5355 }
5356 // We found an element, but did not expect it
5357 if (di->len == 0) {
5358 PyErr_SetString(PyExc_RuntimeError,
5359 "dictionary keys changed during iteration");
5360 goto fail;
5361 }
5362 di->di_pos = i+1;
5363 di->len--;
5364 if (out_key != NULL) {
5365 *out_key = Py_NewRef(key);
5366 }
5367 if (out_value != NULL) {
5368 *out_value = Py_NewRef(value);
5369 }
5370 return 0;
5371
5372 fail:
5373 di->di_dict = NULL;
5374 Py_DECREF(d);
5375 return -1;
5376 }
5377
5378 #ifdef Py_GIL_DISABLED
5379
5380 // Grabs the key and/or value from the provided locations and if successful
5381 // returns them with an increased reference count. If either one is unsucessful
5382 // nothing is incref'd and returns -1.
5383 static int
acquire_key_value(PyObject ** key_loc,PyObject * value,PyObject ** value_loc,PyObject ** out_key,PyObject ** out_value)5384 acquire_key_value(PyObject **key_loc, PyObject *value, PyObject **value_loc,
5385 PyObject **out_key, PyObject **out_value)
5386 {
5387 if (out_key) {
5388 *out_key = _Py_TryXGetRef(key_loc);
5389 if (*out_key == NULL) {
5390 return -1;
5391 }
5392 }
5393
5394 if (out_value) {
5395 if (!_Py_TryIncrefCompare(value_loc, value)) {
5396 if (out_key) {
5397 Py_DECREF(*out_key);
5398 }
5399 return -1;
5400 }
5401 *out_value = value;
5402 }
5403
5404 return 0;
5405 }
5406
5407 static int
dictiter_iternext_threadsafe(PyDictObject * d,PyObject * self,PyObject ** out_key,PyObject ** out_value)5408 dictiter_iternext_threadsafe(PyDictObject *d, PyObject *self,
5409 PyObject **out_key, PyObject **out_value)
5410 {
5411 int res;
5412 dictiterobject *di = (dictiterobject *)self;
5413 Py_ssize_t i;
5414 PyDictKeysObject *k;
5415
5416 assert (PyDict_Check(d));
5417
5418 if (di->di_used != _Py_atomic_load_ssize_relaxed(&d->ma_used)) {
5419 PyErr_SetString(PyExc_RuntimeError,
5420 "dictionary changed size during iteration");
5421 di->di_used = -1; /* Make this state sticky */
5422 return -1;
5423 }
5424
5425 ensure_shared_on_read(d);
5426
5427 i = _Py_atomic_load_ssize_relaxed(&di->di_pos);
5428 k = _Py_atomic_load_ptr_relaxed(&d->ma_keys);
5429 assert(i >= 0);
5430 if (_PyDict_HasSplitTable(d)) {
5431 PyDictValues *values = _Py_atomic_load_ptr_relaxed(&d->ma_values);
5432 if (values == NULL) {
5433 goto concurrent_modification;
5434 }
5435
5436 Py_ssize_t used = (Py_ssize_t)_Py_atomic_load_uint8(&values->size);
5437 if (i >= used) {
5438 goto fail;
5439 }
5440
5441 // We're racing against writes to the order from delete_index_from_values, but
5442 // single threaded can suffer from concurrent modification to those as well and
5443 // can have either duplicated or skipped attributes, so we strive to do no better
5444 // here.
5445 int index = get_index_from_order(d, i);
5446 PyObject *value = _Py_atomic_load_ptr(&values->values[index]);
5447 if (acquire_key_value(&DK_UNICODE_ENTRIES(k)[index].me_key, value,
5448 &values->values[index], out_key, out_value) < 0) {
5449 goto try_locked;
5450 }
5451 }
5452 else {
5453 Py_ssize_t n = _Py_atomic_load_ssize_relaxed(&k->dk_nentries);
5454 if (DK_IS_UNICODE(k)) {
5455 PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
5456 PyObject *value;
5457 while (i < n &&
5458 (value = _Py_atomic_load_ptr(&entry_ptr->me_value)) == NULL) {
5459 entry_ptr++;
5460 i++;
5461 }
5462 if (i >= n)
5463 goto fail;
5464
5465 if (acquire_key_value(&entry_ptr->me_key, value,
5466 &entry_ptr->me_value, out_key, out_value) < 0) {
5467 goto try_locked;
5468 }
5469 }
5470 else {
5471 PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
5472 PyObject *value;
5473 while (i < n &&
5474 (value = _Py_atomic_load_ptr(&entry_ptr->me_value)) == NULL) {
5475 entry_ptr++;
5476 i++;
5477 }
5478
5479 if (i >= n)
5480 goto fail;
5481
5482 if (acquire_key_value(&entry_ptr->me_key, value,
5483 &entry_ptr->me_value, out_key, out_value) < 0) {
5484 goto try_locked;
5485 }
5486 }
5487 }
5488 // We found an element (key), but did not expect it
5489 Py_ssize_t len;
5490 if ((len = _Py_atomic_load_ssize_relaxed(&di->len)) == 0) {
5491 goto concurrent_modification;
5492 }
5493
5494 _Py_atomic_store_ssize_relaxed(&di->di_pos, i + 1);
5495 _Py_atomic_store_ssize_relaxed(&di->len, len - 1);
5496 return 0;
5497
5498 concurrent_modification:
5499 PyErr_SetString(PyExc_RuntimeError,
5500 "dictionary keys changed during iteration");
5501
5502 fail:
5503 di->di_dict = NULL;
5504 Py_DECREF(d);
5505 return -1;
5506
5507 try_locked:
5508 Py_BEGIN_CRITICAL_SECTION(d);
5509 res = dictiter_iternextitem_lock_held(d, self, out_key, out_value);
5510 Py_END_CRITICAL_SECTION();
5511 return res;
5512 }
5513
5514 #endif
5515
5516 static bool
has_unique_reference(PyObject * op)5517 has_unique_reference(PyObject *op)
5518 {
5519 #ifdef Py_GIL_DISABLED
5520 return (_Py_IsOwnedByCurrentThread(op) &&
5521 op->ob_ref_local == 1 &&
5522 _Py_atomic_load_ssize_relaxed(&op->ob_ref_shared) == 0);
5523 #else
5524 return Py_REFCNT(op) == 1;
5525 #endif
5526 }
5527
5528 static bool
acquire_iter_result(PyObject * result)5529 acquire_iter_result(PyObject *result)
5530 {
5531 if (has_unique_reference(result)) {
5532 Py_INCREF(result);
5533 return true;
5534 }
5535 return false;
5536 }
5537
5538 static PyObject *
dictiter_iternextitem(PyObject * self)5539 dictiter_iternextitem(PyObject *self)
5540 {
5541 dictiterobject *di = (dictiterobject *)self;
5542 PyDictObject *d = di->di_dict;
5543
5544 if (d == NULL)
5545 return NULL;
5546
5547 PyObject *key, *value;
5548 #ifdef Py_GIL_DISABLED
5549 if (dictiter_iternext_threadsafe(d, self, &key, &value) == 0) {
5550 #else
5551 if (dictiter_iternextitem_lock_held(d, self, &key, &value) == 0) {
5552
5553 #endif
5554 PyObject *result = di->di_result;
5555 if (acquire_iter_result(result)) {
5556 PyObject *oldkey = PyTuple_GET_ITEM(result, 0);
5557 PyObject *oldvalue = PyTuple_GET_ITEM(result, 1);
5558 PyTuple_SET_ITEM(result, 0, key);
5559 PyTuple_SET_ITEM(result, 1, value);
5560 Py_DECREF(oldkey);
5561 Py_DECREF(oldvalue);
5562 // bpo-42536: The GC may have untracked this result tuple. Since we're
5563 // recycling it, make sure it's tracked again:
5564 if (!_PyObject_GC_IS_TRACKED(result)) {
5565 _PyObject_GC_TRACK(result);
5566 }
5567 }
5568 else {
5569 result = PyTuple_New(2);
5570 if (result == NULL)
5571 return NULL;
5572 PyTuple_SET_ITEM(result, 0, key);
5573 PyTuple_SET_ITEM(result, 1, value);
5574 }
5575 return result;
5576 }
5577 return NULL;
5578 }
5579
5580 PyTypeObject PyDictIterItem_Type = {
5581 PyVarObject_HEAD_INIT(&PyType_Type, 0)
5582 "dict_itemiterator", /* tp_name */
5583 sizeof(dictiterobject), /* tp_basicsize */
5584 0, /* tp_itemsize */
5585 /* methods */
5586 dictiter_dealloc, /* tp_dealloc */
5587 0, /* tp_vectorcall_offset */
5588 0, /* tp_getattr */
5589 0, /* tp_setattr */
5590 0, /* tp_as_async */
5591 0, /* tp_repr */
5592 0, /* tp_as_number */
5593 0, /* tp_as_sequence */
5594 0, /* tp_as_mapping */
5595 0, /* tp_hash */
5596 0, /* tp_call */
5597 0, /* tp_str */
5598 PyObject_GenericGetAttr, /* tp_getattro */
5599 0, /* tp_setattro */
5600 0, /* tp_as_buffer */
5601 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
5602 0, /* tp_doc */
5603 dictiter_traverse, /* tp_traverse */
5604 0, /* tp_clear */
5605 0, /* tp_richcompare */
5606 0, /* tp_weaklistoffset */
5607 PyObject_SelfIter, /* tp_iter */
5608 dictiter_iternextitem, /* tp_iternext */
5609 dictiter_methods, /* tp_methods */
5610 0,
5611 };
5612
5613
5614 /* dictreviter */
5615
5616 static PyObject *
5617 dictreviter_iter_lock_held(PyDictObject *d, PyObject *self)
5618 {
5619 dictiterobject *di = (dictiterobject *)self;
5620
5621 assert (PyDict_Check(d));
5622 ASSERT_DICT_LOCKED(d);
5623
5624 if (di->di_used != d->ma_used) {
5625 PyErr_SetString(PyExc_RuntimeError,
5626 "dictionary changed size during iteration");
5627 di->di_used = -1; /* Make this state sticky */
5628 return NULL;
5629 }
5630
5631 Py_ssize_t i = di->di_pos;
5632 PyDictKeysObject *k = d->ma_keys;
5633 PyObject *key, *value, *result;
5634
5635 if (i < 0) {
5636 goto fail;
5637 }
5638 if (_PyDict_HasSplitTable(d)) {
5639 int index = get_index_from_order(d, i);
5640 key = LOAD_SHARED_KEY(DK_UNICODE_ENTRIES(k)[index].me_key);
5641 value = d->ma_values->values[index];
5642 assert (value != NULL);
5643 }
5644 else {
5645 if (DK_IS_UNICODE(k)) {
5646 PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
5647 while (entry_ptr->me_value == NULL) {
5648 if (--i < 0) {
5649 goto fail;
5650 }
5651 entry_ptr--;
5652 }
5653 key = entry_ptr->me_key;
5654 value = entry_ptr->me_value;
5655 }
5656 else {
5657 PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
5658 while (entry_ptr->me_value == NULL) {
5659 if (--i < 0) {
5660 goto fail;
5661 }
5662 entry_ptr--;
5663 }
5664 key = entry_ptr->me_key;
5665 value = entry_ptr->me_value;
5666 }
5667 }
5668 di->di_pos = i-1;
5669 di->len--;
5670
5671 if (Py_IS_TYPE(di, &PyDictRevIterKey_Type)) {
5672 return Py_NewRef(key);
5673 }
5674 else if (Py_IS_TYPE(di, &PyDictRevIterValue_Type)) {
5675 return Py_NewRef(value);
5676 }
5677 else if (Py_IS_TYPE(di, &PyDictRevIterItem_Type)) {
5678 result = di->di_result;
5679 if (Py_REFCNT(result) == 1) {
5680 PyObject *oldkey = PyTuple_GET_ITEM(result, 0);
5681 PyObject *oldvalue = PyTuple_GET_ITEM(result, 1);
5682 PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
5683 PyTuple_SET_ITEM(result, 1, Py_NewRef(value));
5684 Py_INCREF(result);
5685 Py_DECREF(oldkey);
5686 Py_DECREF(oldvalue);
5687 // bpo-42536: The GC may have untracked this result tuple. Since
5688 // we're recycling it, make sure it's tracked again:
5689 if (!_PyObject_GC_IS_TRACKED(result)) {
5690 _PyObject_GC_TRACK(result);
5691 }
5692 }
5693 else {
5694 result = PyTuple_New(2);
5695 if (result == NULL) {
5696 return NULL;
5697 }
5698 PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
5699 PyTuple_SET_ITEM(result, 1, Py_NewRef(value));
5700 }
5701 return result;
5702 }
5703 else {
5704 Py_UNREACHABLE();
5705 }
5706
5707 fail:
5708 di->di_dict = NULL;
5709 Py_DECREF(d);
5710 return NULL;
5711 }
5712
5713 static PyObject *
5714 dictreviter_iternext(PyObject *self)
5715 {
5716 dictiterobject *di = (dictiterobject *)self;
5717 PyDictObject *d = di->di_dict;
5718
5719 if (d == NULL)
5720 return NULL;
5721
5722 PyObject *value;
5723 Py_BEGIN_CRITICAL_SECTION(d);
5724 value = dictreviter_iter_lock_held(d, self);
5725 Py_END_CRITICAL_SECTION();
5726
5727 return value;
5728 }
5729
5730 PyTypeObject PyDictRevIterKey_Type = {
5731 PyVarObject_HEAD_INIT(&PyType_Type, 0)
5732 "dict_reversekeyiterator",
5733 sizeof(dictiterobject),
5734 .tp_dealloc = dictiter_dealloc,
5735 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
5736 .tp_traverse = dictiter_traverse,
5737 .tp_iter = PyObject_SelfIter,
5738 .tp_iternext = dictreviter_iternext,
5739 .tp_methods = dictiter_methods
5740 };
5741
5742
5743 /*[clinic input]
5744 dict.__reversed__
5745
5746 Return a reverse iterator over the dict keys.
5747 [clinic start generated code]*/
5748
5749 static PyObject *
5750 dict___reversed___impl(PyDictObject *self)
5751 /*[clinic end generated code: output=e674483336d1ed51 input=23210ef3477d8c4d]*/
5752 {
5753 assert (PyDict_Check(self));
5754 return dictiter_new(self, &PyDictRevIterKey_Type);
5755 }
5756
5757 static PyObject *
5758 dictiter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
5759 {
5760 dictiterobject *di = (dictiterobject *)self;
5761 /* copy the iterator state */
5762 dictiterobject tmp = *di;
5763 Py_XINCREF(tmp.di_dict);
5764 PyObject *list = PySequence_List((PyObject*)&tmp);
5765 Py_XDECREF(tmp.di_dict);
5766 if (list == NULL) {
5767 return NULL;
5768 }
5769 return Py_BuildValue("N(N)", _PyEval_GetBuiltin(&_Py_ID(iter)), list);
5770 }
5771
5772 PyTypeObject PyDictRevIterItem_Type = {
5773 PyVarObject_HEAD_INIT(&PyType_Type, 0)
5774 "dict_reverseitemiterator",
5775 sizeof(dictiterobject),
5776 .tp_dealloc = dictiter_dealloc,
5777 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
5778 .tp_traverse = dictiter_traverse,
5779 .tp_iter = PyObject_SelfIter,
5780 .tp_iternext = dictreviter_iternext,
5781 .tp_methods = dictiter_methods
5782 };
5783
5784 PyTypeObject PyDictRevIterValue_Type = {
5785 PyVarObject_HEAD_INIT(&PyType_Type, 0)
5786 "dict_reversevalueiterator",
5787 sizeof(dictiterobject),
5788 .tp_dealloc = dictiter_dealloc,
5789 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
5790 .tp_traverse = dictiter_traverse,
5791 .tp_iter = PyObject_SelfIter,
5792 .tp_iternext = dictreviter_iternext,
5793 .tp_methods = dictiter_methods
5794 };
5795
5796 /***********************************************/
5797 /* View objects for keys(), items(), values(). */
5798 /***********************************************/
5799
5800 /* The instance lay-out is the same for all three; but the type differs. */
5801
5802 static void
5803 dictview_dealloc(PyObject *self)
5804 {
5805 _PyDictViewObject *dv = (_PyDictViewObject *)self;
5806 /* bpo-31095: UnTrack is needed before calling any callbacks */
5807 _PyObject_GC_UNTRACK(dv);
5808 Py_XDECREF(dv->dv_dict);
5809 PyObject_GC_Del(dv);
5810 }
5811
5812 static int
5813 dictview_traverse(PyObject *self, visitproc visit, void *arg)
5814 {
5815 _PyDictViewObject *dv = (_PyDictViewObject *)self;
5816 Py_VISIT(dv->dv_dict);
5817 return 0;
5818 }
5819
5820 static Py_ssize_t
5821 dictview_len(PyObject *self)
5822 {
5823 _PyDictViewObject *dv = (_PyDictViewObject *)self;
5824 Py_ssize_t len = 0;
5825 if (dv->dv_dict != NULL)
5826 len = FT_ATOMIC_LOAD_SSIZE_RELAXED(dv->dv_dict->ma_used);
5827 return len;
5828 }
5829
5830 PyObject *
5831 _PyDictView_New(PyObject *dict, PyTypeObject *type)
5832 {
5833 _PyDictViewObject *dv;
5834 if (dict == NULL) {
5835 PyErr_BadInternalCall();
5836 return NULL;
5837 }
5838 if (!PyDict_Check(dict)) {
5839 /* XXX Get rid of this restriction later */
5840 PyErr_Format(PyExc_TypeError,
5841 "%s() requires a dict argument, not '%s'",
5842 type->tp_name, Py_TYPE(dict)->tp_name);
5843 return NULL;
5844 }
5845 dv = PyObject_GC_New(_PyDictViewObject, type);
5846 if (dv == NULL)
5847 return NULL;
5848 dv->dv_dict = (PyDictObject *)Py_NewRef(dict);
5849 _PyObject_GC_TRACK(dv);
5850 return (PyObject *)dv;
5851 }
5852
5853 static PyObject *
5854 dictview_mapping(PyObject *view, void *Py_UNUSED(ignored)) {
5855 assert(view != NULL);
5856 assert(PyDictKeys_Check(view)
5857 || PyDictValues_Check(view)
5858 || PyDictItems_Check(view));
5859 PyObject *mapping = (PyObject *)((_PyDictViewObject *)view)->dv_dict;
5860 return PyDictProxy_New(mapping);
5861 }
5862
5863 static PyGetSetDef dictview_getset[] = {
5864 {"mapping", dictview_mapping, (setter)NULL,
5865 PyDoc_STR("dictionary that this view refers to"), NULL},
5866 {0}
5867 };
5868
5869 /* TODO(guido): The views objects are not complete:
5870
5871 * support more set operations
5872 * support arbitrary mappings?
5873 - either these should be static or exported in dictobject.h
5874 - if public then they should probably be in builtins
5875 */
5876
5877 /* Return 1 if self is a subset of other, iterating over self;
5878 0 if not; -1 if an error occurred. */
5879 static int
5880 all_contained_in(PyObject *self, PyObject *other)
5881 {
5882 PyObject *iter = PyObject_GetIter(self);
5883 int ok = 1;
5884
5885 if (iter == NULL)
5886 return -1;
5887 for (;;) {
5888 PyObject *next = PyIter_Next(iter);
5889 if (next == NULL) {
5890 if (PyErr_Occurred())
5891 ok = -1;
5892 break;
5893 }
5894 ok = PySequence_Contains(other, next);
5895 Py_DECREF(next);
5896 if (ok <= 0)
5897 break;
5898 }
5899 Py_DECREF(iter);
5900 return ok;
5901 }
5902
5903 static PyObject *
5904 dictview_richcompare(PyObject *self, PyObject *other, int op)
5905 {
5906 Py_ssize_t len_self, len_other;
5907 int ok;
5908 PyObject *result;
5909
5910 assert(self != NULL);
5911 assert(PyDictViewSet_Check(self));
5912 assert(other != NULL);
5913
5914 if (!PyAnySet_Check(other) && !PyDictViewSet_Check(other))
5915 Py_RETURN_NOTIMPLEMENTED;
5916
5917 len_self = PyObject_Size(self);
5918 if (len_self < 0)
5919 return NULL;
5920 len_other = PyObject_Size(other);
5921 if (len_other < 0)
5922 return NULL;
5923
5924 ok = 0;
5925 switch(op) {
5926
5927 case Py_NE:
5928 case Py_EQ:
5929 if (len_self == len_other)
5930 ok = all_contained_in(self, other);
5931 if (op == Py_NE && ok >= 0)
5932 ok = !ok;
5933 break;
5934
5935 case Py_LT:
5936 if (len_self < len_other)
5937 ok = all_contained_in(self, other);
5938 break;
5939
5940 case Py_LE:
5941 if (len_self <= len_other)
5942 ok = all_contained_in(self, other);
5943 break;
5944
5945 case Py_GT:
5946 if (len_self > len_other)
5947 ok = all_contained_in(other, self);
5948 break;
5949
5950 case Py_GE:
5951 if (len_self >= len_other)
5952 ok = all_contained_in(other, self);
5953 break;
5954
5955 }
5956 if (ok < 0)
5957 return NULL;
5958 result = ok ? Py_True : Py_False;
5959 return Py_NewRef(result);
5960 }
5961
5962 static PyObject *
5963 dictview_repr(PyObject *self)
5964 {
5965 _PyDictViewObject *dv = (_PyDictViewObject *)self;
5966 PyObject *seq;
5967 PyObject *result = NULL;
5968 Py_ssize_t rc;
5969
5970 rc = Py_ReprEnter((PyObject *)dv);
5971 if (rc != 0) {
5972 return rc > 0 ? PyUnicode_FromString("...") : NULL;
5973 }
5974 seq = PySequence_List((PyObject *)dv);
5975 if (seq == NULL) {
5976 goto Done;
5977 }
5978 result = PyUnicode_FromFormat("%s(%R)", Py_TYPE(dv)->tp_name, seq);
5979 Py_DECREF(seq);
5980
5981 Done:
5982 Py_ReprLeave((PyObject *)dv);
5983 return result;
5984 }
5985
5986 /*** dict_keys ***/
5987
5988 static PyObject *
5989 dictkeys_iter(PyObject *self)
5990 {
5991 _PyDictViewObject *dv = (_PyDictViewObject *)self;
5992 if (dv->dv_dict == NULL) {
5993 Py_RETURN_NONE;
5994 }
5995 return dictiter_new(dv->dv_dict, &PyDictIterKey_Type);
5996 }
5997
5998 static int
5999 dictkeys_contains(PyObject *self, PyObject *obj)
6000 {
6001 _PyDictViewObject *dv = (_PyDictViewObject *)self;
6002 if (dv->dv_dict == NULL)
6003 return 0;
6004 return PyDict_Contains((PyObject *)dv->dv_dict, obj);
6005 }
6006
6007 static PySequenceMethods dictkeys_as_sequence = {
6008 dictview_len, /* sq_length */
6009 0, /* sq_concat */
6010 0, /* sq_repeat */
6011 0, /* sq_item */
6012 0, /* sq_slice */
6013 0, /* sq_ass_item */
6014 0, /* sq_ass_slice */
6015 dictkeys_contains, /* sq_contains */
6016 };
6017
6018 // Create a set object from dictviews object.
6019 // Returns a new reference.
6020 // This utility function is used by set operations.
6021 static PyObject*
6022 dictviews_to_set(PyObject *self)
6023 {
6024 PyObject *left = self;
6025 if (PyDictKeys_Check(self)) {
6026 // PySet_New() has fast path for the dict object.
6027 PyObject *dict = (PyObject *)((_PyDictViewObject *)self)->dv_dict;
6028 if (PyDict_CheckExact(dict)) {
6029 left = dict;
6030 }
6031 }
6032 return PySet_New(left);
6033 }
6034
6035 static PyObject*
6036 dictviews_sub(PyObject *self, PyObject *other)
6037 {
6038 PyObject *result = dictviews_to_set(self);
6039 if (result == NULL) {
6040 return NULL;
6041 }
6042
6043 PyObject *tmp = PyObject_CallMethodOneArg(
6044 result, &_Py_ID(difference_update), other);
6045 if (tmp == NULL) {
6046 Py_DECREF(result);
6047 return NULL;
6048 }
6049
6050 Py_DECREF(tmp);
6051 return result;
6052 }
6053
6054 static int
6055 dictitems_contains(PyObject *dv, PyObject *obj);
6056
6057 PyObject *
6058 _PyDictView_Intersect(PyObject* self, PyObject *other)
6059 {
6060 PyObject *result;
6061 PyObject *it;
6062 PyObject *key;
6063 Py_ssize_t len_self;
6064 int rv;
6065 objobjproc dict_contains;
6066
6067 /* Python interpreter swaps parameters when dict view
6068 is on right side of & */
6069 if (!PyDictViewSet_Check(self)) {
6070 PyObject *tmp = other;
6071 other = self;
6072 self = tmp;
6073 }
6074
6075 len_self = dictview_len(self);
6076
6077 /* if other is a set and self is smaller than other,
6078 reuse set intersection logic */
6079 if (PySet_CheckExact(other) && len_self <= PyObject_Size(other)) {
6080 return PyObject_CallMethodObjArgs(
6081 other, &_Py_ID(intersection), self, NULL);
6082 }
6083
6084 /* if other is another dict view, and it is bigger than self,
6085 swap them */
6086 if (PyDictViewSet_Check(other)) {
6087 Py_ssize_t len_other = dictview_len(other);
6088 if (len_other > len_self) {
6089 PyObject *tmp = other;
6090 other = self;
6091 self = tmp;
6092 }
6093 }
6094
6095 /* at this point, two things should be true
6096 1. self is a dictview
6097 2. if other is a dictview then it is smaller than self */
6098 result = PySet_New(NULL);
6099 if (result == NULL)
6100 return NULL;
6101
6102 it = PyObject_GetIter(other);
6103 if (it == NULL) {
6104 Py_DECREF(result);
6105 return NULL;
6106 }
6107
6108 if (PyDictKeys_Check(self)) {
6109 dict_contains = dictkeys_contains;
6110 }
6111 /* else PyDictItems_Check(self) */
6112 else {
6113 dict_contains = dictitems_contains;
6114 }
6115
6116 while ((key = PyIter_Next(it)) != NULL) {
6117 rv = dict_contains(self, key);
6118 if (rv < 0) {
6119 goto error;
6120 }
6121 if (rv) {
6122 if (PySet_Add(result, key)) {
6123 goto error;
6124 }
6125 }
6126 Py_DECREF(key);
6127 }
6128 Py_DECREF(it);
6129 if (PyErr_Occurred()) {
6130 Py_DECREF(result);
6131 return NULL;
6132 }
6133 return result;
6134
6135 error:
6136 Py_DECREF(it);
6137 Py_DECREF(result);
6138 Py_DECREF(key);
6139 return NULL;
6140 }
6141
6142 static PyObject*
6143 dictviews_or(PyObject* self, PyObject *other)
6144 {
6145 PyObject *result = dictviews_to_set(self);
6146 if (result == NULL) {
6147 return NULL;
6148 }
6149
6150 if (_PySet_Update(result, other) < 0) {
6151 Py_DECREF(result);
6152 return NULL;
6153 }
6154 return result;
6155 }
6156
6157 static PyObject *
6158 dictitems_xor_lock_held(PyObject *d1, PyObject *d2)
6159 {
6160 ASSERT_DICT_LOCKED(d1);
6161 ASSERT_DICT_LOCKED(d2);
6162
6163 PyObject *temp_dict = copy_lock_held(d1);
6164 if (temp_dict == NULL) {
6165 return NULL;
6166 }
6167 PyObject *result_set = PySet_New(NULL);
6168 if (result_set == NULL) {
6169 Py_CLEAR(temp_dict);
6170 return NULL;
6171 }
6172
6173 PyObject *key = NULL, *val1 = NULL, *val2 = NULL;
6174 Py_ssize_t pos = 0;
6175 Py_hash_t hash;
6176
6177 while (_PyDict_Next(d2, &pos, &key, &val2, &hash)) {
6178 Py_INCREF(key);
6179 Py_INCREF(val2);
6180 val1 = _PyDict_GetItem_KnownHash(temp_dict, key, hash);
6181
6182 int to_delete;
6183 if (val1 == NULL) {
6184 if (PyErr_Occurred()) {
6185 goto error;
6186 }
6187 to_delete = 0;
6188 }
6189 else {
6190 Py_INCREF(val1);
6191 to_delete = PyObject_RichCompareBool(val1, val2, Py_EQ);
6192 if (to_delete < 0) {
6193 goto error;
6194 }
6195 }
6196
6197 if (to_delete) {
6198 if (_PyDict_DelItem_KnownHash(temp_dict, key, hash) < 0) {
6199 goto error;
6200 }
6201 }
6202 else {
6203 PyObject *pair = PyTuple_Pack(2, key, val2);
6204 if (pair == NULL) {
6205 goto error;
6206 }
6207 if (PySet_Add(result_set, pair) < 0) {
6208 Py_DECREF(pair);
6209 goto error;
6210 }
6211 Py_DECREF(pair);
6212 }
6213 Py_DECREF(key);
6214 Py_XDECREF(val1);
6215 Py_DECREF(val2);
6216 }
6217 key = val1 = val2 = NULL;
6218
6219 PyObject *remaining_pairs = PyObject_CallMethodNoArgs(
6220 temp_dict, &_Py_ID(items));
6221 if (remaining_pairs == NULL) {
6222 goto error;
6223 }
6224 if (_PySet_Update(result_set, remaining_pairs) < 0) {
6225 Py_DECREF(remaining_pairs);
6226 goto error;
6227 }
6228 Py_DECREF(temp_dict);
6229 Py_DECREF(remaining_pairs);
6230 return result_set;
6231
6232 error:
6233 Py_XDECREF(temp_dict);
6234 Py_XDECREF(result_set);
6235 Py_XDECREF(key);
6236 Py_XDECREF(val1);
6237 Py_XDECREF(val2);
6238 return NULL;
6239 }
6240
6241 static PyObject *
6242 dictitems_xor(PyObject *self, PyObject *other)
6243 {
6244 assert(PyDictItems_Check(self));
6245 assert(PyDictItems_Check(other));
6246 PyObject *d1 = (PyObject *)((_PyDictViewObject *)self)->dv_dict;
6247 PyObject *d2 = (PyObject *)((_PyDictViewObject *)other)->dv_dict;
6248
6249 PyObject *res;
6250 Py_BEGIN_CRITICAL_SECTION2(d1, d2);
6251 res = dictitems_xor_lock_held(d1, d2);
6252 Py_END_CRITICAL_SECTION2();
6253
6254 return res;
6255 }
6256
6257 static PyObject*
6258 dictviews_xor(PyObject* self, PyObject *other)
6259 {
6260 if (PyDictItems_Check(self) && PyDictItems_Check(other)) {
6261 return dictitems_xor(self, other);
6262 }
6263 PyObject *result = dictviews_to_set(self);
6264 if (result == NULL) {
6265 return NULL;
6266 }
6267
6268 PyObject *tmp = PyObject_CallMethodOneArg(
6269 result, &_Py_ID(symmetric_difference_update), other);
6270 if (tmp == NULL) {
6271 Py_DECREF(result);
6272 return NULL;
6273 }
6274
6275 Py_DECREF(tmp);
6276 return result;
6277 }
6278
6279 static PyNumberMethods dictviews_as_number = {
6280 0, /*nb_add*/
6281 (binaryfunc)dictviews_sub, /*nb_subtract*/
6282 0, /*nb_multiply*/
6283 0, /*nb_remainder*/
6284 0, /*nb_divmod*/
6285 0, /*nb_power*/
6286 0, /*nb_negative*/
6287 0, /*nb_positive*/
6288 0, /*nb_absolute*/
6289 0, /*nb_bool*/
6290 0, /*nb_invert*/
6291 0, /*nb_lshift*/
6292 0, /*nb_rshift*/
6293 (binaryfunc)_PyDictView_Intersect, /*nb_and*/
6294 (binaryfunc)dictviews_xor, /*nb_xor*/
6295 (binaryfunc)dictviews_or, /*nb_or*/
6296 };
6297
6298 static PyObject*
6299 dictviews_isdisjoint(PyObject *self, PyObject *other)
6300 {
6301 PyObject *it;
6302 PyObject *item = NULL;
6303
6304 if (self == other) {
6305 if (dictview_len(self) == 0)
6306 Py_RETURN_TRUE;
6307 else
6308 Py_RETURN_FALSE;
6309 }
6310
6311 /* Iterate over the shorter object (only if other is a set,
6312 * because PySequence_Contains may be expensive otherwise): */
6313 if (PyAnySet_Check(other) || PyDictViewSet_Check(other)) {
6314 Py_ssize_t len_self = dictview_len(self);
6315 Py_ssize_t len_other = PyObject_Size(other);
6316 if (len_other == -1)
6317 return NULL;
6318
6319 if ((len_other > len_self)) {
6320 PyObject *tmp = other;
6321 other = self;
6322 self = tmp;
6323 }
6324 }
6325
6326 it = PyObject_GetIter(other);
6327 if (it == NULL)
6328 return NULL;
6329
6330 while ((item = PyIter_Next(it)) != NULL) {
6331 int contains = PySequence_Contains(self, item);
6332 Py_DECREF(item);
6333 if (contains == -1) {
6334 Py_DECREF(it);
6335 return NULL;
6336 }
6337
6338 if (contains) {
6339 Py_DECREF(it);
6340 Py_RETURN_FALSE;
6341 }
6342 }
6343 Py_DECREF(it);
6344 if (PyErr_Occurred())
6345 return NULL; /* PyIter_Next raised an exception. */
6346 Py_RETURN_TRUE;
6347 }
6348
6349 PyDoc_STRVAR(isdisjoint_doc,
6350 "Return True if the view and the given iterable have a null intersection.");
6351
6352 static PyObject* dictkeys_reversed(PyObject *dv, PyObject *Py_UNUSED(ignored));
6353
6354 PyDoc_STRVAR(reversed_keys_doc,
6355 "Return a reverse iterator over the dict keys.");
6356
6357 static PyMethodDef dictkeys_methods[] = {
6358 {"isdisjoint", dictviews_isdisjoint, METH_O,
6359 isdisjoint_doc},
6360 {"__reversed__", dictkeys_reversed, METH_NOARGS,
6361 reversed_keys_doc},
6362 {NULL, NULL} /* sentinel */
6363 };
6364
6365 PyTypeObject PyDictKeys_Type = {
6366 PyVarObject_HEAD_INIT(&PyType_Type, 0)
6367 "dict_keys", /* tp_name */
6368 sizeof(_PyDictViewObject), /* tp_basicsize */
6369 0, /* tp_itemsize */
6370 /* methods */
6371 dictview_dealloc, /* tp_dealloc */
6372 0, /* tp_vectorcall_offset */
6373 0, /* tp_getattr */
6374 0, /* tp_setattr */
6375 0, /* tp_as_async */
6376 dictview_repr, /* tp_repr */
6377 &dictviews_as_number, /* tp_as_number */
6378 &dictkeys_as_sequence, /* tp_as_sequence */
6379 0, /* tp_as_mapping */
6380 0, /* tp_hash */
6381 0, /* tp_call */
6382 0, /* tp_str */
6383 PyObject_GenericGetAttr, /* tp_getattro */
6384 0, /* tp_setattro */
6385 0, /* tp_as_buffer */
6386 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
6387 0, /* tp_doc */
6388 dictview_traverse, /* tp_traverse */
6389 0, /* tp_clear */
6390 dictview_richcompare, /* tp_richcompare */
6391 0, /* tp_weaklistoffset */
6392 dictkeys_iter, /* tp_iter */
6393 0, /* tp_iternext */
6394 dictkeys_methods, /* tp_methods */
6395 .tp_getset = dictview_getset,
6396 };
6397
6398 /*[clinic input]
6399 dict.keys
6400
6401 Return a set-like object providing a view on the dict's keys.
6402 [clinic start generated code]*/
6403
6404 static PyObject *
6405 dict_keys_impl(PyDictObject *self)
6406 /*[clinic end generated code: output=aac2830c62990358 input=42f48a7a771212a7]*/
6407 {
6408 return _PyDictView_New((PyObject *)self, &PyDictKeys_Type);
6409 }
6410
6411 static PyObject *
6412 dictkeys_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
6413 {
6414 _PyDictViewObject *dv = (_PyDictViewObject *)self;
6415 if (dv->dv_dict == NULL) {
6416 Py_RETURN_NONE;
6417 }
6418 return dictiter_new(dv->dv_dict, &PyDictRevIterKey_Type);
6419 }
6420
6421 /*** dict_items ***/
6422
6423 static PyObject *
6424 dictitems_iter(PyObject *self)
6425 {
6426 _PyDictViewObject *dv = (_PyDictViewObject *)self;
6427 if (dv->dv_dict == NULL) {
6428 Py_RETURN_NONE;
6429 }
6430 return dictiter_new(dv->dv_dict, &PyDictIterItem_Type);
6431 }
6432
6433 static int
6434 dictitems_contains(PyObject *self, PyObject *obj)
6435 {
6436 _PyDictViewObject *dv = (_PyDictViewObject *)self;
6437 int result;
6438 PyObject *key, *value, *found;
6439 if (dv->dv_dict == NULL)
6440 return 0;
6441 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 2)
6442 return 0;
6443 key = PyTuple_GET_ITEM(obj, 0);
6444 value = PyTuple_GET_ITEM(obj, 1);
6445 result = PyDict_GetItemRef((PyObject *)dv->dv_dict, key, &found);
6446 if (result == 1) {
6447 result = PyObject_RichCompareBool(found, value, Py_EQ);
6448 Py_DECREF(found);
6449 }
6450 return result;
6451 }
6452
6453 static PySequenceMethods dictitems_as_sequence = {
6454 dictview_len, /* sq_length */
6455 0, /* sq_concat */
6456 0, /* sq_repeat */
6457 0, /* sq_item */
6458 0, /* sq_slice */
6459 0, /* sq_ass_item */
6460 0, /* sq_ass_slice */
6461 dictitems_contains, /* sq_contains */
6462 };
6463
6464 static PyObject* dictitems_reversed(PyObject *dv, PyObject *Py_UNUSED(ignored));
6465
6466 PyDoc_STRVAR(reversed_items_doc,
6467 "Return a reverse iterator over the dict items.");
6468
6469 static PyMethodDef dictitems_methods[] = {
6470 {"isdisjoint", dictviews_isdisjoint, METH_O,
6471 isdisjoint_doc},
6472 {"__reversed__", dictitems_reversed, METH_NOARGS,
6473 reversed_items_doc},
6474 {NULL, NULL} /* sentinel */
6475 };
6476
6477 PyTypeObject PyDictItems_Type = {
6478 PyVarObject_HEAD_INIT(&PyType_Type, 0)
6479 "dict_items", /* tp_name */
6480 sizeof(_PyDictViewObject), /* tp_basicsize */
6481 0, /* tp_itemsize */
6482 /* methods */
6483 dictview_dealloc, /* tp_dealloc */
6484 0, /* tp_vectorcall_offset */
6485 0, /* tp_getattr */
6486 0, /* tp_setattr */
6487 0, /* tp_as_async */
6488 dictview_repr, /* tp_repr */
6489 &dictviews_as_number, /* tp_as_number */
6490 &dictitems_as_sequence, /* tp_as_sequence */
6491 0, /* tp_as_mapping */
6492 0, /* tp_hash */
6493 0, /* tp_call */
6494 0, /* tp_str */
6495 PyObject_GenericGetAttr, /* tp_getattro */
6496 0, /* tp_setattro */
6497 0, /* tp_as_buffer */
6498 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
6499 0, /* tp_doc */
6500 dictview_traverse, /* tp_traverse */
6501 0, /* tp_clear */
6502 dictview_richcompare, /* tp_richcompare */
6503 0, /* tp_weaklistoffset */
6504 dictitems_iter, /* tp_iter */
6505 0, /* tp_iternext */
6506 dictitems_methods, /* tp_methods */
6507 .tp_getset = dictview_getset,
6508 };
6509
6510 /*[clinic input]
6511 dict.items
6512
6513 Return a set-like object providing a view on the dict's items.
6514 [clinic start generated code]*/
6515
6516 static PyObject *
6517 dict_items_impl(PyDictObject *self)
6518 /*[clinic end generated code: output=88c7db7150c7909a input=87c822872eb71f5a]*/
6519 {
6520 return _PyDictView_New((PyObject *)self, &PyDictItems_Type);
6521 }
6522
6523 static PyObject *
6524 dictitems_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
6525 {
6526 _PyDictViewObject *dv = (_PyDictViewObject *)self;
6527 if (dv->dv_dict == NULL) {
6528 Py_RETURN_NONE;
6529 }
6530 return dictiter_new(dv->dv_dict, &PyDictRevIterItem_Type);
6531 }
6532
6533 /*** dict_values ***/
6534
6535 static PyObject *
6536 dictvalues_iter(PyObject *self)
6537 {
6538 _PyDictViewObject *dv = (_PyDictViewObject *)self;
6539 if (dv->dv_dict == NULL) {
6540 Py_RETURN_NONE;
6541 }
6542 return dictiter_new(dv->dv_dict, &PyDictIterValue_Type);
6543 }
6544
6545 static PySequenceMethods dictvalues_as_sequence = {
6546 dictview_len, /* sq_length */
6547 0, /* sq_concat */
6548 0, /* sq_repeat */
6549 0, /* sq_item */
6550 0, /* sq_slice */
6551 0, /* sq_ass_item */
6552 0, /* sq_ass_slice */
6553 (objobjproc)0, /* sq_contains */
6554 };
6555
6556 static PyObject* dictvalues_reversed(PyObject *dv, PyObject *Py_UNUSED(ignored));
6557
6558 PyDoc_STRVAR(reversed_values_doc,
6559 "Return a reverse iterator over the dict values.");
6560
6561 static PyMethodDef dictvalues_methods[] = {
6562 {"__reversed__", dictvalues_reversed, METH_NOARGS,
6563 reversed_values_doc},
6564 {NULL, NULL} /* sentinel */
6565 };
6566
6567 PyTypeObject PyDictValues_Type = {
6568 PyVarObject_HEAD_INIT(&PyType_Type, 0)
6569 "dict_values", /* tp_name */
6570 sizeof(_PyDictViewObject), /* tp_basicsize */
6571 0, /* tp_itemsize */
6572 /* methods */
6573 dictview_dealloc, /* tp_dealloc */
6574 0, /* tp_vectorcall_offset */
6575 0, /* tp_getattr */
6576 0, /* tp_setattr */
6577 0, /* tp_as_async */
6578 dictview_repr, /* tp_repr */
6579 0, /* tp_as_number */
6580 &dictvalues_as_sequence, /* tp_as_sequence */
6581 0, /* tp_as_mapping */
6582 0, /* tp_hash */
6583 0, /* tp_call */
6584 0, /* tp_str */
6585 PyObject_GenericGetAttr, /* tp_getattro */
6586 0, /* tp_setattro */
6587 0, /* tp_as_buffer */
6588 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
6589 0, /* tp_doc */
6590 dictview_traverse, /* tp_traverse */
6591 0, /* tp_clear */
6592 0, /* tp_richcompare */
6593 0, /* tp_weaklistoffset */
6594 dictvalues_iter, /* tp_iter */
6595 0, /* tp_iternext */
6596 dictvalues_methods, /* tp_methods */
6597 .tp_getset = dictview_getset,
6598 };
6599
6600 /*[clinic input]
6601 dict.values
6602
6603 Return an object providing a view on the dict's values.
6604 [clinic start generated code]*/
6605
6606 static PyObject *
6607 dict_values_impl(PyDictObject *self)
6608 /*[clinic end generated code: output=ce9f2e9e8a959dd4 input=b46944f85493b230]*/
6609 {
6610 return _PyDictView_New((PyObject *)self, &PyDictValues_Type);
6611 }
6612
6613 static PyObject *
6614 dictvalues_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
6615 {
6616 _PyDictViewObject *dv = (_PyDictViewObject *)self;
6617 if (dv->dv_dict == NULL) {
6618 Py_RETURN_NONE;
6619 }
6620 return dictiter_new(dv->dv_dict, &PyDictRevIterValue_Type);
6621 }
6622
6623
6624 /* Returns NULL if cannot allocate a new PyDictKeysObject,
6625 but does not set an error */
6626 PyDictKeysObject *
6627 _PyDict_NewKeysForClass(void)
6628 {
6629 PyInterpreterState *interp = _PyInterpreterState_GET();
6630 PyDictKeysObject *keys = new_keys_object(
6631 interp, NEXT_LOG2_SHARED_KEYS_MAX_SIZE, 1);
6632 if (keys == NULL) {
6633 PyErr_Clear();
6634 }
6635 else {
6636 assert(keys->dk_nentries == 0);
6637 /* Set to max size+1 as it will shrink by one before each new object */
6638 keys->dk_usable = SHARED_KEYS_MAX_SIZE;
6639 keys->dk_kind = DICT_KEYS_SPLIT;
6640 }
6641 return keys;
6642 }
6643
6644 void
6645 _PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp)
6646 {
6647 assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE);
6648 assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES);
6649 assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
6650 PyDictKeysObject *keys = CACHED_KEYS(tp);
6651 assert(keys != NULL);
6652 OBJECT_STAT_INC(inline_values);
6653 #ifdef Py_GIL_DISABLED
6654 Py_ssize_t usable = _Py_atomic_load_ssize_relaxed(&keys->dk_usable);
6655 if (usable > 1) {
6656 LOCK_KEYS(keys);
6657 if (keys->dk_usable > 1) {
6658 _Py_atomic_store_ssize(&keys->dk_usable, keys->dk_usable - 1);
6659 }
6660 UNLOCK_KEYS(keys);
6661 }
6662 #else
6663 if (keys->dk_usable > 1) {
6664 keys->dk_usable--;
6665 }
6666 #endif
6667 size_t size = shared_keys_usable_size(keys);
6668 PyDictValues *values = _PyObject_InlineValues(obj);
6669 assert(size < 256);
6670 values->capacity = (uint8_t)size;
6671 values->size = 0;
6672 values->embedded = 1;
6673 values->valid = 1;
6674 for (size_t i = 0; i < size; i++) {
6675 values->values[i] = NULL;
6676 }
6677 _PyObject_ManagedDictPointer(obj)->dict = NULL;
6678 }
6679
6680 static PyDictObject *
6681 make_dict_from_instance_attributes(PyInterpreterState *interp,
6682 PyDictKeysObject *keys, PyDictValues *values)
6683 {
6684 dictkeys_incref(keys);
6685 Py_ssize_t used = 0;
6686 Py_ssize_t track = 0;
6687 size_t size = shared_keys_usable_size(keys);
6688 for (size_t i = 0; i < size; i++) {
6689 PyObject *val = values->values[i];
6690 if (val != NULL) {
6691 used += 1;
6692 track += _PyObject_GC_MAY_BE_TRACKED(val);
6693 }
6694 }
6695 PyDictObject *res = (PyDictObject *)new_dict(interp, keys, values, used, 0);
6696 if (track && res) {
6697 _PyObject_GC_TRACK(res);
6698 }
6699 return res;
6700 }
6701
6702 PyDictObject *
6703 _PyObject_MaterializeManagedDict_LockHeld(PyObject *obj)
6704 {
6705 ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(obj);
6706
6707 OBJECT_STAT_INC(dict_materialized_on_request);
6708
6709 PyDictValues *values = _PyObject_InlineValues(obj);
6710 PyDictObject *dict;
6711 if (values->valid) {
6712 PyInterpreterState *interp = _PyInterpreterState_GET();
6713 PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
6714 dict = make_dict_from_instance_attributes(interp, keys, values);
6715 }
6716 else {
6717 dict = (PyDictObject *)PyDict_New();
6718 }
6719 FT_ATOMIC_STORE_PTR_RELEASE(_PyObject_ManagedDictPointer(obj)->dict,
6720 dict);
6721 return dict;
6722 }
6723
6724 PyDictObject *
6725 _PyObject_MaterializeManagedDict(PyObject *obj)
6726 {
6727 PyDictObject *dict = _PyObject_GetManagedDict(obj);
6728 if (dict != NULL) {
6729 return dict;
6730 }
6731
6732 Py_BEGIN_CRITICAL_SECTION(obj);
6733
6734 #ifdef Py_GIL_DISABLED
6735 dict = _PyObject_GetManagedDict(obj);
6736 if (dict != NULL) {
6737 // We raced with another thread creating the dict
6738 goto exit;
6739 }
6740 #endif
6741 dict = _PyObject_MaterializeManagedDict_LockHeld(obj);
6742
6743 #ifdef Py_GIL_DISABLED
6744 exit:
6745 #endif
6746 Py_END_CRITICAL_SECTION();
6747 return dict;
6748 }
6749
6750 int
6751 _PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value)
6752 {
6753 if (value == NULL) {
6754 Py_hash_t hash = _PyObject_HashFast(name);
6755 if (hash == -1) {
6756 return -1;
6757 }
6758 return delitem_knownhash_lock_held((PyObject *)dict, name, hash);
6759 } else {
6760 return setitem_lock_held(dict, name, value);
6761 }
6762 }
6763
6764 // Called with either the object's lock or the dict's lock held
6765 // depending on whether or not a dict has been materialized for
6766 // the object.
6767 static int
6768 store_instance_attr_lock_held(PyObject *obj, PyDictValues *values,
6769 PyObject *name, PyObject *value)
6770 {
6771 PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
6772 assert(keys != NULL);
6773 assert(values != NULL);
6774 assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_INLINE_VALUES);
6775 Py_ssize_t ix = DKIX_EMPTY;
6776 PyDictObject *dict = _PyObject_GetManagedDict(obj);
6777 assert(dict == NULL || ((PyDictObject *)dict)->ma_values == values);
6778 if (PyUnicode_CheckExact(name)) {
6779 Py_hash_t hash = unicode_get_hash(name);
6780 if (hash == -1) {
6781 hash = PyUnicode_Type.tp_hash(name);
6782 assert(hash != -1);
6783 }
6784
6785 ix = insert_split_key(keys, name, hash);
6786
6787 #ifdef Py_STATS
6788 if (ix == DKIX_EMPTY) {
6789 if (PyUnicode_CheckExact(name)) {
6790 if (shared_keys_usable_size(keys) == SHARED_KEYS_MAX_SIZE) {
6791 OBJECT_STAT_INC(dict_materialized_too_big);
6792 }
6793 else {
6794 OBJECT_STAT_INC(dict_materialized_new_key);
6795 }
6796 }
6797 else {
6798 OBJECT_STAT_INC(dict_materialized_str_subclass);
6799 }
6800 }
6801 #endif
6802 }
6803
6804 if (ix == DKIX_EMPTY) {
6805 int res;
6806 if (dict == NULL) {
6807 // Make the dict but don't publish it in the object
6808 // so that no one else will see it.
6809 dict = make_dict_from_instance_attributes(PyInterpreterState_Get(), keys, values);
6810 if (dict == NULL ||
6811 _PyDict_SetItem_LockHeld(dict, name, value) < 0) {
6812 Py_XDECREF(dict);
6813 return -1;
6814 }
6815
6816 FT_ATOMIC_STORE_PTR_RELEASE(_PyObject_ManagedDictPointer(obj)->dict,
6817 (PyDictObject *)dict);
6818 return 0;
6819 }
6820
6821 _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(dict);
6822
6823 res = _PyDict_SetItem_LockHeld(dict, name, value);
6824 return res;
6825 }
6826
6827 PyObject *old_value = values->values[ix];
6828 if (old_value == NULL && value == NULL) {
6829 PyErr_Format(PyExc_AttributeError,
6830 "'%.100s' object has no attribute '%U'",
6831 Py_TYPE(obj)->tp_name, name);
6832 return -1;
6833 }
6834
6835 if (dict) {
6836 PyInterpreterState *interp = _PyInterpreterState_GET();
6837 PyDict_WatchEvent event = (old_value == NULL ? PyDict_EVENT_ADDED :
6838 value == NULL ? PyDict_EVENT_DELETED :
6839 PyDict_EVENT_MODIFIED);
6840 _PyDict_NotifyEvent(interp, event, dict, name, value);
6841 }
6842
6843 FT_ATOMIC_STORE_PTR_RELEASE(values->values[ix], Py_XNewRef(value));
6844
6845 if (old_value == NULL) {
6846 _PyDictValues_AddToInsertionOrder(values, ix);
6847 if (dict) {
6848 assert(dict->ma_values == values);
6849 STORE_USED(dict, dict->ma_used + 1);
6850 }
6851 }
6852 else {
6853 if (value == NULL) {
6854 delete_index_from_values(values, ix);
6855 if (dict) {
6856 assert(dict->ma_values == values);
6857 STORE_USED(dict, dict->ma_used - 1);
6858 }
6859 }
6860 Py_DECREF(old_value);
6861 }
6862 return 0;
6863 }
6864
6865 static inline int
6866 store_instance_attr_dict(PyObject *obj, PyDictObject *dict, PyObject *name, PyObject *value)
6867 {
6868 PyDictValues *values = _PyObject_InlineValues(obj);
6869 int res;
6870 Py_BEGIN_CRITICAL_SECTION(dict);
6871 if (dict->ma_values == values) {
6872 res = store_instance_attr_lock_held(obj, values, name, value);
6873 }
6874 else {
6875 res = _PyDict_SetItem_LockHeld(dict, name, value);
6876 }
6877 Py_END_CRITICAL_SECTION();
6878 return res;
6879 }
6880
6881 int
6882 _PyObject_StoreInstanceAttribute(PyObject *obj, PyObject *name, PyObject *value)
6883 {
6884 PyDictValues *values = _PyObject_InlineValues(obj);
6885 if (!FT_ATOMIC_LOAD_UINT8(values->valid)) {
6886 PyDictObject *dict = _PyObject_GetManagedDict(obj);
6887 if (dict == NULL) {
6888 dict = (PyDictObject *)PyObject_GenericGetDict(obj, NULL);
6889 if (dict == NULL) {
6890 return -1;
6891 }
6892 int res = store_instance_attr_dict(obj, dict, name, value);
6893 Py_DECREF(dict);
6894 return res;
6895 }
6896 return store_instance_attr_dict(obj, dict, name, value);
6897 }
6898
6899 #ifdef Py_GIL_DISABLED
6900 // We have a valid inline values, at least for now... There are two potential
6901 // races with having the values become invalid. One is the dictionary
6902 // being detached from the object. The other is if someone is inserting
6903 // into the dictionary directly and therefore causing it to resize.
6904 //
6905 // If we haven't materialized the dictionary yet we lock on the object, which
6906 // will also be used to prevent the dictionary from being materialized while
6907 // we're doing the insertion. If we race and the dictionary gets created
6908 // then we'll need to release the object lock and lock the dictionary to
6909 // prevent resizing.
6910 PyDictObject *dict = _PyObject_GetManagedDict(obj);
6911 if (dict == NULL) {
6912 int res;
6913 Py_BEGIN_CRITICAL_SECTION(obj);
6914 dict = _PyObject_GetManagedDict(obj);
6915
6916 if (dict == NULL) {
6917 res = store_instance_attr_lock_held(obj, values, name, value);
6918 }
6919 Py_END_CRITICAL_SECTION();
6920
6921 if (dict == NULL) {
6922 return res;
6923 }
6924 }
6925 return store_instance_attr_dict(obj, dict, name, value);
6926 #else
6927 return store_instance_attr_lock_held(obj, values, name, value);
6928 #endif
6929 }
6930
6931 /* Sanity check for managed dicts */
6932 #if 0
6933 #define CHECK(val) assert(val); if (!(val)) { return 0; }
6934
6935 int
6936 _PyObject_ManagedDictValidityCheck(PyObject *obj)
6937 {
6938 PyTypeObject *tp = Py_TYPE(obj);
6939 CHECK(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
6940 PyManagedDictPointer *managed_dict = _PyObject_ManagedDictPointer(obj);
6941 if (_PyManagedDictPointer_IsValues(*managed_dict)) {
6942 PyDictValues *values = _PyManagedDictPointer_GetValues(*managed_dict);
6943 int size = ((uint8_t *)values)[-2];
6944 int count = 0;
6945 PyDictKeysObject *keys = CACHED_KEYS(tp);
6946 for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
6947 if (values->values[i] != NULL) {
6948 count++;
6949 }
6950 }
6951 CHECK(size == count);
6952 }
6953 else {
6954 if (managed_dict->dict != NULL) {
6955 CHECK(PyDict_Check(managed_dict->dict));
6956 }
6957 }
6958 return 1;
6959 }
6960 #endif
6961
6962 // Attempts to get an instance attribute from the inline values. Returns true
6963 // if successful, or false if the caller needs to lookup in the dictionary.
6964 bool
6965 _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr)
6966 {
6967 assert(PyUnicode_CheckExact(name));
6968 PyDictValues *values = _PyObject_InlineValues(obj);
6969 if (!FT_ATOMIC_LOAD_UINT8(values->valid)) {
6970 return false;
6971 }
6972
6973 PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
6974 assert(keys != NULL);
6975 Py_ssize_t ix = _PyDictKeys_StringLookup(keys, name);
6976 if (ix == DKIX_EMPTY) {
6977 *attr = NULL;
6978 return true;
6979 }
6980
6981 #ifdef Py_GIL_DISABLED
6982 PyObject *value = _Py_atomic_load_ptr_acquire(&values->values[ix]);
6983 if (value == NULL || _Py_TryIncrefCompare(&values->values[ix], value)) {
6984 *attr = value;
6985 return true;
6986 }
6987
6988 PyDictObject *dict = _PyObject_GetManagedDict(obj);
6989 if (dict == NULL) {
6990 // No dict, lock the object to prevent one from being
6991 // materialized...
6992 bool success = false;
6993 Py_BEGIN_CRITICAL_SECTION(obj);
6994
6995 dict = _PyObject_GetManagedDict(obj);
6996 if (dict == NULL) {
6997 // Still no dict, we can read from the values
6998 assert(values->valid);
6999 value = values->values[ix];
7000 *attr = _Py_XNewRefWithLock(value);
7001 success = true;
7002 }
7003
7004 Py_END_CRITICAL_SECTION();
7005
7006 if (success) {
7007 return true;
7008 }
7009 }
7010
7011 // We have a dictionary, we'll need to lock it to prevent
7012 // the values from being resized.
7013 assert(dict != NULL);
7014
7015 bool success;
7016 Py_BEGIN_CRITICAL_SECTION(dict);
7017
7018 if (dict->ma_values == values && FT_ATOMIC_LOAD_UINT8(values->valid)) {
7019 value = _Py_atomic_load_ptr_relaxed(&values->values[ix]);
7020 *attr = _Py_XNewRefWithLock(value);
7021 success = true;
7022 } else {
7023 // Caller needs to lookup from the dictionary
7024 success = false;
7025 }
7026
7027 Py_END_CRITICAL_SECTION();
7028
7029 return success;
7030 #else
7031 PyObject *value = values->values[ix];
7032 *attr = Py_XNewRef(value);
7033 return true;
7034 #endif
7035 }
7036
7037 int
7038 _PyObject_IsInstanceDictEmpty(PyObject *obj)
7039 {
7040 PyTypeObject *tp = Py_TYPE(obj);
7041 if (tp->tp_dictoffset == 0) {
7042 return 1;
7043 }
7044 PyDictObject *dict;
7045 if (tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
7046 PyDictValues *values = _PyObject_InlineValues(obj);
7047 if (FT_ATOMIC_LOAD_UINT8(values->valid)) {
7048 PyDictKeysObject *keys = CACHED_KEYS(tp);
7049 for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
7050 if (FT_ATOMIC_LOAD_PTR_RELAXED(values->values[i]) != NULL) {
7051 return 0;
7052 }
7053 }
7054 return 1;
7055 }
7056 dict = _PyObject_GetManagedDict(obj);
7057 }
7058 else if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
7059 dict = _PyObject_GetManagedDict(obj);
7060 }
7061 else {
7062 PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
7063 dict = (PyDictObject *)*dictptr;
7064 }
7065 if (dict == NULL) {
7066 return 1;
7067 }
7068 return FT_ATOMIC_LOAD_SSIZE_RELAXED(((PyDictObject *)dict)->ma_used) == 0;
7069 }
7070
7071 int
7072 PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
7073 {
7074 PyTypeObject *tp = Py_TYPE(obj);
7075 if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
7076 return 0;
7077 }
7078 if (tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
7079 PyDictValues *values = _PyObject_InlineValues(obj);
7080 if (values->valid) {
7081 for (Py_ssize_t i = 0; i < values->capacity; i++) {
7082 Py_VISIT(values->values[i]);
7083 }
7084 return 0;
7085 }
7086 }
7087 Py_VISIT(_PyObject_ManagedDictPointer(obj)->dict);
7088 return 0;
7089 }
7090
7091 static void
7092 set_dict_inline_values(PyObject *obj, PyDictObject *new_dict)
7093 {
7094 _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(obj);
7095
7096 PyDictValues *values = _PyObject_InlineValues(obj);
7097
7098 Py_XINCREF(new_dict);
7099 FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict, new_dict);
7100
7101 if (values->valid) {
7102 FT_ATOMIC_STORE_UINT8(values->valid, 0);
7103 for (Py_ssize_t i = 0; i < values->capacity; i++) {
7104 Py_CLEAR(values->values[i]);
7105 }
7106 }
7107 }
7108
7109 int
7110 _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
7111 {
7112 assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
7113 assert(_PyObject_InlineValuesConsistencyCheck(obj));
7114 int err = 0;
7115 PyTypeObject *tp = Py_TYPE(obj);
7116 if (tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
7117 PyDictObject *dict = _PyObject_GetManagedDict(obj);
7118 if (dict == NULL) {
7119 #ifdef Py_GIL_DISABLED
7120 Py_BEGIN_CRITICAL_SECTION(obj);
7121
7122 dict = _PyObject_ManagedDictPointer(obj)->dict;
7123 if (dict == NULL) {
7124 set_dict_inline_values(obj, (PyDictObject *)new_dict);
7125 }
7126
7127 Py_END_CRITICAL_SECTION();
7128
7129 if (dict == NULL) {
7130 return 0;
7131 }
7132 #else
7133 set_dict_inline_values(obj, (PyDictObject *)new_dict);
7134 return 0;
7135 #endif
7136 }
7137
7138 Py_BEGIN_CRITICAL_SECTION2(dict, obj);
7139
7140 // We've locked dict, but the actual dict could have changed
7141 // since we locked it.
7142 dict = _PyObject_ManagedDictPointer(obj)->dict;
7143 err = _PyDict_DetachFromObject(dict, obj);
7144 if (err == 0) {
7145 FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict,
7146 (PyDictObject *)Py_XNewRef(new_dict));
7147 }
7148 Py_END_CRITICAL_SECTION2();
7149
7150 if (err == 0) {
7151 Py_XDECREF(dict);
7152 }
7153 }
7154 else {
7155 PyDictObject *dict;
7156
7157 Py_BEGIN_CRITICAL_SECTION(obj);
7158
7159 dict = _PyObject_ManagedDictPointer(obj)->dict;
7160
7161 FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict,
7162 (PyDictObject *)Py_XNewRef(new_dict));
7163
7164 Py_END_CRITICAL_SECTION();
7165
7166 Py_XDECREF(dict);
7167 }
7168 assert(_PyObject_InlineValuesConsistencyCheck(obj));
7169 return err;
7170 }
7171
7172 void
7173 PyObject_ClearManagedDict(PyObject *obj)
7174 {
7175 if (_PyObject_SetManagedDict(obj, NULL) < 0) {
7176 PyErr_WriteUnraisable(NULL);
7177 }
7178 }
7179
7180 int
7181 _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
7182 {
7183 ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(obj);
7184 assert(_PyObject_ManagedDictPointer(obj)->dict == mp);
7185 assert(_PyObject_InlineValuesConsistencyCheck(obj));
7186
7187 if (FT_ATOMIC_LOAD_PTR_RELAXED(mp->ma_values) != _PyObject_InlineValues(obj)) {
7188 return 0;
7189 }
7190
7191 // We could be called with an unlocked dict when the caller knows the
7192 // values are already detached, so we assert after inline values check.
7193 ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(mp);
7194 assert(mp->ma_values->embedded == 1);
7195 assert(mp->ma_values->valid == 1);
7196 assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_INLINE_VALUES);
7197
7198 PyDictValues *values = copy_values(mp->ma_values);
7199
7200 if (values == NULL) {
7201 /* Out of memory. Clear the dict */
7202 PyInterpreterState *interp = _PyInterpreterState_GET();
7203 PyDictKeysObject *oldkeys = mp->ma_keys;
7204 set_keys(mp, Py_EMPTY_KEYS);
7205 dictkeys_decref(interp, oldkeys, IS_DICT_SHARED(mp));
7206 STORE_USED(mp, 0);
7207 PyErr_NoMemory();
7208 return -1;
7209 }
7210 mp->ma_values = values;
7211
7212 FT_ATOMIC_STORE_UINT8(_PyObject_InlineValues(obj)->valid, 0);
7213
7214 assert(_PyObject_InlineValuesConsistencyCheck(obj));
7215 ASSERT_CONSISTENT(mp);
7216 return 0;
7217 }
7218
7219 static inline PyObject *
7220 ensure_managed_dict(PyObject *obj)
7221 {
7222 PyDictObject *dict = _PyObject_GetManagedDict(obj);
7223 if (dict == NULL) {
7224 PyTypeObject *tp = Py_TYPE(obj);
7225 if ((tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) &&
7226 FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(obj)->valid)) {
7227 dict = _PyObject_MaterializeManagedDict(obj);
7228 }
7229 else {
7230 #ifdef Py_GIL_DISABLED
7231 // Check again that we're not racing with someone else creating the dict
7232 Py_BEGIN_CRITICAL_SECTION(obj);
7233 dict = _PyObject_GetManagedDict(obj);
7234 if (dict != NULL) {
7235 goto done;
7236 }
7237 #endif
7238 dict = (PyDictObject *)new_dict_with_shared_keys(_PyInterpreterState_GET(),
7239 CACHED_KEYS(tp));
7240 FT_ATOMIC_STORE_PTR_RELEASE(_PyObject_ManagedDictPointer(obj)->dict,
7241 (PyDictObject *)dict);
7242
7243 #ifdef Py_GIL_DISABLED
7244 done:
7245 Py_END_CRITICAL_SECTION();
7246 #endif
7247 }
7248 }
7249 return (PyObject *)dict;
7250 }
7251
7252 static inline PyObject *
7253 ensure_nonmanaged_dict(PyObject *obj, PyObject **dictptr)
7254 {
7255 PyDictKeysObject *cached;
7256
7257 PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*dictptr);
7258 if (dict == NULL) {
7259 #ifdef Py_GIL_DISABLED
7260 Py_BEGIN_CRITICAL_SECTION(obj);
7261 dict = *dictptr;
7262 if (dict != NULL) {
7263 goto done;
7264 }
7265 #endif
7266 PyTypeObject *tp = Py_TYPE(obj);
7267 if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && (cached = CACHED_KEYS(tp))) {
7268 PyInterpreterState *interp = _PyInterpreterState_GET();
7269 assert(!_PyType_HasFeature(tp, Py_TPFLAGS_INLINE_VALUES));
7270 dict = new_dict_with_shared_keys(interp, cached);
7271 }
7272 else {
7273 dict = PyDict_New();
7274 }
7275 FT_ATOMIC_STORE_PTR_RELEASE(*dictptr, dict);
7276 #ifdef Py_GIL_DISABLED
7277 done:
7278 Py_END_CRITICAL_SECTION();
7279 #endif
7280 }
7281 return dict;
7282 }
7283
7284 PyObject *
7285 PyObject_GenericGetDict(PyObject *obj, void *context)
7286 {
7287 PyTypeObject *tp = Py_TYPE(obj);
7288 if (_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT)) {
7289 return Py_XNewRef(ensure_managed_dict(obj));
7290 }
7291 else {
7292 PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
7293 if (dictptr == NULL) {
7294 PyErr_SetString(PyExc_AttributeError,
7295 "This object has no __dict__");
7296 return NULL;
7297 }
7298
7299 return Py_XNewRef(ensure_nonmanaged_dict(obj, dictptr));
7300 }
7301 }
7302
7303 int
7304 _PyObjectDict_SetItem(PyTypeObject *tp, PyObject *obj, PyObject **dictptr,
7305 PyObject *key, PyObject *value)
7306 {
7307 PyObject *dict;
7308 int res;
7309
7310 assert(dictptr != NULL);
7311 dict = ensure_nonmanaged_dict(obj, dictptr);
7312 if (dict == NULL) {
7313 return -1;
7314 }
7315
7316 Py_BEGIN_CRITICAL_SECTION(dict);
7317 res = _PyDict_SetItem_LockHeld((PyDictObject *)dict, key, value);
7318 ASSERT_CONSISTENT(dict);
7319 Py_END_CRITICAL_SECTION();
7320 return res;
7321 }
7322
7323 void
7324 _PyDictKeys_DecRef(PyDictKeysObject *keys)
7325 {
7326 PyInterpreterState *interp = _PyInterpreterState_GET();
7327 dictkeys_decref(interp, keys, false);
7328 }
7329
7330 uint32_t _PyDictKeys_GetVersionForCurrentState(PyInterpreterState *interp,
7331 PyDictKeysObject *dictkeys)
7332 {
7333 if (dictkeys->dk_version != 0) {
7334 return dictkeys->dk_version;
7335 }
7336 if (interp->dict_state.next_keys_version == 0) {
7337 return 0;
7338 }
7339 uint32_t v = interp->dict_state.next_keys_version++;
7340 dictkeys->dk_version = v;
7341 return v;
7342 }
7343
7344 static inline int
7345 validate_watcher_id(PyInterpreterState *interp, int watcher_id)
7346 {
7347 if (watcher_id < 0 || watcher_id >= DICT_MAX_WATCHERS) {
7348 PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id);
7349 return -1;
7350 }
7351 if (!interp->dict_state.watchers[watcher_id]) {
7352 PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id);
7353 return -1;
7354 }
7355 return 0;
7356 }
7357
7358 int
7359 PyDict_Watch(int watcher_id, PyObject* dict)
7360 {
7361 if (!PyDict_Check(dict)) {
7362 PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary");
7363 return -1;
7364 }
7365 PyInterpreterState *interp = _PyInterpreterState_GET();
7366 if (validate_watcher_id(interp, watcher_id)) {
7367 return -1;
7368 }
7369 ((PyDictObject*)dict)->ma_version_tag |= (1LL << watcher_id);
7370 return 0;
7371 }
7372
7373 int
7374 PyDict_Unwatch(int watcher_id, PyObject* dict)
7375 {
7376 if (!PyDict_Check(dict)) {
7377 PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary");
7378 return -1;
7379 }
7380 PyInterpreterState *interp = _PyInterpreterState_GET();
7381 if (validate_watcher_id(interp, watcher_id)) {
7382 return -1;
7383 }
7384 ((PyDictObject*)dict)->ma_version_tag &= ~(1LL << watcher_id);
7385 return 0;
7386 }
7387
7388 int
7389 PyDict_AddWatcher(PyDict_WatchCallback callback)
7390 {
7391 PyInterpreterState *interp = _PyInterpreterState_GET();
7392
7393 /* Start at 2, as 0 and 1 are reserved for CPython */
7394 for (int i = 2; i < DICT_MAX_WATCHERS; i++) {
7395 if (!interp->dict_state.watchers[i]) {
7396 interp->dict_state.watchers[i] = callback;
7397 return i;
7398 }
7399 }
7400
7401 PyErr_SetString(PyExc_RuntimeError, "no more dict watcher IDs available");
7402 return -1;
7403 }
7404
7405 int
7406 PyDict_ClearWatcher(int watcher_id)
7407 {
7408 PyInterpreterState *interp = _PyInterpreterState_GET();
7409 if (validate_watcher_id(interp, watcher_id)) {
7410 return -1;
7411 }
7412 interp->dict_state.watchers[watcher_id] = NULL;
7413 return 0;
7414 }
7415
7416 static const char *
7417 dict_event_name(PyDict_WatchEvent event) {
7418 switch (event) {
7419 #define CASE(op) \
7420 case PyDict_EVENT_##op: \
7421 return "PyDict_EVENT_" #op;
7422 PY_FOREACH_DICT_EVENT(CASE)
7423 #undef CASE
7424 }
7425 Py_UNREACHABLE();
7426 }
7427
7428 void
7429 _PyDict_SendEvent(int watcher_bits,
7430 PyDict_WatchEvent event,
7431 PyDictObject *mp,
7432 PyObject *key,
7433 PyObject *value)
7434 {
7435 PyInterpreterState *interp = _PyInterpreterState_GET();
7436 for (int i = 0; i < DICT_MAX_WATCHERS; i++) {
7437 if (watcher_bits & 1) {
7438 PyDict_WatchCallback cb = interp->dict_state.watchers[i];
7439 if (cb && (cb(event, (PyObject*)mp, key, value) < 0)) {
7440 // We don't want to resurrect the dict by potentially having an
7441 // unraisablehook keep a reference to it, so we don't pass the
7442 // dict as context, just an informative string message. Dict
7443 // repr can call arbitrary code, so we invent a simpler version.
7444 PyErr_FormatUnraisable(
7445 "Exception ignored in %s watcher callback for <dict at %p>",
7446 dict_event_name(event), mp);
7447 }
7448 }
7449 watcher_bits >>= 1;
7450 }
7451 }
7452
7453 #ifndef NDEBUG
7454 static int
7455 _PyObject_InlineValuesConsistencyCheck(PyObject *obj)
7456 {
7457 if ((Py_TYPE(obj)->tp_flags & Py_TPFLAGS_INLINE_VALUES) == 0) {
7458 return 1;
7459 }
7460 assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
7461 PyDictObject *dict = _PyObject_GetManagedDict(obj);
7462 if (dict == NULL) {
7463 return 1;
7464 }
7465 if (dict->ma_values == _PyObject_InlineValues(obj) ||
7466 _PyObject_InlineValues(obj)->valid == 0) {
7467 return 1;
7468 }
7469 assert(0);
7470 return 0;
7471 }
7472 #endif
7473