• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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