Coverage Report

Created: 2025-11-30 06:38

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