Coverage Report

Created: 2026-06-21 06:15

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