Coverage Report

Created: 2026-05-30 06:18

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