Coverage Report

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