Coverage Report

Created: 2025-08-24 07:03

/src/cpython/Objects/dictobject.c
Line
Count
Source (jump to first uncovered line)
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
196M
#define PyDict_LOG_MINSIZE 3
116
29.7M
#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.76M
#define STORE_SHARED_KEY(key, value) key = value
242
697k
#define INCREF_KEYS(dk)  dk->dk_refcnt++
243
32.5M
#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
11.2M
#define IS_DICT_SHARED(mp) (false)
250
#define SET_DICT_SHARED(mp)
251
3.72G
#define LOAD_INDEX(keys, size, idx) ((const int##size##_t*)(keys->dk_indices))[idx]
252
728M
#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.76M
{
256
1.76M
    keys->dk_usable--;
257
1.76M
    keys->dk_nentries++;
258
1.76M
}
259
260
static inline void
261
set_keys(PyDictObject *mp, PyDictKeysObject *keys)
262
11.8M
{
263
11.8M
    mp->ma_keys = keys;
264
11.8M
}
265
266
static inline void
267
set_values(PyDictObject *mp, PyDictValues *values)
268
694k
{
269
694k
    mp->ma_values = values;
270
694k
}
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
307M
#define STORE_KEY(ep, key) FT_ATOMIC_STORE_PTR_RELEASE((ep)->me_key, key)
282
424M
#define STORE_VALUE(ep, value) FT_ATOMIC_STORE_PTR_RELEASE((ep)->me_value, value)
283
9.70k
#define STORE_SPLIT_VALUE(mp, idx, value) FT_ATOMIC_STORE_PTR_RELEASE(mp->ma_values->values[idx], value)
284
286M
#define STORE_HASH(ep, hash) FT_ATOMIC_STORE_SSIZE_RELAXED((ep)->me_hash, hash)
285
315M
#define STORE_KEYS_USABLE(keys, usable) FT_ATOMIC_STORE_SSIZE_RELAXED(keys->dk_usable, usable)
286
315M
#define STORE_KEYS_NENTRIES(keys, nentries) FT_ATOMIC_STORE_SSIZE_RELAXED(keys->dk_nentries, nentries)
287
337M
#define STORE_USED(mp, used) FT_ATOMIC_STORE_SSIZE_RELAXED(mp->ma_used, used)
288
289
1.38G
#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
566M
{
403
566M
    assert(PyUnicode_CheckExact(o));
404
566M
    return FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyASCIIObject_CAST(o)->hash);
405
566M
}
406
407
/* Print summary info about the state of the optimized allocator */
408
void
409
_PyDict_DebugMallocStats(FILE *out)
410
0
{
411
0
    _PyDebugAllocatorStats(out, "free PyDictObject",
412
0
                           _Py_FREELIST_SIZE(dicts),
413
0
                           sizeof(PyDictObject));
414
0
    _PyDebugAllocatorStats(out, "free PyDictKeysObject",
415
0
                           _Py_FREELIST_SIZE(dictkeys),
416
0
                           sizeof(PyDictKeysObject));
417
0
}
418
419
1.95G
#define DK_MASK(dk) (DK_SIZE(dk)-1)
420
421
#define _Py_DICT_IMMORTAL_INITIAL_REFCNT PY_SSIZE_T_MIN
422
423
static void free_keys_object(PyDictKeysObject *keys, bool use_qsbr);
424
425
/* PyDictKeysObject has refcounts like PyObject does, so we have the
426
   following two functions to mirror what Py_INCREF() and Py_DECREF() do.
427
   (Keep in mind that PyDictKeysObject isn't actually a PyObject.)
428
   Likewise a PyDictKeysObject can be immortal (e.g. Py_EMPTY_KEYS),
429
   so we apply a naive version of what Py_INCREF() and Py_DECREF() do
430
   for immortal objects. */
431
432
static inline void
433
dictkeys_incref(PyDictKeysObject *dk)
434
697k
{
435
697k
    if (FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_refcnt) < 0) {
436
0
        assert(FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_refcnt) == _Py_DICT_IMMORTAL_INITIAL_REFCNT);
437
0
        return;
438
0
    }
439
#ifdef Py_REF_DEBUG
440
    _Py_IncRefTotal(_PyThreadState_GET());
441
#endif
442
697k
    INCREF_KEYS(dk);
443
697k
}
444
445
static inline void
446
dictkeys_decref(PyDictKeysObject *dk, bool use_qsbr)
447
313M
{
448
313M
    if (FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_refcnt) < 0) {
449
280M
        assert(FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_refcnt) == _Py_DICT_IMMORTAL_INITIAL_REFCNT);
450
280M
        return;
451
280M
    }
452
32.5M
    assert(FT_ATOMIC_LOAD_SSIZE(dk->dk_refcnt) > 0);
453
#ifdef Py_REF_DEBUG
454
    _Py_DecRefTotal(_PyThreadState_GET());
455
#endif
456
32.5M
    if (DECREF_KEYS(dk) == 1) {
457
31.8M
        if (DK_IS_UNICODE(dk)) {
458
20.7M
            PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dk);
459
20.7M
            Py_ssize_t i, n;
460
61.9M
            for (i = 0, n = dk->dk_nentries; i < n; i++) {
461
41.1M
                Py_XDECREF(entries[i].me_key);
462
41.1M
                Py_XDECREF(entries[i].me_value);
463
41.1M
            }
464
20.7M
        }
465
11.1M
        else {
466
11.1M
            PyDictKeyEntry *entries = DK_ENTRIES(dk);
467
11.1M
            Py_ssize_t i, n;
468
306M
            for (i = 0, n = dk->dk_nentries; i < n; i++) {
469
295M
                Py_XDECREF(entries[i].me_key);
470
295M
                Py_XDECREF(entries[i].me_value);
471
295M
            }
472
11.1M
        }
473
31.8M
        free_keys_object(dk, use_qsbr);
474
31.8M
    }
475
32.5M
}
476
477
/* lookup indices.  returns DKIX_EMPTY, DKIX_DUMMY, or ix >=0 */
478
static inline Py_ssize_t
479
dictkeys_get_index(const PyDictKeysObject *keys, Py_ssize_t i)
480
3.72G
{
481
3.72G
    int log2size = DK_LOG_SIZE(keys);
482
3.72G
    Py_ssize_t ix;
483
484
3.72G
    if (log2size < 8) {
485
2.26G
        ix = LOAD_INDEX(keys, 8, i);
486
2.26G
    }
487
1.45G
    else if (log2size < 16) {
488
1.44G
        ix = LOAD_INDEX(keys, 16, i);
489
1.44G
    }
490
8.93M
#if SIZEOF_VOID_P > 4
491
8.93M
    else if (log2size >= 32) {
492
0
        ix = LOAD_INDEX(keys, 64, i);
493
0
    }
494
8.93M
#endif
495
8.93M
    else {
496
8.93M
        ix = LOAD_INDEX(keys, 32, i);
497
8.93M
    }
498
3.72G
    assert(ix >= DKIX_DUMMY);
499
3.72G
    return ix;
500
3.72G
}
501
502
/* write to indices. */
503
static inline void
504
dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix)
505
728M
{
506
728M
    int log2size = DK_LOG_SIZE(keys);
507
508
728M
    assert(ix >= DKIX_DUMMY);
509
728M
    assert(keys->dk_version == 0);
510
511
728M
    if (log2size < 8) {
512
264M
        assert(ix <= 0x7f);
513
264M
        STORE_INDEX(keys, 8, i, ix);
514
264M
    }
515
464M
    else if (log2size < 16) {
516
462M
        assert(ix <= 0x7fff);
517
462M
        STORE_INDEX(keys, 16, i, ix);
518
462M
    }
519
1.94M
#if SIZEOF_VOID_P > 4
520
1.94M
    else if (log2size >= 32) {
521
0
        STORE_INDEX(keys, 64, i, ix);
522
0
    }
523
1.94M
#endif
524
1.94M
    else {
525
1.94M
        assert(ix <= 0x7fffffff);
526
1.94M
        STORE_INDEX(keys, 32, i, ix);
527
1.94M
    }
528
728M
}
529
530
531
/* USABLE_FRACTION is the maximum dictionary load.
532
 * Increasing this ratio makes dictionaries more dense resulting in more
533
 * collisions.  Decreasing it improves sparseness at the expense of spreading
534
 * indices over more cache lines and at the cost of total memory consumed.
535
 *
536
 * USABLE_FRACTION must obey the following:
537
 *     (0 < USABLE_FRACTION(n) < n) for all n >= 2
538
 *
539
 * USABLE_FRACTION should be quick to calculate.
540
 * Fractions around 1/2 to 2/3 seem to work well in practice.
541
 */
542
323M
#define USABLE_FRACTION(n) (((n) << 1)/3)
543
544
/* Find the smallest dk_size >= minsize. */
545
static inline uint8_t
546
calculate_log2_keysize(Py_ssize_t minsize)
547
11.2M
{
548
11.2M
#if SIZEOF_LONG == SIZEOF_SIZE_T
549
11.2M
    minsize = Py_MAX(minsize, PyDict_MINSIZE);
550
11.2M
    return _Py_bit_length(minsize - 1);
551
#elif defined(_MSC_VER)
552
    // On 64bit Windows, sizeof(long) == 4. We cannot use _Py_bit_length.
553
    minsize = Py_MAX(minsize, PyDict_MINSIZE);
554
    unsigned long msb;
555
    _BitScanReverse64(&msb, (uint64_t)minsize - 1);
556
    return (uint8_t)(msb + 1);
557
#else
558
    uint8_t log2_size;
559
    for (log2_size = PyDict_LOG_MINSIZE;
560
            (((Py_ssize_t)1) << log2_size) < minsize;
561
            log2_size++)
562
        ;
563
    return log2_size;
564
#endif
565
11.2M
}
566
567
/* estimate_keysize is reverse function of USABLE_FRACTION.
568
 *
569
 * This can be used to reserve enough size to insert n entries without
570
 * resizing.
571
 */
572
static inline uint8_t
573
estimate_log2_keysize(Py_ssize_t n)
574
588k
{
575
588k
    return calculate_log2_keysize((n*3 + 1) / 2);
576
588k
}
577
578
579
/* GROWTH_RATE. Growth rate upon hitting maximum load.
580
 * Currently set to used*3.
581
 * This means that dicts double in size when growing without deletions,
582
 * but have more head room when the number of deletions is on a par with the
583
 * number of insertions.  See also bpo-17563 and bpo-33205.
584
 *
585
 * GROWTH_RATE was set to used*4 up to version 3.2.
586
 * GROWTH_RATE was set to used*2 in version 3.3.0
587
 * GROWTH_RATE was set to used*2 + capacity/2 in 3.4.0-3.6.0.
588
 */
589
10.6M
#define GROWTH_RATE(d) ((d)->ma_used*3)
590
591
/* This immutable, empty PyDictKeysObject is used for PyDict_Clear()
592
 * (which cannot fail and thus can do no allocation).
593
 *
594
 * See https://github.com/python/cpython/pull/127568#discussion_r1868070614
595
 * for the rationale of using dk_log2_index_bytes=3 instead of 0.
596
 */
597
static PyDictKeysObject empty_keys_struct = {
598
        _Py_DICT_IMMORTAL_INITIAL_REFCNT, /* dk_refcnt */
599
        0, /* dk_log2_size */
600
        3, /* dk_log2_index_bytes */
601
        DICT_KEYS_UNICODE, /* dk_kind */
602
#ifdef Py_GIL_DISABLED
603
        {0}, /* dk_mutex */
604
#endif
605
        1, /* dk_version */
606
        0, /* dk_usable (immutable) */
607
        0, /* dk_nentries */
608
        {DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY,
609
         DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY}, /* dk_indices */
610
};
611
612
852M
#define Py_EMPTY_KEYS &empty_keys_struct
613
614
/* Uncomment to check the dict content in _PyDict_CheckConsistency() */
615
// #define DEBUG_PYDICT
616
617
#ifdef DEBUG_PYDICT
618
#  define ASSERT_CONSISTENT(op) assert(_PyDict_CheckConsistency((PyObject *)(op), 1))
619
#else
620
861M
#  define ASSERT_CONSISTENT(op) assert(_PyDict_CheckConsistency((PyObject *)(op), 0))
621
#endif
622
623
static inline int
624
get_index_from_order(PyDictObject *mp, Py_ssize_t i)
625
1.10M
{
626
1.10M
    assert(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
627
1.10M
    assert(i < mp->ma_values->size);
628
1.10M
    uint8_t *array = get_insertion_order_array(mp->ma_values);
629
1.10M
    return array[i];
630
1.10M
}
631
632
#ifdef DEBUG_PYDICT
633
static void
634
dump_entries(PyDictKeysObject *dk)
635
{
636
    for (Py_ssize_t i = 0; i < dk->dk_nentries; i++) {
637
        if (DK_IS_UNICODE(dk)) {
638
            PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(dk)[i];
639
            printf("key=%p value=%p\n", ep->me_key, ep->me_value);
640
        }
641
        else {
642
            PyDictKeyEntry *ep = &DK_ENTRIES(dk)[i];
643
            printf("key=%p hash=%lx value=%p\n", ep->me_key, ep->me_hash, ep->me_value);
644
        }
645
    }
646
}
647
#endif
648
649
int
650
_PyDict_CheckConsistency(PyObject *op, int check_content)
651
0
{
652
0
    ASSERT_WORLD_STOPPED_OR_DICT_LOCKED(op);
653
654
0
#define CHECK(expr) \
655
0
    do { if (!(expr)) { _PyObject_ASSERT_FAILED_MSG(op, Py_STRINGIFY(expr)); } } while (0)
656
657
0
    assert(op != NULL);
658
0
    CHECK(PyDict_Check(op));
659
0
    PyDictObject *mp = (PyDictObject *)op;
660
661
0
    PyDictKeysObject *keys = mp->ma_keys;
662
0
    int splitted = _PyDict_HasSplitTable(mp);
663
0
    Py_ssize_t usable = USABLE_FRACTION(DK_SIZE(keys));
664
665
    // In the free-threaded build, shared keys may be concurrently modified,
666
    // so use atomic loads.
667
0
    Py_ssize_t dk_usable = FT_ATOMIC_LOAD_SSIZE_ACQUIRE(keys->dk_usable);
668
0
    Py_ssize_t dk_nentries = FT_ATOMIC_LOAD_SSIZE_ACQUIRE(keys->dk_nentries);
669
670
0
    CHECK(0 <= mp->ma_used && mp->ma_used <= usable);
671
0
    CHECK(0 <= dk_usable && dk_usable <= usable);
672
0
    CHECK(0 <= dk_nentries && dk_nentries <= usable);
673
0
    CHECK(dk_usable + dk_nentries <= usable);
674
675
0
    if (!splitted) {
676
        /* combined table */
677
0
        CHECK(keys->dk_kind != DICT_KEYS_SPLIT);
678
0
        CHECK(keys->dk_refcnt == 1 || keys == Py_EMPTY_KEYS);
679
0
    }
680
0
    else {
681
0
        CHECK(keys->dk_kind == DICT_KEYS_SPLIT);
682
0
        CHECK(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
683
0
        if (mp->ma_values->embedded) {
684
0
            CHECK(mp->ma_values->embedded == 1);
685
0
            CHECK(mp->ma_values->valid == 1);
686
0
        }
687
0
    }
688
689
0
    if (check_content) {
690
0
        LOCK_KEYS_IF_SPLIT(keys, keys->dk_kind);
691
0
        for (Py_ssize_t i=0; i < DK_SIZE(keys); i++) {
692
0
            Py_ssize_t ix = dictkeys_get_index(keys, i);
693
0
            CHECK(DKIX_DUMMY <= ix && ix <= usable);
694
0
        }
695
696
0
        if (keys->dk_kind == DICT_KEYS_GENERAL) {
697
0
            PyDictKeyEntry *entries = DK_ENTRIES(keys);
698
0
            for (Py_ssize_t i=0; i < usable; i++) {
699
0
                PyDictKeyEntry *entry = &entries[i];
700
0
                PyObject *key = entry->me_key;
701
702
0
                if (key != NULL) {
703
                    /* test_dict fails if PyObject_Hash() is called again */
704
0
                    CHECK(entry->me_hash != -1);
705
0
                    CHECK(entry->me_value != NULL);
706
707
0
                    if (PyUnicode_CheckExact(key)) {
708
0
                        Py_hash_t hash = unicode_get_hash(key);
709
0
                        CHECK(entry->me_hash == hash);
710
0
                    }
711
0
                }
712
0
            }
713
0
        }
714
0
        else {
715
0
            PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
716
0
            for (Py_ssize_t i=0; i < usable; i++) {
717
0
                PyDictUnicodeEntry *entry = &entries[i];
718
0
                PyObject *key = entry->me_key;
719
720
0
                if (key != NULL) {
721
0
                    CHECK(PyUnicode_CheckExact(key));
722
0
                    Py_hash_t hash = unicode_get_hash(key);
723
0
                    CHECK(hash != -1);
724
0
                    if (!splitted) {
725
0
                        CHECK(entry->me_value != NULL);
726
0
                    }
727
0
                }
728
729
0
                if (splitted) {
730
0
                    CHECK(entry->me_value == NULL);
731
0
                }
732
0
            }
733
0
        }
734
735
0
        if (splitted) {
736
0
            CHECK(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
737
            /* splitted table */
738
0
            int duplicate_check = 0;
739
0
            for (Py_ssize_t i=0; i < mp->ma_used; i++) {
740
0
                int index = get_index_from_order(mp, i);
741
0
                CHECK((duplicate_check & (1<<index)) == 0);
742
0
                duplicate_check |= (1<<index);
743
0
                CHECK(mp->ma_values->values[index] != NULL);
744
0
            }
745
0
        }
746
0
        UNLOCK_KEYS_IF_SPLIT(keys, keys->dk_kind);
747
0
    }
748
0
    return 1;
749
750
0
#undef CHECK
751
0
}
752
753
754
static PyDictKeysObject*
755
new_keys_object(uint8_t log2_size, bool unicode)
756
41.2M
{
757
41.2M
    Py_ssize_t usable;
758
41.2M
    int log2_bytes;
759
41.2M
    size_t entry_size = unicode ? sizeof(PyDictUnicodeEntry) : sizeof(PyDictKeyEntry);
760
761
41.2M
    assert(log2_size >= PyDict_LOG_MINSIZE);
762
763
41.2M
    usable = USABLE_FRACTION((size_t)1<<log2_size);
764
41.2M
    if (log2_size < 8) {
765
40.4M
        log2_bytes = log2_size;
766
40.4M
    }
767
835k
    else if (log2_size < 16) {
768
835k
        log2_bytes = log2_size + 1;
769
835k
    }
770
35
#if SIZEOF_VOID_P > 4
771
35
    else if (log2_size >= 32) {
772
0
        log2_bytes = log2_size + 3;
773
0
    }
774
35
#endif
775
35
    else {
776
35
        log2_bytes = log2_size + 2;
777
35
    }
778
779
41.2M
    PyDictKeysObject *dk = NULL;
780
41.2M
    if (log2_size == PyDict_LOG_MINSIZE && unicode) {
781
19.8M
        dk = _Py_FREELIST_POP_MEM(dictkeys);
782
19.8M
    }
783
41.2M
    if (dk == NULL) {
784
28.6M
        dk = PyMem_Malloc(sizeof(PyDictKeysObject)
785
28.6M
                          + ((size_t)1 << log2_bytes)
786
28.6M
                          + entry_size * usable);
787
28.6M
        if (dk == NULL) {
788
0
            PyErr_NoMemory();
789
0
            return NULL;
790
0
        }
791
28.6M
    }
792
#ifdef Py_REF_DEBUG
793
    _Py_IncRefTotal(_PyThreadState_GET());
794
#endif
795
41.2M
    dk->dk_refcnt = 1;
796
41.2M
    dk->dk_log2_size = log2_size;
797
41.2M
    dk->dk_log2_index_bytes = log2_bytes;
798
41.2M
    dk->dk_kind = unicode ? DICT_KEYS_UNICODE : DICT_KEYS_GENERAL;
799
#ifdef Py_GIL_DISABLED
800
    dk->dk_mutex = (PyMutex){0};
801
#endif
802
41.2M
    dk->dk_nentries = 0;
803
41.2M
    dk->dk_usable = usable;
804
41.2M
    dk->dk_version = 0;
805
41.2M
    memset(&dk->dk_indices[0], 0xff, ((size_t)1 << log2_bytes));
806
41.2M
    memset(&dk->dk_indices[(size_t)1 << log2_bytes], 0, entry_size * usable);
807
41.2M
    return dk;
808
41.2M
}
809
810
static void
811
free_keys_object(PyDictKeysObject *keys, bool use_qsbr)
812
41.8M
{
813
#ifdef Py_GIL_DISABLED
814
    if (use_qsbr) {
815
        _PyMem_FreeDelayed(keys, _PyDict_KeysSize(keys));
816
        return;
817
    }
818
#endif
819
41.8M
    if (DK_LOG_SIZE(keys) == PyDict_LOG_MINSIZE && keys->dk_kind == DICT_KEYS_UNICODE) {
820
20.4M
        _Py_FREELIST_FREE(dictkeys, keys, PyMem_Free);
821
20.4M
    }
822
21.3M
    else {
823
21.3M
        PyMem_Free(keys);
824
21.3M
    }
825
41.8M
}
826
827
static size_t
828
values_size_from_count(size_t count)
829
2.71k
{
830
2.71k
    assert(count >= 1);
831
2.71k
    size_t suffix_size = _Py_SIZE_ROUND_UP(count, sizeof(PyObject *));
832
2.71k
    assert(suffix_size < 128);
833
2.71k
    assert(suffix_size % sizeof(PyObject *) == 0);
834
2.71k
    return (count + 1) * sizeof(PyObject *) + suffix_size;
835
2.71k
}
836
837
98.6M
#define CACHED_KEYS(tp) (((PyHeapTypeObject*)tp)->ht_cached_keys)
838
839
static inline PyDictValues*
840
new_values(size_t size)
841
2.71k
{
842
2.71k
    size_t n = values_size_from_count(size);
843
2.71k
    PyDictValues *res = (PyDictValues *)PyMem_Malloc(n);
844
2.71k
    if (res == NULL) {
845
0
        return NULL;
846
0
    }
847
2.71k
    res->embedded = 0;
848
2.71k
    res->size = 0;
849
2.71k
    assert(size < 256);
850
2.71k
    res->capacity = (uint8_t)size;
851
2.71k
    return res;
852
2.71k
}
853
854
static inline void
855
free_values(PyDictValues *values, bool use_qsbr)
856
117
{
857
117
    assert(values->embedded == 0);
858
#ifdef Py_GIL_DISABLED
859
    if (use_qsbr) {
860
        _PyMem_FreeDelayed(values, values_size_from_count(values->capacity));
861
        return;
862
    }
863
#endif
864
117
    PyMem_Free(values);
865
117
}
866
867
/* Consumes a reference to the keys object */
868
static PyObject *
869
new_dict(PyDictKeysObject *keys, PyDictValues *values,
870
         Py_ssize_t used, int free_values_on_failure)
871
311M
{
872
311M
    assert(keys != NULL);
873
311M
    PyDictObject *mp = _Py_FREELIST_POP(PyDictObject, dicts);
874
311M
    if (mp == NULL) {
875
8.91M
        mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
876
8.91M
        if (mp == NULL) {
877
0
            dictkeys_decref(keys, false);
878
0
            if (free_values_on_failure) {
879
0
                free_values(values, false);
880
0
            }
881
0
            return NULL;
882
0
        }
883
8.91M
    }
884
311M
    assert(Py_IS_TYPE(mp, &PyDict_Type));
885
311M
    mp->ma_keys = keys;
886
311M
    mp->ma_values = values;
887
311M
    mp->ma_used = used;
888
311M
    mp->_ma_watcher_tag = 0;
889
311M
    ASSERT_CONSISTENT(mp);
890
311M
    _PyObject_GC_TRACK(mp);
891
311M
    return (PyObject *)mp;
892
311M
}
893
894
static PyObject *
895
new_dict_with_shared_keys(PyDictKeysObject *keys)
896
2.71k
{
897
2.71k
    size_t size = shared_keys_usable_size(keys);
898
2.71k
    PyDictValues *values = new_values(size);
899
2.71k
    if (values == NULL) {
900
0
        return PyErr_NoMemory();
901
0
    }
902
2.71k
    dictkeys_incref(keys);
903
84.0k
    for (size_t i = 0; i < size; i++) {
904
81.3k
        values->values[i] = NULL;
905
81.3k
    }
906
2.71k
    return new_dict(keys, values, 0, 1);
907
2.71k
}
908
909
910
static PyDictKeysObject *
911
clone_combined_dict_keys(PyDictObject *orig)
912
605k
{
913
605k
    assert(PyDict_Check(orig));
914
605k
    assert(Py_TYPE(orig)->tp_iter == dict_iter);
915
605k
    assert(orig->ma_values == NULL);
916
605k
    assert(orig->ma_keys != Py_EMPTY_KEYS);
917
605k
    assert(orig->ma_keys->dk_refcnt == 1);
918
919
605k
    ASSERT_DICT_LOCKED(orig);
920
921
605k
    size_t keys_size = _PyDict_KeysSize(orig->ma_keys);
922
605k
    PyDictKeysObject *keys = PyMem_Malloc(keys_size);
923
605k
    if (keys == NULL) {
924
0
        PyErr_NoMemory();
925
0
        return NULL;
926
0
    }
927
928
605k
    memcpy(keys, orig->ma_keys, keys_size);
929
930
    /* After copying key/value pairs, we need to incref all
931
       keys and values and they are about to be co-owned by a
932
       new dict object. */
933
605k
    PyObject **pkey, **pvalue;
934
605k
    size_t offs;
935
605k
    if (DK_IS_UNICODE(orig->ma_keys)) {
936
605k
        PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(keys);
937
605k
        pkey = &ep0->me_key;
938
605k
        pvalue = &ep0->me_value;
939
605k
        offs = sizeof(PyDictUnicodeEntry) / sizeof(PyObject*);
940
605k
    }
941
0
    else {
942
0
        PyDictKeyEntry *ep0 = DK_ENTRIES(keys);
943
0
        pkey = &ep0->me_key;
944
0
        pvalue = &ep0->me_value;
945
0
        offs = sizeof(PyDictKeyEntry) / sizeof(PyObject*);
946
0
    }
947
948
605k
    Py_ssize_t n = keys->dk_nentries;
949
2.19M
    for (Py_ssize_t i = 0; i < n; i++) {
950
1.59M
        PyObject *value = *pvalue;
951
1.59M
        if (value != NULL) {
952
1.58M
            Py_INCREF(value);
953
1.58M
            Py_INCREF(*pkey);
954
1.58M
        }
955
1.59M
        pvalue += offs;
956
1.59M
        pkey += offs;
957
1.59M
    }
958
959
    /* Since we copied the keys table we now have an extra reference
960
       in the system.  Manually call increment _Py_RefTotal to signal that
961
       we have it now; calling dictkeys_incref would be an error as
962
       keys->dk_refcnt is already set to 1 (after memcpy). */
963
#ifdef Py_REF_DEBUG
964
    _Py_IncRefTotal(_PyThreadState_GET());
965
#endif
966
605k
    return keys;
967
605k
}
968
969
PyObject *
970
PyDict_New(void)
971
310M
{
972
    /* We don't incref Py_EMPTY_KEYS here because it is immortal. */
973
310M
    return new_dict(Py_EMPTY_KEYS, NULL, 0, 0);
974
310M
}
975
976
/* Search index of hash table from offset of entry table */
977
static Py_ssize_t
978
lookdict_index(PyDictKeysObject *k, Py_hash_t hash, Py_ssize_t index)
979
3.23M
{
980
3.23M
    size_t mask = DK_MASK(k);
981
3.23M
    size_t perturb = (size_t)hash;
982
3.23M
    size_t i = (size_t)hash & mask;
983
984
6.13M
    for (;;) {
985
6.13M
        Py_ssize_t ix = dictkeys_get_index(k, i);
986
6.13M
        if (ix == index) {
987
3.23M
            return i;
988
3.23M
        }
989
2.90M
        if (ix == DKIX_EMPTY) {
990
0
            return DKIX_EMPTY;
991
0
        }
992
2.90M
        perturb >>= PERTURB_SHIFT;
993
2.90M
        i = mask & (i*5 + perturb + 1);
994
2.90M
    }
995
3.23M
    Py_UNREACHABLE();
996
3.23M
}
997
998
static inline Py_ALWAYS_INLINE Py_ssize_t
999
do_lookup(PyDictObject *mp, PyDictKeysObject *dk, PyObject *key, Py_hash_t hash,
1000
          int (*check_lookup)(PyDictObject *, PyDictKeysObject *, void *, Py_ssize_t ix, PyObject *key, Py_hash_t))
1001
1.63G
{
1002
1.63G
    void *ep0 = _DK_ENTRIES(dk);
1003
1.63G
    size_t mask = DK_MASK(dk);
1004
1.63G
    size_t perturb = hash;
1005
1.63G
    size_t i = (size_t)hash & mask;
1006
1.63G
    Py_ssize_t ix;
1007
1.98G
    for (;;) {
1008
1.98G
        ix = dictkeys_get_index(dk, i);
1009
1.98G
        if (ix >= 0) {
1010
1.08G
            int cmp = check_lookup(mp, dk, ep0, ix, key, hash);
1011
1.08G
            if (cmp < 0) {
1012
0
                return cmp;
1013
1.08G
            } else if (cmp) {
1014
610M
                return ix;
1015
610M
            }
1016
1.08G
        }
1017
895M
        else if (ix == DKIX_EMPTY) {
1018
640M
            return DKIX_EMPTY;
1019
640M
        }
1020
731M
        perturb >>= PERTURB_SHIFT;
1021
731M
        i = mask & (i*5 + perturb + 1);
1022
1023
        // Manual loop unrolling
1024
731M
        ix = dictkeys_get_index(dk, i);
1025
731M
        if (ix >= 0) {
1026
351M
            int cmp = check_lookup(mp, dk, ep0, ix, key, hash);
1027
351M
            if (cmp < 0) {
1028
0
                return cmp;
1029
351M
            } else if (cmp) {
1030
46.8M
                return ix;
1031
46.8M
            }
1032
351M
        }
1033
379M
        else if (ix == DKIX_EMPTY) {
1034
335M
            return DKIX_EMPTY;
1035
335M
        }
1036
348M
        perturb >>= PERTURB_SHIFT;
1037
348M
        i = mask & (i*5 + perturb + 1);
1038
348M
    }
1039
1.63G
    Py_UNREACHABLE();
1040
1.63G
}
1041
1042
static inline int
1043
compare_unicode_generic(PyDictObject *mp, PyDictKeysObject *dk,
1044
                        void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
1045
1.30k
{
1046
1.30k
    PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
1047
1.30k
    assert(ep->me_key != NULL);
1048
1.30k
    assert(PyUnicode_CheckExact(ep->me_key));
1049
1.30k
    assert(!PyUnicode_CheckExact(key));
1050
1051
1.30k
    if (unicode_get_hash(ep->me_key) == hash) {
1052
10
        PyObject *startkey = ep->me_key;
1053
10
        Py_INCREF(startkey);
1054
10
        int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
1055
10
        Py_DECREF(startkey);
1056
10
        if (cmp < 0) {
1057
0
            return DKIX_ERROR;
1058
0
        }
1059
10
        if (dk == mp->ma_keys && ep->me_key == startkey) {
1060
10
            return cmp;
1061
10
        }
1062
0
        else {
1063
            /* The dict was mutated, restart */
1064
0
            return DKIX_KEY_CHANGED;
1065
0
        }
1066
10
    }
1067
1.29k
    return 0;
1068
1.30k
}
1069
1070
// Search non-Unicode key from Unicode table
1071
static Py_ssize_t
1072
unicodekeys_lookup_generic(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1073
95.5M
{
1074
95.5M
    return do_lookup(mp, dk, key, hash, compare_unicode_generic);
1075
95.5M
}
1076
1077
static inline int
1078
compare_unicode_unicode(PyDictObject *mp, PyDictKeysObject *dk,
1079
                        void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
1080
949M
{
1081
949M
    PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
1082
949M
    PyObject *ep_key = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key);
1083
949M
    assert(ep_key != NULL);
1084
949M
    assert(PyUnicode_CheckExact(ep_key));
1085
949M
    if (ep_key == key ||
1086
949M
            (unicode_get_hash(ep_key) == hash && unicode_eq(ep_key, key))) {
1087
527M
        return 1;
1088
527M
    }
1089
421M
    return 0;
1090
949M
}
1091
1092
static Py_ssize_t _Py_HOT_FUNCTION
1093
unicodekeys_lookup_unicode(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1094
1.04G
{
1095
1.04G
    return do_lookup(NULL, dk, key, hash, compare_unicode_unicode);
1096
1.04G
}
1097
1098
static inline int
1099
compare_generic(PyDictObject *mp, PyDictKeysObject *dk,
1100
                void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
1101
489M
{
1102
489M
    PyDictKeyEntry *ep = &((PyDictKeyEntry *)ep0)[ix];
1103
489M
    assert(ep->me_key != NULL);
1104
489M
    if (ep->me_key == key) {
1105
17.4M
        return 1;
1106
17.4M
    }
1107
471M
    if (ep->me_hash == hash) {
1108
111M
        PyObject *startkey = ep->me_key;
1109
111M
        Py_INCREF(startkey);
1110
111M
        int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
1111
111M
        Py_DECREF(startkey);
1112
111M
        if (cmp < 0) {
1113
0
            return DKIX_ERROR;
1114
0
        }
1115
111M
        if (dk == mp->ma_keys && ep->me_key == startkey) {
1116
111M
            return cmp;
1117
111M
        }
1118
0
        else {
1119
            /* The dict was mutated, restart */
1120
0
            return DKIX_KEY_CHANGED;
1121
0
        }
1122
111M
    }
1123
360M
    return 0;
1124
471M
}
1125
1126
static Py_ssize_t
1127
dictkeys_generic_lookup(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1128
493M
{
1129
493M
    return do_lookup(mp, dk, key, hash, compare_generic);
1130
493M
}
1131
1132
static bool
1133
check_keys_unicode(PyDictKeysObject *dk, PyObject *key)
1134
606k
{
1135
606k
    return PyUnicode_CheckExact(key) && (dk->dk_kind != DICT_KEYS_GENERAL);
1136
606k
}
1137
1138
static Py_ssize_t
1139
hash_unicode_key(PyObject *key)
1140
3.82M
{
1141
3.82M
    assert(PyUnicode_CheckExact(key));
1142
3.82M
    Py_hash_t hash = unicode_get_hash(key);
1143
3.82M
    if (hash == -1) {
1144
0
        hash = PyUnicode_Type.tp_hash(key);
1145
0
        assert(hash != -1);
1146
0
    }
1147
3.82M
    return hash;
1148
3.82M
}
1149
1150
#ifdef Py_GIL_DISABLED
1151
static Py_ssize_t
1152
unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject* dk, PyObject *key,
1153
                                      Py_hash_t hash);
1154
#endif
1155
1156
static Py_ssize_t
1157
unicodekeys_lookup_split(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1158
44.7M
{
1159
44.7M
    Py_ssize_t ix;
1160
44.7M
    assert(dk->dk_kind == DICT_KEYS_SPLIT);
1161
44.7M
    assert(PyUnicode_CheckExact(key));
1162
1163
#ifdef Py_GIL_DISABLED
1164
    // A split dictionaries keys can be mutated by other dictionaries
1165
    // but if we have a unicode key we can avoid locking the shared
1166
    // keys.
1167
    ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash);
1168
    if (ix == DKIX_KEY_CHANGED) {
1169
        LOCK_KEYS(dk);
1170
        ix = unicodekeys_lookup_unicode(dk, key, hash);
1171
        UNLOCK_KEYS(dk);
1172
    }
1173
#else
1174
44.7M
    ix = unicodekeys_lookup_unicode(dk, key, hash);
1175
44.7M
#endif
1176
44.7M
    return ix;
1177
44.7M
}
1178
1179
/* Lookup a string in a (all unicode) dict keys.
1180
 * Returns DKIX_ERROR if key is not a string,
1181
 * or if the dict keys is not all strings.
1182
 * If the keys is present then return the index of key.
1183
 * If the key is not present then return DKIX_EMPTY.
1184
 */
1185
Py_ssize_t
1186
_PyDictKeys_StringLookup(PyDictKeysObject* dk, PyObject *key)
1187
18.7k
{
1188
18.7k
    if (!check_keys_unicode(dk, key)) {
1189
0
        return DKIX_ERROR;
1190
0
    }
1191
18.7k
    Py_hash_t hash = hash_unicode_key(key);
1192
18.7k
    return unicodekeys_lookup_unicode(dk, key, hash);
1193
18.7k
}
1194
1195
Py_ssize_t
1196
_PyDictKeys_StringLookupAndVersion(PyDictKeysObject *dk, PyObject *key, uint32_t *version)
1197
587k
{
1198
587k
    if (!check_keys_unicode(dk, key)) {
1199
0
        return DKIX_ERROR;
1200
0
    }
1201
587k
    Py_ssize_t ix;
1202
587k
    Py_hash_t hash = hash_unicode_key(key);
1203
587k
    LOCK_KEYS(dk);
1204
587k
    ix = unicodekeys_lookup_unicode(dk, key, hash);
1205
587k
    *version = _PyDictKeys_GetVersionForCurrentState(_PyInterpreterState_GET(), dk);
1206
587k
    UNLOCK_KEYS(dk);
1207
587k
    return ix;
1208
587k
}
1209
1210
/* Like _PyDictKeys_StringLookup() but only works on split keys.  Note
1211
 * that in free-threaded builds this locks the keys object as required.
1212
 */
1213
Py_ssize_t
1214
_PyDictKeys_StringLookupSplit(PyDictKeysObject* dk, PyObject *key)
1215
44.7M
{
1216
44.7M
    assert(dk->dk_kind == DICT_KEYS_SPLIT);
1217
44.7M
    assert(PyUnicode_CheckExact(key));
1218
44.7M
    Py_hash_t hash = unicode_get_hash(key);
1219
44.7M
    if (hash == -1) {
1220
0
        hash = PyUnicode_Type.tp_hash(key);
1221
0
        if (hash == -1) {
1222
0
            PyErr_Clear();
1223
0
            return DKIX_ERROR;
1224
0
        }
1225
0
    }
1226
44.7M
    return unicodekeys_lookup_split(dk, key, hash);
1227
44.7M
}
1228
1229
/*
1230
The basic lookup function used by all operations.
1231
This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4.
1232
Open addressing is preferred over chaining since the link overhead for
1233
chaining would be substantial (100% with typical malloc overhead).
1234
1235
The initial probe index is computed as hash mod the table size. Subsequent
1236
probe indices are computed as explained earlier.
1237
1238
All arithmetic on hash should ignore overflow.
1239
1240
_Py_dict_lookup() is general-purpose, and may return DKIX_ERROR if (and only if) a
1241
comparison raises an exception.
1242
When the key isn't found a DKIX_EMPTY is returned.
1243
*/
1244
Py_ssize_t
1245
_Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr)
1246
1.56G
{
1247
1.56G
    PyDictKeysObject *dk;
1248
1.56G
    DictKeysKind kind;
1249
1.56G
    Py_ssize_t ix;
1250
1251
1.56G
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(mp);
1252
1.56G
start:
1253
1.56G
    dk = mp->ma_keys;
1254
1.56G
    kind = dk->dk_kind;
1255
1256
1.56G
    if (kind != DICT_KEYS_GENERAL) {
1257
1.07G
        if (PyUnicode_CheckExact(key)) {
1258
#ifdef Py_GIL_DISABLED
1259
            if (kind == DICT_KEYS_SPLIT) {
1260
                ix = unicodekeys_lookup_split(dk, key, hash);
1261
            }
1262
            else {
1263
                ix = unicodekeys_lookup_unicode(dk, key, hash);
1264
            }
1265
#else
1266
981M
            ix = unicodekeys_lookup_unicode(dk, key, hash);
1267
981M
#endif
1268
981M
        }
1269
95.5M
        else {
1270
95.5M
            INCREF_KEYS_FT(dk);
1271
95.5M
            LOCK_KEYS_IF_SPLIT(dk, kind);
1272
1273
95.5M
            ix = unicodekeys_lookup_generic(mp, dk, key, hash);
1274
1275
95.5M
            UNLOCK_KEYS_IF_SPLIT(dk, kind);
1276
95.5M
            DECREF_KEYS_FT(dk, IS_DICT_SHARED(mp));
1277
95.5M
            if (ix == DKIX_KEY_CHANGED) {
1278
0
                goto start;
1279
0
            }
1280
95.5M
        }
1281
1282
1.07G
        if (ix >= 0) {
1283
486M
            if (kind == DICT_KEYS_SPLIT) {
1284
3.41M
                *value_addr = mp->ma_values->values[ix];
1285
3.41M
            }
1286
482M
            else {
1287
482M
                *value_addr = DK_UNICODE_ENTRIES(dk)[ix].me_value;
1288
482M
            }
1289
486M
        }
1290
590M
        else {
1291
590M
            *value_addr = NULL;
1292
590M
        }
1293
1.07G
    }
1294
493M
    else {
1295
493M
        ix = dictkeys_generic_lookup(mp, dk, key, hash);
1296
493M
        if (ix == DKIX_KEY_CHANGED) {
1297
0
            goto start;
1298
0
        }
1299
493M
        if (ix >= 0) {
1300
129M
            *value_addr = DK_ENTRIES(dk)[ix].me_value;
1301
129M
        }
1302
363M
        else {
1303
363M
            *value_addr = NULL;
1304
363M
        }
1305
493M
    }
1306
1307
1.56G
    return ix;
1308
1.56G
}
1309
1310
#ifdef Py_GIL_DISABLED
1311
static inline void
1312
ensure_shared_on_read(PyDictObject *mp)
1313
{
1314
    if (!_Py_IsOwnedByCurrentThread((PyObject *)mp) && !IS_DICT_SHARED(mp)) {
1315
        // The first time we access a dict from a non-owning thread we mark it
1316
        // as shared. This ensures that a concurrent resize operation will
1317
        // delay freeing the old keys or values using QSBR, which is necessary
1318
        // to safely allow concurrent reads without locking...
1319
        Py_BEGIN_CRITICAL_SECTION(mp);
1320
        if (!IS_DICT_SHARED(mp)) {
1321
            SET_DICT_SHARED(mp);
1322
        }
1323
        Py_END_CRITICAL_SECTION();
1324
    }
1325
}
1326
1327
void
1328
_PyDict_EnsureSharedOnRead(PyDictObject *mp)
1329
{
1330
    ensure_shared_on_read(mp);
1331
}
1332
#endif
1333
1334
static inline void
1335
ensure_shared_on_resize(PyDictObject *mp)
1336
11.8M
{
1337
#ifdef Py_GIL_DISABLED
1338
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(mp);
1339
1340
    if (!_Py_IsOwnedByCurrentThread((PyObject *)mp) && !IS_DICT_SHARED(mp)) {
1341
        // We are writing to the dict from another thread that owns
1342
        // it and we haven't marked it as shared which will ensure
1343
        // that when we re-size ma_keys or ma_values that we will
1344
        // free using QSBR.  We need to lock the dictionary to
1345
        // contend with writes from the owning thread, mark it as
1346
        // shared, and then we can continue with lock-free reads.
1347
        // Technically this is a little heavy handed, we could just
1348
        // free the individual old keys / old-values using qsbr
1349
        SET_DICT_SHARED(mp);
1350
    }
1351
#endif
1352
11.8M
}
1353
1354
static inline void
1355
ensure_shared_on_keys_version_assignment(PyDictObject *mp)
1356
21.1k
{
1357
21.1k
    ASSERT_DICT_LOCKED((PyObject *) mp);
1358
    #ifdef Py_GIL_DISABLED
1359
    if (!IS_DICT_SHARED(mp)) {
1360
        // This ensures that a concurrent resize operation will delay
1361
        // freeing the old keys or values using QSBR, which is necessary to
1362
        // safely allow concurrent reads without locking.
1363
        SET_DICT_SHARED(mp);
1364
    }
1365
    #endif
1366
21.1k
}
1367
1368
#ifdef Py_GIL_DISABLED
1369
1370
static inline Py_ALWAYS_INLINE int
1371
compare_unicode_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
1372
                                   void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
1373
{
1374
    PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
1375
    PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
1376
    assert(startkey == NULL || PyUnicode_CheckExact(ep->me_key));
1377
    assert(!PyUnicode_CheckExact(key));
1378
1379
    if (startkey != NULL) {
1380
        if (!_Py_TryIncrefCompare(&ep->me_key, startkey)) {
1381
            return DKIX_KEY_CHANGED;
1382
        }
1383
1384
        if (unicode_get_hash(startkey) == hash) {
1385
            int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
1386
            Py_DECREF(startkey);
1387
            if (cmp < 0) {
1388
                return DKIX_ERROR;
1389
            }
1390
            if (dk == _Py_atomic_load_ptr_relaxed(&mp->ma_keys) &&
1391
                startkey == _Py_atomic_load_ptr_relaxed(&ep->me_key)) {
1392
                return cmp;
1393
            }
1394
            else {
1395
                /* The dict was mutated, restart */
1396
                return DKIX_KEY_CHANGED;
1397
            }
1398
        }
1399
        else {
1400
            Py_DECREF(startkey);
1401
        }
1402
    }
1403
    return 0;
1404
}
1405
1406
// Search non-Unicode key from Unicode table
1407
static Py_ssize_t
1408
unicodekeys_lookup_generic_threadsafe(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1409
{
1410
    return do_lookup(mp, dk, key, hash, compare_unicode_generic_threadsafe);
1411
}
1412
1413
static inline Py_ALWAYS_INLINE int
1414
compare_unicode_unicode_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
1415
                                   void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
1416
{
1417
    PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
1418
    PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
1419
    if (startkey == key) {
1420
        assert(PyUnicode_CheckExact(startkey));
1421
        return 1;
1422
    }
1423
    if (startkey != NULL) {
1424
        if (_Py_IsImmortal(startkey)) {
1425
            assert(PyUnicode_CheckExact(startkey));
1426
            return unicode_get_hash(startkey) == hash && unicode_eq(startkey, key);
1427
        }
1428
        else {
1429
            if (!_Py_TryIncrefCompare(&ep->me_key, startkey)) {
1430
                return DKIX_KEY_CHANGED;
1431
            }
1432
            assert(PyUnicode_CheckExact(startkey));
1433
            if (unicode_get_hash(startkey) == hash && unicode_eq(startkey, key)) {
1434
                Py_DECREF(startkey);
1435
                return 1;
1436
            }
1437
            Py_DECREF(startkey);
1438
        }
1439
    }
1440
    return 0;
1441
}
1442
1443
static Py_ssize_t _Py_HOT_FUNCTION
1444
unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1445
{
1446
    return do_lookup(NULL, dk, key, hash, compare_unicode_unicode_threadsafe);
1447
}
1448
1449
static inline Py_ALWAYS_INLINE int
1450
compare_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
1451
                           void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
1452
{
1453
    PyDictKeyEntry *ep = &((PyDictKeyEntry *)ep0)[ix];
1454
    PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
1455
    if (startkey == key) {
1456
        return 1;
1457
    }
1458
    Py_ssize_t ep_hash = _Py_atomic_load_ssize_relaxed(&ep->me_hash);
1459
    if (ep_hash == hash) {
1460
        if (startkey == NULL || !_Py_TryIncrefCompare(&ep->me_key, startkey)) {
1461
            return DKIX_KEY_CHANGED;
1462
        }
1463
        int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
1464
        Py_DECREF(startkey);
1465
        if (cmp < 0) {
1466
            return DKIX_ERROR;
1467
        }
1468
        if (dk == _Py_atomic_load_ptr_relaxed(&mp->ma_keys) &&
1469
            startkey == _Py_atomic_load_ptr_relaxed(&ep->me_key)) {
1470
            return cmp;
1471
        }
1472
        else {
1473
            /* The dict was mutated, restart */
1474
            return DKIX_KEY_CHANGED;
1475
        }
1476
    }
1477
    return 0;
1478
}
1479
1480
static Py_ssize_t
1481
dictkeys_generic_lookup_threadsafe(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1482
{
1483
    return do_lookup(mp, dk, key, hash, compare_generic_threadsafe);
1484
}
1485
1486
Py_ssize_t
1487
_Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr)
1488
{
1489
    PyDictKeysObject *dk;
1490
    DictKeysKind kind;
1491
    Py_ssize_t ix;
1492
    PyObject *value;
1493
1494
    ensure_shared_on_read(mp);
1495
1496
    dk = _Py_atomic_load_ptr(&mp->ma_keys);
1497
    kind = dk->dk_kind;
1498
1499
    if (kind != DICT_KEYS_GENERAL) {
1500
        if (PyUnicode_CheckExact(key)) {
1501
            ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash);
1502
        }
1503
        else {
1504
            ix = unicodekeys_lookup_generic_threadsafe(mp, dk, key, hash);
1505
        }
1506
        if (ix == DKIX_KEY_CHANGED) {
1507
            goto read_failed;
1508
        }
1509
1510
        if (ix >= 0) {
1511
            if (kind == DICT_KEYS_SPLIT) {
1512
                PyDictValues *values = _Py_atomic_load_ptr(&mp->ma_values);
1513
                if (values == NULL)
1514
                    goto read_failed;
1515
1516
                uint8_t capacity = _Py_atomic_load_uint8_relaxed(&values->capacity);
1517
                if (ix >= (Py_ssize_t)capacity)
1518
                    goto read_failed;
1519
1520
                value = _Py_TryXGetRef(&values->values[ix]);
1521
                if (value == NULL)
1522
                    goto read_failed;
1523
1524
                if (values != _Py_atomic_load_ptr(&mp->ma_values)) {
1525
                    Py_DECREF(value);
1526
                    goto read_failed;
1527
                }
1528
            }
1529
            else {
1530
                value = _Py_TryXGetRef(&DK_UNICODE_ENTRIES(dk)[ix].me_value);
1531
                if (value == NULL) {
1532
                    goto read_failed;
1533
                }
1534
1535
                if (dk != _Py_atomic_load_ptr(&mp->ma_keys)) {
1536
                    Py_DECREF(value);
1537
                    goto read_failed;
1538
                }
1539
            }
1540
        }
1541
        else {
1542
            value = NULL;
1543
        }
1544
    }
1545
    else {
1546
        ix = dictkeys_generic_lookup_threadsafe(mp, dk, key, hash);
1547
        if (ix == DKIX_KEY_CHANGED) {
1548
            goto read_failed;
1549
        }
1550
        if (ix >= 0) {
1551
            value = _Py_TryXGetRef(&DK_ENTRIES(dk)[ix].me_value);
1552
            if (value == NULL)
1553
                goto read_failed;
1554
1555
            if (dk != _Py_atomic_load_ptr(&mp->ma_keys)) {
1556
                Py_DECREF(value);
1557
                goto read_failed;
1558
            }
1559
        }
1560
        else {
1561
            value = NULL;
1562
        }
1563
    }
1564
1565
    *value_addr = value;
1566
    return ix;
1567
1568
read_failed:
1569
    // In addition to the normal races of the dict being modified the _Py_TryXGetRef
1570
    // can all fail if they don't yet have a shared ref count.  That can happen here
1571
    // or in the *_lookup_* helper.  In that case we need to take the lock to avoid
1572
    // mutation and do a normal incref which will make them shared.
1573
    Py_BEGIN_CRITICAL_SECTION(mp);
1574
    ix = _Py_dict_lookup(mp, key, hash, &value);
1575
    *value_addr = value;
1576
    if (value != NULL) {
1577
        assert(ix >= 0);
1578
        _Py_NewRefWithLock(value);
1579
    }
1580
    Py_END_CRITICAL_SECTION();
1581
    return ix;
1582
}
1583
1584
static Py_ssize_t
1585
lookup_threadsafe_unicode(PyDictKeysObject *dk, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr)
1586
{
1587
    assert(dk->dk_kind == DICT_KEYS_UNICODE);
1588
    assert(PyUnicode_CheckExact(key));
1589
1590
    Py_ssize_t ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash);
1591
    if (ix == DKIX_EMPTY) {
1592
        *value_addr = PyStackRef_NULL;
1593
        return ix;
1594
    }
1595
    else if (ix >= 0) {
1596
        PyObject **addr_of_value = &DK_UNICODE_ENTRIES(dk)[ix].me_value;
1597
        PyObject *value = _Py_atomic_load_ptr(addr_of_value);
1598
        if (value == NULL) {
1599
            *value_addr = PyStackRef_NULL;
1600
            return DKIX_EMPTY;
1601
        }
1602
        if (_PyObject_HasDeferredRefcount(value)) {
1603
            *value_addr =  (_PyStackRef){ .bits = (uintptr_t)value | Py_TAG_DEFERRED };
1604
            return ix;
1605
        }
1606
        if (_Py_TryIncrefCompare(addr_of_value, value)) {
1607
            *value_addr = PyStackRef_FromPyObjectSteal(value);
1608
            return ix;
1609
        }
1610
        return DKIX_KEY_CHANGED;
1611
    }
1612
    assert(ix == DKIX_KEY_CHANGED);
1613
    return ix;
1614
}
1615
1616
Py_ssize_t
1617
_Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr)
1618
{
1619
    PyDictKeysObject *dk = _Py_atomic_load_ptr(&mp->ma_keys);
1620
    if (dk->dk_kind == DICT_KEYS_UNICODE && PyUnicode_CheckExact(key)) {
1621
        Py_ssize_t ix = lookup_threadsafe_unicode(dk, key, hash, value_addr);
1622
        if (ix != DKIX_KEY_CHANGED) {
1623
            return ix;
1624
        }
1625
    }
1626
1627
    PyObject *obj;
1628
    Py_ssize_t ix = _Py_dict_lookup_threadsafe(mp, key, hash, &obj);
1629
    if (ix >= 0 && obj != NULL) {
1630
        *value_addr = PyStackRef_FromPyObjectSteal(obj);
1631
    }
1632
    else {
1633
        *value_addr = PyStackRef_NULL;
1634
    }
1635
    return ix;
1636
}
1637
1638
#else   // Py_GIL_DISABLED
1639
1640
Py_ssize_t
1641
_Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr)
1642
597M
{
1643
597M
    Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, value_addr);
1644
597M
    Py_XNewRef(*value_addr);
1645
597M
    return ix;
1646
597M
}
1647
1648
Py_ssize_t
1649
_Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr)
1650
13.6M
{
1651
13.6M
    PyObject *val;
1652
13.6M
    Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &val);
1653
13.6M
    if (val == NULL) {
1654
52.1k
        *value_addr = PyStackRef_NULL;
1655
52.1k
    }
1656
13.5M
    else {
1657
13.5M
        *value_addr = PyStackRef_FromPyObjectNew(val);
1658
13.5M
    }
1659
13.6M
    return ix;
1660
13.6M
}
1661
1662
#endif
1663
1664
// Looks up the unicode key `key` in the dictionary. Note that `*method` may
1665
// already contain a valid value! See _PyObject_GetMethodStackRef().
1666
int
1667
_PyDict_GetMethodStackRef(PyDictObject *mp, PyObject *key, _PyStackRef *method)
1668
3.21M
{
1669
3.21M
    assert(PyUnicode_CheckExact(key));
1670
3.21M
    Py_hash_t hash = hash_unicode_key(key);
1671
1672
#ifdef Py_GIL_DISABLED
1673
    PyDictKeysObject *dk = _Py_atomic_load_ptr_acquire(&mp->ma_keys);
1674
    if (dk->dk_kind == DICT_KEYS_UNICODE) {
1675
        _PyStackRef ref;
1676
        Py_ssize_t ix = lookup_threadsafe_unicode(dk, key, hash, &ref);
1677
        if (ix >= 0) {
1678
            assert(!PyStackRef_IsNull(ref));
1679
            PyStackRef_XSETREF(*method, ref);
1680
            return 1;
1681
        }
1682
        else if (ix == DKIX_EMPTY) {
1683
            return 0;
1684
        }
1685
        assert(ix == DKIX_KEY_CHANGED);
1686
    }
1687
#endif
1688
1689
3.21M
    PyObject *obj;
1690
3.21M
    Py_INCREF(mp);
1691
3.21M
    Py_ssize_t ix = _Py_dict_lookup_threadsafe(mp, key, hash, &obj);
1692
3.21M
    Py_DECREF(mp);
1693
3.21M
    if (ix == DKIX_ERROR) {
1694
0
        PyStackRef_CLEAR(*method);
1695
0
        return -1;
1696
0
    }
1697
3.21M
    else if (ix >= 0 && obj != NULL) {
1698
0
        PyStackRef_XSETREF(*method, PyStackRef_FromPyObjectSteal(obj));
1699
0
        return 1;
1700
0
    }
1701
3.21M
    return 0;  // not found
1702
3.21M
}
1703
1704
int
1705
_PyDict_HasOnlyStringKeys(PyObject *dict)
1706
301k
{
1707
301k
    Py_ssize_t pos = 0;
1708
301k
    PyObject *key, *value;
1709
301k
    assert(PyDict_Check(dict));
1710
    /* Shortcut */
1711
301k
    if (((PyDictObject *)dict)->ma_keys->dk_kind != DICT_KEYS_GENERAL)
1712
301k
        return 1;
1713
0
    while (PyDict_Next(dict, &pos, &key, &value))
1714
0
        if (!PyUnicode_Check(key))
1715
0
            return 0;
1716
0
    return 1;
1717
0
}
1718
1719
void
1720
_PyDict_EnablePerThreadRefcounting(PyObject *op)
1721
1.45k
{
1722
1.45k
    assert(PyDict_Check(op));
1723
#ifdef Py_GIL_DISABLED
1724
    Py_ssize_t id = _PyObject_AssignUniqueId(op);
1725
    if (id == _Py_INVALID_UNIQUE_ID) {
1726
        return;
1727
    }
1728
    if ((uint64_t)id >= (uint64_t)DICT_UNIQUE_ID_MAX) {
1729
        _PyObject_ReleaseUniqueId(id);
1730
        return;
1731
    }
1732
1733
    PyDictObject *mp = (PyDictObject *)op;
1734
    assert((mp->_ma_watcher_tag >> DICT_UNIQUE_ID_SHIFT) == 0);
1735
    mp->_ma_watcher_tag += (uint64_t)id << DICT_UNIQUE_ID_SHIFT;
1736
#endif
1737
1.45k
}
1738
1739
static inline int
1740
is_unusable_slot(Py_ssize_t ix)
1741
547M
{
1742
#ifdef Py_GIL_DISABLED
1743
    return ix >= 0 || ix == DKIX_DUMMY;
1744
#else
1745
547M
    return ix >= 0;
1746
547M
#endif
1747
547M
}
1748
1749
/* Internal function to find slot for an item from its hash
1750
   when it is known that the key is not present in the dict.
1751
 */
1752
static Py_ssize_t
1753
find_empty_slot(PyDictKeysObject *keys, Py_hash_t hash)
1754
305M
{
1755
305M
    assert(keys != NULL);
1756
1757
305M
    const size_t mask = DK_MASK(keys);
1758
305M
    size_t i = hash & mask;
1759
305M
    Py_ssize_t ix = dictkeys_get_index(keys, i);
1760
547M
    for (size_t perturb = hash; is_unusable_slot(ix);) {
1761
242M
        perturb >>= PERTURB_SHIFT;
1762
242M
        i = (i*5 + perturb + 1) & mask;
1763
242M
        ix = dictkeys_get_index(keys, i);
1764
242M
    }
1765
305M
    return i;
1766
305M
}
1767
1768
static int
1769
insertion_resize(PyDictObject *mp, int unicode)
1770
10.6M
{
1771
10.6M
    return dictresize(mp, calculate_log2_keysize(GROWTH_RATE(mp)), unicode);
1772
10.6M
}
1773
1774
static inline int
1775
insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
1776
                     Py_hash_t hash, PyObject *key, PyObject *value)
1777
303M
{
1778
303M
    if (mp->ma_keys->dk_usable <= 0) {
1779
        /* Need to resize. */
1780
9.92M
        if (insertion_resize(mp, 1) < 0) {
1781
0
            return -1;
1782
0
        }
1783
9.92M
    }
1784
1785
303M
    _PyDict_NotifyEvent(interp, PyDict_EVENT_ADDED, mp, key, value);
1786
303M
    FT_ATOMIC_STORE_UINT32_RELAXED(mp->ma_keys->dk_version, 0);
1787
1788
303M
    Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash);
1789
303M
    dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
1790
1791
303M
    if (DK_IS_UNICODE(mp->ma_keys)) {
1792
18.9M
        PyDictUnicodeEntry *ep;
1793
18.9M
        ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
1794
18.9M
        STORE_KEY(ep, key);
1795
18.9M
        STORE_VALUE(ep, value);
1796
18.9M
    }
1797
284M
    else {
1798
284M
        PyDictKeyEntry *ep;
1799
284M
        ep = &DK_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
1800
284M
        STORE_KEY(ep, key);
1801
284M
        STORE_VALUE(ep, value);
1802
284M
        STORE_HASH(ep, hash);
1803
284M
    }
1804
303M
    STORE_KEYS_USABLE(mp->ma_keys, mp->ma_keys->dk_usable - 1);
1805
303M
    STORE_KEYS_NENTRIES(mp->ma_keys, mp->ma_keys->dk_nentries + 1);
1806
303M
    assert(mp->ma_keys->dk_usable >= 0);
1807
303M
    return 0;
1808
303M
}
1809
1810
static Py_ssize_t
1811
insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash)
1812
18.0M
{
1813
18.0M
    assert(PyUnicode_CheckExact(key));
1814
18.0M
    Py_ssize_t ix;
1815
1816
1817
#ifdef Py_GIL_DISABLED
1818
    ix = unicodekeys_lookup_unicode_threadsafe(keys, key, hash);
1819
    if (ix >= 0) {
1820
        return ix;
1821
    }
1822
#endif
1823
1824
18.0M
    LOCK_KEYS(keys);
1825
18.0M
    ix = unicodekeys_lookup_unicode(keys, key, hash);
1826
18.0M
    if (ix == DKIX_EMPTY && keys->dk_usable > 0) {
1827
        // Insert into new slot
1828
1.76M
        FT_ATOMIC_STORE_UINT32_RELAXED(keys->dk_version, 0);
1829
1.76M
        Py_ssize_t hashpos = find_empty_slot(keys, hash);
1830
1.76M
        ix = keys->dk_nentries;
1831
1.76M
        dictkeys_set_index(keys, hashpos, ix);
1832
1.76M
        PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(keys)[ix];
1833
1.76M
        STORE_SHARED_KEY(ep->me_key, Py_NewRef(key));
1834
1.76M
        split_keys_entry_added(keys);
1835
1.76M
    }
1836
18.0M
    assert (ix < SHARED_KEYS_MAX_SIZE);
1837
18.0M
    UNLOCK_KEYS(keys);
1838
18.0M
    return ix;
1839
18.0M
}
1840
1841
static void
1842
insert_split_value(PyInterpreterState *interp, PyDictObject *mp, PyObject *key, PyObject *value, Py_ssize_t ix)
1843
9.70k
{
1844
9.70k
    assert(PyUnicode_CheckExact(key));
1845
9.70k
    ASSERT_DICT_LOCKED(mp);
1846
9.70k
    PyObject *old_value = mp->ma_values->values[ix];
1847
9.70k
    if (old_value == NULL) {
1848
9.70k
        _PyDict_NotifyEvent(interp, PyDict_EVENT_ADDED, mp, key, value);
1849
9.70k
        STORE_SPLIT_VALUE(mp, ix, Py_NewRef(value));
1850
9.70k
        _PyDictValues_AddToInsertionOrder(mp->ma_values, ix);
1851
9.70k
        STORE_USED(mp, mp->ma_used + 1);
1852
9.70k
    }
1853
0
    else {
1854
0
        _PyDict_NotifyEvent(interp, PyDict_EVENT_MODIFIED, mp, key, value);
1855
0
        STORE_SPLIT_VALUE(mp, ix, Py_NewRef(value));
1856
        // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault,
1857
        // when dict only holds the strong reference to value in ep->me_value.
1858
0
        Py_DECREF(old_value);
1859
0
    }
1860
9.70k
    ASSERT_CONSISTENT(mp);
1861
9.70k
}
1862
1863
/*
1864
Internal routine to insert a new item into the table.
1865
Used both by the internal resize routine and by the public insert routine.
1866
Returns -1 if an error occurred, or 0 on success.
1867
Consumes key and value references.
1868
*/
1869
static int
1870
insertdict(PyInterpreterState *interp, PyDictObject *mp,
1871
           PyObject *key, Py_hash_t hash, PyObject *value)
1872
388M
{
1873
388M
    PyObject *old_value;
1874
1875
388M
    ASSERT_DICT_LOCKED(mp);
1876
1877
388M
    if (DK_IS_UNICODE(mp->ma_keys) && !PyUnicode_CheckExact(key)) {
1878
3.93k
        if (insertion_resize(mp, 0) < 0)
1879
0
            goto Fail;
1880
3.93k
        assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
1881
3.93k
    }
1882
1883
388M
    if (_PyDict_HasSplitTable(mp)) {
1884
704k
        Py_ssize_t ix = insert_split_key(mp->ma_keys, key, hash);
1885
704k
        if (ix != DKIX_EMPTY) {
1886
9.70k
            insert_split_value(interp, mp, key, value, ix);
1887
9.70k
            Py_DECREF(key);
1888
9.70k
            Py_DECREF(value);
1889
9.70k
            return 0;
1890
9.70k
        }
1891
1892
        /* No space in shared keys. Resize and continue below. */
1893
694k
        if (insertion_resize(mp, 1) < 0) {
1894
0
            goto Fail;
1895
0
        }
1896
694k
    }
1897
1898
388M
    Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &old_value);
1899
388M
    if (ix == DKIX_ERROR)
1900
0
        goto Fail;
1901
1902
388M
    if (ix == DKIX_EMPTY) {
1903
299M
        assert(!_PyDict_HasSplitTable(mp));
1904
        /* Insert into new slot. */
1905
299M
        assert(old_value == NULL);
1906
299M
        if (insert_combined_dict(interp, mp, hash, key, value) < 0) {
1907
0
            goto Fail;
1908
0
        }
1909
299M
        STORE_USED(mp, mp->ma_used + 1);
1910
299M
        ASSERT_CONSISTENT(mp);
1911
299M
        return 0;
1912
299M
    }
1913
1914
88.0M
    if (old_value != value) {
1915
87.9M
        _PyDict_NotifyEvent(interp, PyDict_EVENT_MODIFIED, mp, key, value);
1916
87.9M
        assert(old_value != NULL);
1917
87.9M
        assert(!_PyDict_HasSplitTable(mp));
1918
87.9M
        if (DK_IS_UNICODE(mp->ma_keys)) {
1919
87.9M
            PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[ix];
1920
87.9M
            STORE_VALUE(ep, value);
1921
87.9M
        }
1922
6.69k
        else {
1923
6.69k
            PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[ix];
1924
6.69k
            STORE_VALUE(ep, value);
1925
6.69k
        }
1926
87.9M
    }
1927
88.0M
    Py_XDECREF(old_value); /* which **CAN** re-enter (see issue #22653) */
1928
88.0M
    ASSERT_CONSISTENT(mp);
1929
88.0M
    Py_DECREF(key);
1930
88.0M
    return 0;
1931
1932
0
Fail:
1933
0
    Py_DECREF(value);
1934
0
    Py_DECREF(key);
1935
0
    return -1;
1936
388M
}
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
29.7M
{
1944
29.7M
    assert(mp->ma_keys == Py_EMPTY_KEYS);
1945
29.7M
    ASSERT_DICT_LOCKED(mp);
1946
1947
29.7M
    int unicode = PyUnicode_CheckExact(key);
1948
29.7M
    PyDictKeysObject *newkeys = new_keys_object(PyDict_LOG_MINSIZE, unicode);
1949
29.7M
    if (newkeys == NULL) {
1950
0
        Py_DECREF(key);
1951
0
        Py_DECREF(value);
1952
0
        return -1;
1953
0
    }
1954
29.7M
    _PyDict_NotifyEvent(interp, PyDict_EVENT_ADDED, mp, key, value);
1955
1956
    /* We don't decref Py_EMPTY_KEYS here because it is immortal. */
1957
29.7M
    assert(mp->ma_values == NULL);
1958
1959
29.7M
    size_t hashpos = (size_t)hash & (PyDict_MINSIZE-1);
1960
29.7M
    dictkeys_set_index(newkeys, hashpos, 0);
1961
29.7M
    if (unicode) {
1962
18.5M
        PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(newkeys);
1963
18.5M
        ep->me_key = key;
1964
18.5M
        STORE_VALUE(ep, value);
1965
18.5M
    }
1966
11.1M
    else {
1967
11.1M
        PyDictKeyEntry *ep = DK_ENTRIES(newkeys);
1968
11.1M
        ep->me_key = key;
1969
11.1M
        ep->me_hash = hash;
1970
11.1M
        STORE_VALUE(ep, value);
1971
11.1M
    }
1972
29.7M
    STORE_USED(mp, mp->ma_used + 1);
1973
29.7M
    newkeys->dk_usable--;
1974
29.7M
    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
29.7M
    FT_ATOMIC_STORE_PTR_RELEASE(mp->ma_keys, newkeys);
1981
29.7M
    return 0;
1982
29.7M
}
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
8.53M
{
1990
8.53M
    size_t mask = DK_MASK(keys);
1991
384M
    for (Py_ssize_t ix = 0; ix != n; ix++, ep++) {
1992
376M
        Py_hash_t hash = ep->me_hash;
1993
376M
        size_t i = hash & mask;
1994
437M
        for (size_t perturb = hash; dictkeys_get_index(keys, i) != DKIX_EMPTY;) {
1995
61.3M
            perturb >>= PERTURB_SHIFT;
1996
61.3M
            i = mask & (i*5 + perturb + 1);
1997
61.3M
        }
1998
376M
        dictkeys_set_index(keys, i, ix);
1999
376M
    }
2000
8.53M
}
2001
2002
static void
2003
build_indices_unicode(PyDictKeysObject *keys, PyDictUnicodeEntry *ep, Py_ssize_t n)
2004
2.67M
{
2005
2.67M
    size_t mask = DK_MASK(keys);
2006
17.0M
    for (Py_ssize_t ix = 0; ix != n; ix++, ep++) {
2007
14.3M
        Py_hash_t hash = unicode_get_hash(ep->me_key);
2008
14.3M
        assert(hash != -1);
2009
14.3M
        size_t i = hash & mask;
2010
16.7M
        for (size_t perturb = hash; dictkeys_get_index(keys, i) != DKIX_EMPTY;) {
2011
2.37M
            perturb >>= PERTURB_SHIFT;
2012
2.37M
            i = mask & (i*5 + perturb + 1);
2013
2.37M
        }
2014
14.3M
        dictkeys_set_index(keys, i, ix);
2015
14.3M
    }
2016
2.67M
}
2017
2018
static void
2019
invalidate_and_clear_inline_values(PyDictValues *values)
2020
694k
{
2021
694k
    assert(values->embedded);
2022
694k
    FT_ATOMIC_STORE_UINT8(values->valid, 0);
2023
2.12M
    for (int i = 0; i < values->capacity; i++) {
2024
1.42M
        FT_ATOMIC_STORE_PTR_RELEASE(values->values[i], NULL);
2025
1.42M
    }
2026
694k
}
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
11.2M
{
2046
11.2M
    PyDictKeysObject *oldkeys, *newkeys;
2047
11.2M
    PyDictValues *oldvalues;
2048
2049
11.2M
    ASSERT_DICT_LOCKED(mp);
2050
2051
11.2M
    if (log2_newsize >= SIZEOF_SIZE_T*8) {
2052
0
        PyErr_NoMemory();
2053
0
        return -1;
2054
0
    }
2055
11.2M
    assert(log2_newsize >= PyDict_LOG_MINSIZE);
2056
2057
11.2M
    oldkeys = mp->ma_keys;
2058
11.2M
    oldvalues = mp->ma_values;
2059
2060
11.2M
    if (!DK_IS_UNICODE(oldkeys)) {
2061
8.53M
        unicode = 0;
2062
8.53M
    }
2063
2064
11.2M
    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
11.2M
    newkeys = new_keys_object(log2_newsize, unicode);
2072
11.2M
    if (newkeys == NULL) {
2073
0
        return -1;
2074
0
    }
2075
    // New table must be large enough.
2076
11.2M
    assert(newkeys->dk_usable >= mp->ma_used);
2077
2078
11.2M
    Py_ssize_t numentries = mp->ma_used;
2079
2080
11.2M
    if (oldvalues != NULL) {
2081
694k
        LOCK_KEYS(oldkeys);
2082
694k
        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
694k
        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
694k
        else { // split -> combined unicode
2101
694k
            PyDictUnicodeEntry *newentries = DK_UNICODE_ENTRIES(newkeys);
2102
2103
1.80M
            for (Py_ssize_t i = 0; i < numentries; i++) {
2104
1.10M
                int index = get_index_from_order(mp, i);
2105
1.10M
                PyDictUnicodeEntry *ep = &oldentries[index];
2106
1.10M
                assert(oldvalues->values[index] != NULL);
2107
1.10M
                newentries[i].me_key = Py_NewRef(ep->me_key);
2108
1.10M
                newentries[i].me_value = oldvalues->values[index];
2109
1.10M
            }
2110
694k
            build_indices_unicode(newkeys, newentries, numentries);
2111
694k
        }
2112
694k
        UNLOCK_KEYS(oldkeys);
2113
694k
        set_keys(mp, newkeys);
2114
694k
        dictkeys_decref(oldkeys, IS_DICT_SHARED(mp));
2115
694k
        set_values(mp, NULL);
2116
694k
        if (oldvalues->embedded) {
2117
694k
            assert(oldvalues->embedded == 1);
2118
694k
            assert(oldvalues->valid == 1);
2119
694k
            invalidate_and_clear_inline_values(oldvalues);
2120
694k
        }
2121
0
        else {
2122
0
            free_values(oldvalues, IS_DICT_SHARED(mp));
2123
0
        }
2124
694k
    }
2125
10.5M
    else {  // oldkeys is combined.
2126
10.5M
        if (oldkeys->dk_kind == DICT_KEYS_GENERAL) {
2127
            // generic -> generic
2128
8.53M
            assert(newkeys->dk_kind == DICT_KEYS_GENERAL);
2129
8.53M
            PyDictKeyEntry *oldentries = DK_ENTRIES(oldkeys);
2130
8.53M
            PyDictKeyEntry *newentries = DK_ENTRIES(newkeys);
2131
8.53M
            if (oldkeys->dk_nentries == numentries) {
2132
8.49M
                memcpy(newentries, oldentries, numentries * sizeof(PyDictKeyEntry));
2133
8.49M
            }
2134
41.1k
            else {
2135
41.1k
                PyDictKeyEntry *ep = oldentries;
2136
609k
                for (Py_ssize_t i = 0; i < numentries; i++) {
2137
1.28M
                    while (ep->me_value == NULL)
2138
716k
                        ep++;
2139
567k
                    newentries[i] = *ep++;
2140
567k
                }
2141
41.1k
            }
2142
8.53M
            build_indices_generic(newkeys, newentries, numentries);
2143
8.53M
        }
2144
1.98M
        else {  // oldkeys is combined unicode
2145
1.98M
            PyDictUnicodeEntry *oldentries = DK_UNICODE_ENTRIES(oldkeys);
2146
1.98M
            if (unicode) { // combined unicode -> combined unicode
2147
1.98M
                PyDictUnicodeEntry *newentries = DK_UNICODE_ENTRIES(newkeys);
2148
1.98M
                if (oldkeys->dk_nentries == numentries && mp->ma_keys->dk_kind == DICT_KEYS_UNICODE) {
2149
1.98M
                    memcpy(newentries, oldentries, numentries * sizeof(PyDictUnicodeEntry));
2150
1.98M
                }
2151
2.03k
                else {
2152
2.03k
                    PyDictUnicodeEntry *ep = oldentries;
2153
473k
                    for (Py_ssize_t i = 0; i < numentries; i++) {
2154
487k
                        while (ep->me_value == NULL)
2155
16.0k
                            ep++;
2156
471k
                        newentries[i] = *ep++;
2157
471k
                    }
2158
2.03k
                }
2159
1.98M
                build_indices_unicode(newkeys, newentries, numentries);
2160
1.98M
            }
2161
4.13k
            else { // combined unicode -> generic
2162
4.13k
                PyDictKeyEntry *newentries = DK_ENTRIES(newkeys);
2163
4.13k
                PyDictUnicodeEntry *ep = oldentries;
2164
13.2k
                for (Py_ssize_t i = 0; i < numentries; i++) {
2165
9.14k
                    while (ep->me_value == NULL)
2166
0
                        ep++;
2167
9.14k
                    newentries[i].me_key = ep->me_key;
2168
9.14k
                    newentries[i].me_hash = unicode_get_hash(ep->me_key);
2169
9.14k
                    newentries[i].me_value = ep->me_value;
2170
9.14k
                    ep++;
2171
9.14k
                }
2172
4.13k
                build_indices_generic(newkeys, newentries, numentries);
2173
4.13k
            }
2174
1.98M
        }
2175
2176
10.5M
        set_keys(mp, newkeys);
2177
2178
10.5M
        if (oldkeys != Py_EMPTY_KEYS) {
2179
#ifdef Py_REF_DEBUG
2180
            _Py_DecRefTotal(_PyThreadState_GET());
2181
#endif
2182
9.93M
            assert(oldkeys->dk_kind != DICT_KEYS_SPLIT);
2183
9.93M
            assert(oldkeys->dk_refcnt == 1);
2184
9.93M
            free_keys_object(oldkeys, IS_DICT_SHARED(mp));
2185
9.93M
        }
2186
10.5M
    }
2187
2188
11.2M
    STORE_KEYS_USABLE(mp->ma_keys, mp->ma_keys->dk_usable - numentries);
2189
11.2M
    STORE_KEYS_NENTRIES(mp->ma_keys, numentries);
2190
11.2M
    ASSERT_CONSISTENT(mp);
2191
11.2M
    return 0;
2192
11.2M
}
2193
2194
static PyObject *
2195
dict_new_presized(Py_ssize_t minused, bool unicode)
2196
280M
{
2197
280M
    const uint8_t log2_max_presize = 17;
2198
280M
    const Py_ssize_t max_presize = ((Py_ssize_t)1) << log2_max_presize;
2199
280M
    uint8_t log2_newsize;
2200
280M
    PyDictKeysObject *new_keys;
2201
2202
280M
    if (minused <= USABLE_FRACTION(PyDict_MINSIZE)) {
2203
280M
        return PyDict_New();
2204
280M
    }
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
798
    if (minused > USABLE_FRACTION(max_presize)) {
2210
0
        log2_newsize = log2_max_presize;
2211
0
    }
2212
798
    else {
2213
798
        log2_newsize = estimate_log2_keysize(minused);
2214
798
    }
2215
2216
798
    new_keys = new_keys_object(log2_newsize, unicode);
2217
798
    if (new_keys == NULL)
2218
0
        return NULL;
2219
798
    return new_dict(new_keys, NULL, 0, 0);
2220
798
}
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
280M
{
2233
280M
    bool unicode = true;
2234
280M
    PyObject *const *ks = keys;
2235
2236
287M
    for (Py_ssize_t i = 0; i < length; i++) {
2237
6.64M
        if (!PyUnicode_CheckExact(*ks)) {
2238
263
            unicode = false;
2239
263
            break;
2240
263
        }
2241
6.64M
        ks += keys_offset;
2242
6.64M
    }
2243
2244
280M
    PyObject *dict = dict_new_presized(length, unicode);
2245
280M
    if (dict == NULL) {
2246
0
        return NULL;
2247
0
    }
2248
2249
280M
    ks = keys;
2250
280M
    PyObject *const *vs = values;
2251
2252
287M
    for (Py_ssize_t i = 0; i < length; i++) {
2253
6.64M
        PyObject *key = *ks;
2254
6.64M
        PyObject *value = *vs;
2255
6.64M
        if (setitem_lock_held((PyDictObject *)dict, key, value) < 0) {
2256
0
            Py_DECREF(dict);
2257
0
            return NULL;
2258
0
        }
2259
6.64M
        ks += keys_offset;
2260
6.64M
        vs += values_offset;
2261
6.64M
    }
2262
2263
280M
    return dict;
2264
280M
}
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
298k
{
2279
298k
    if (!PyDict_Check(op)) {
2280
0
        return NULL;
2281
0
    }
2282
298k
    PyDictObject *mp = (PyDictObject *)op;
2283
2284
298k
    Py_hash_t hash = _PyObject_HashFast(key);
2285
298k
    if (hash == -1) {
2286
0
        PyErr_FormatUnraisable(warnmsg);
2287
0
        return NULL;
2288
0
    }
2289
2290
298k
    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
298k
    PyObject *value;
2299
298k
    Py_ssize_t ix; (void)ix;
2300
2301
298k
    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
298k
    ix = _Py_dict_lookup(mp, key, hash, &value);
2307
298k
#endif
2308
2309
    /* Ignore any exception raised by the lookup */
2310
298k
    PyObject *exc2 = _PyErr_Occurred(tstate);
2311
298k
    if (exc2 && !PyErr_GivenExceptionMatches(exc2, PyExc_KeyError)) {
2312
0
        PyErr_FormatUnraisable(warnmsg);
2313
0
    }
2314
298k
    _PyErr_SetRaisedException(tstate, exc);
2315
2316
298k
    assert(ix >= 0 || value == NULL);
2317
298k
    return value;  // borrowed reference
2318
298k
}
2319
2320
PyObject *
2321
PyDict_GetItem(PyObject *op, PyObject *key)
2322
298k
{
2323
298k
    return dict_getitem(op, key,
2324
298k
            "Exception ignored in PyDict_GetItem(); consider using "
2325
298k
            "PyDict_GetItemRef() or PyDict_GetItemWithError()");
2326
298k
}
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
19.1k
{
2347
    // TODO: Thread safety
2348
19.1k
    PyObject *value;
2349
19.1k
    assert(PyDict_CheckExact((PyObject*)mp));
2350
19.1k
    assert(PyUnicode_CheckExact(key));
2351
2352
19.1k
    Py_hash_t hash = _PyObject_HashFast(key);
2353
19.1k
    if (hash == -1) {
2354
0
        dict_unhashable_type(key);
2355
0
        return -1;
2356
0
    }
2357
2358
19.1k
    return _Py_dict_lookup(mp, key, hash, &value);
2359
19.1k
}
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
28
{
2395
28
    PyObject *value;
2396
28
    Py_ssize_t ix = _Py_dict_lookup(op, key, hash, &value);
2397
28
    assert(ix >= 0 || value == NULL);
2398
28
    if (ix == DKIX_ERROR) {
2399
0
        *result = NULL;
2400
0
        return -1;
2401
0
    }
2402
28
    if (value == NULL) {
2403
8
        *result = NULL;
2404
8
        return 0;  // missing key
2405
8
    }
2406
20
    *result = Py_NewRef(value);
2407
20
    return 1;  // key is present
2408
28
}
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
372M
{
2417
372M
    PyObject *value;
2418
#ifdef Py_GIL_DISABLED
2419
    Py_ssize_t ix = _Py_dict_lookup_threadsafe(op, key, hash, &value);
2420
#else
2421
372M
    Py_ssize_t ix = _Py_dict_lookup(op, key, hash, &value);
2422
372M
#endif
2423
372M
    assert(ix >= 0 || value == NULL);
2424
372M
    if (ix == DKIX_ERROR) {
2425
0
        *result = NULL;
2426
0
        return -1;
2427
0
    }
2428
372M
    if (value == NULL) {
2429
220M
        *result = NULL;
2430
220M
        return 0;  // missing key
2431
220M
    }
2432
#ifdef Py_GIL_DISABLED
2433
    *result = value;
2434
#else
2435
152M
    *result = Py_NewRef(value);
2436
152M
#endif
2437
152M
    return 1;  // key is present
2438
372M
}
2439
2440
int
2441
PyDict_GetItemRef(PyObject *op, PyObject *key, PyObject **result)
2442
148M
{
2443
148M
    if (!PyDict_Check(op)) {
2444
0
        PyErr_BadInternalCall();
2445
0
        *result = NULL;
2446
0
        return -1;
2447
0
    }
2448
2449
148M
    Py_hash_t hash = _PyObject_HashFast(key);
2450
148M
    if (hash == -1) {
2451
0
        dict_unhashable_type(key);
2452
0
        *result = NULL;
2453
0
        return -1;
2454
0
    }
2455
2456
148M
    return _PyDict_GetItemRef_KnownHash((PyDictObject *)op, key, hash, result);
2457
148M
}
2458
2459
int
2460
_PyDict_GetItemRef_Unicode_LockHeld(PyDictObject *op, PyObject *key, PyObject **result)
2461
11.3k
{
2462
11.3k
    ASSERT_DICT_LOCKED(op);
2463
11.3k
    assert(PyUnicode_CheckExact(key));
2464
2465
11.3k
    Py_hash_t hash = _PyObject_HashFast(key);
2466
11.3k
    if (hash == -1) {
2467
0
        dict_unhashable_type(key);
2468
0
        *result = NULL;
2469
0
        return -1;
2470
0
    }
2471
2472
11.3k
    PyObject *value;
2473
11.3k
    Py_ssize_t ix = _Py_dict_lookup(op, key, hash, &value);
2474
11.3k
    assert(ix >= 0 || value == NULL);
2475
11.3k
    if (ix == DKIX_ERROR) {
2476
0
        *result = NULL;
2477
0
        return -1;
2478
0
    }
2479
11.3k
    if (value == NULL) {
2480
4.99k
        *result = NULL;
2481
4.99k
        return 0;  // missing key
2482
4.99k
    }
2483
6.33k
    *result = Py_NewRef(value);
2484
6.33k
    return 1;  // key is present
2485
11.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
16.9M
{
2494
16.9M
    Py_ssize_t ix; (void)ix;
2495
16.9M
    Py_hash_t hash;
2496
16.9M
    PyDictObject*mp = (PyDictObject *)op;
2497
16.9M
    PyObject *value;
2498
2499
16.9M
    if (!PyDict_Check(op)) {
2500
0
        PyErr_BadInternalCall();
2501
0
        return NULL;
2502
0
    }
2503
16.9M
    hash = _PyObject_HashFast(key);
2504
16.9M
    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
16.9M
    ix = _Py_dict_lookup(mp, key, hash, &value);
2514
16.9M
#endif
2515
16.9M
    assert(ix >= 0 || value == NULL);
2516
16.9M
    return value;  // borrowed reference
2517
16.9M
}
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
94
{
2570
94
    Py_ssize_t ix;
2571
94
    Py_hash_t hash;
2572
94
    PyObject *value;
2573
2574
94
    hash = _PyObject_HashFast(key);
2575
94
    if (hash == -1) {
2576
0
        return NULL;
2577
0
    }
2578
2579
    /* namespace 1: globals */
2580
94
    ix = _Py_dict_lookup_threadsafe(globals, key, hash, &value);
2581
94
    if (ix == DKIX_ERROR)
2582
0
        return NULL;
2583
94
    if (ix != DKIX_EMPTY && value != NULL)
2584
10
        return value;
2585
2586
    /* namespace 2: builtins */
2587
84
    ix = _Py_dict_lookup_threadsafe(builtins, key, hash, &value);
2588
84
    assert(ix >= 0 || value == NULL);
2589
84
    return value;
2590
94
}
2591
2592
void
2593
_PyDict_LoadGlobalStackRef(PyDictObject *globals, PyDictObject *builtins, PyObject *key, _PyStackRef *res)
2594
85.3k
{
2595
85.3k
    Py_ssize_t ix;
2596
85.3k
    Py_hash_t hash;
2597
2598
85.3k
    hash = _PyObject_HashFast(key);
2599
85.3k
    if (hash == -1) {
2600
0
        *res = PyStackRef_NULL;
2601
0
        return;
2602
0
    }
2603
2604
    /* namespace 1: globals */
2605
85.3k
    ix = _Py_dict_lookup_threadsafe_stackref(globals, key, hash, res);
2606
85.3k
    if (ix == DKIX_ERROR) {
2607
0
        return;
2608
0
    }
2609
85.3k
    if (ix != DKIX_EMPTY && !PyStackRef_IsNull(*res)) {
2610
33.2k
        return;
2611
33.2k
    }
2612
2613
    /* namespace 2: builtins */
2614
52.1k
    ix = _Py_dict_lookup_threadsafe_stackref(builtins, key, hash, res);
2615
52.1k
    assert(ix >= 0 || PyStackRef_IsNull(*res));
2616
52.1k
}
2617
2618
PyObject *
2619
_PyDict_LoadBuiltinsFromGlobals(PyObject *globals)
2620
13.5M
{
2621
13.5M
    if (!PyDict_Check(globals)) {
2622
0
        PyErr_BadInternalCall();
2623
0
        return NULL;
2624
0
    }
2625
2626
13.5M
    PyDictObject *mp = (PyDictObject *)globals;
2627
13.5M
    PyObject *key = &_Py_ID(__builtins__);
2628
13.5M
    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.5M
    _PyStackRef ref;
2635
13.5M
    Py_ssize_t ix = _Py_dict_lookup_threadsafe_stackref(mp, key, hash, &ref);
2636
13.5M
    if (ix == DKIX_ERROR) {
2637
0
        return NULL;
2638
0
    }
2639
13.5M
    if (PyStackRef_IsNull(ref)) {
2640
0
        return Py_NewRef(PyEval_GetBuiltins());
2641
0
    }
2642
13.5M
    PyObject *builtins = PyStackRef_AsPyObjectBorrow(ref);
2643
13.5M
    if (PyModule_Check(builtins)) {
2644
32
        builtins = _PyModule_GetDict(builtins);
2645
32
        assert(builtins != NULL);
2646
32
    }
2647
13.5M
    _Py_INCREF_BUILTINS(builtins);
2648
13.5M
    PyStackRef_CLOSE(ref);
2649
13.5M
    return builtins;
2650
13.5M
}
2651
2652
/* Consumes references to key and value */
2653
static int
2654
setitem_take2_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
2655
415M
{
2656
415M
    ASSERT_DICT_LOCKED(mp);
2657
2658
415M
    assert(key);
2659
415M
    assert(value);
2660
415M
    assert(PyDict_Check(mp));
2661
415M
    Py_hash_t hash = _PyObject_HashFast(key);
2662
415M
    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
415M
    PyInterpreterState *interp = _PyInterpreterState_GET();
2670
2671
415M
    if (mp->ma_keys == Py_EMPTY_KEYS) {
2672
29.2M
        return insert_to_emptydict(interp, mp, key, hash, value);
2673
29.2M
    }
2674
    /* insertdict() handles any resizing that might be necessary */
2675
386M
    return insertdict(interp, mp, key, hash, value);
2676
415M
}
2677
2678
int
2679
_PyDict_SetItem_Take2(PyDictObject *mp, PyObject *key, PyObject *value)
2680
395M
{
2681
395M
    int res;
2682
395M
    Py_BEGIN_CRITICAL_SECTION(mp);
2683
395M
    res = setitem_take2_lock_held(mp, key, value);
2684
395M
    Py_END_CRITICAL_SECTION();
2685
395M
    return res;
2686
395M
}
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.54M
{
2697
6.54M
    if (!PyDict_Check(op)) {
2698
0
        PyErr_BadInternalCall();
2699
0
        return -1;
2700
0
    }
2701
6.54M
    assert(key);
2702
6.54M
    assert(value);
2703
6.54M
    return _PyDict_SetItem_Take2((PyDictObject *)op,
2704
6.54M
                                 Py_NewRef(key), Py_NewRef(value));
2705
6.54M
}
2706
2707
static int
2708
setitem_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
2709
20.6M
{
2710
20.6M
    assert(key);
2711
20.6M
    assert(value);
2712
20.6M
    return setitem_take2_lock_held(mp,
2713
20.6M
                                   Py_NewRef(key), Py_NewRef(value));
2714
20.6M
}
2715
2716
2717
int
2718
_PyDict_SetItem_KnownHash_LockHeld(PyDictObject *mp, PyObject *key, PyObject *value,
2719
                                   Py_hash_t hash)
2720
156
{
2721
156
    PyInterpreterState *interp = _PyInterpreterState_GET();
2722
156
    if (mp->ma_keys == Py_EMPTY_KEYS) {
2723
18
        return insert_to_emptydict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value));
2724
18
    }
2725
    /* insertdict() handles any resizing that might be necessary */
2726
138
    return insertdict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value));
2727
156
}
2728
2729
int
2730
_PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
2731
                          Py_hash_t hash)
2732
152
{
2733
152
    if (!PyDict_Check(op)) {
2734
0
        PyErr_BadInternalCall();
2735
0
        return -1;
2736
0
    }
2737
152
    assert(key);
2738
152
    assert(value);
2739
152
    assert(hash != -1);
2740
2741
152
    int res;
2742
152
    Py_BEGIN_CRITICAL_SECTION(op);
2743
152
    res = _PyDict_SetItem_KnownHash_LockHeld((PyDictObject *)op, key, value, hash);
2744
152
    Py_END_CRITICAL_SECTION();
2745
152
    return res;
2746
152
}
2747
2748
static void
2749
delete_index_from_values(PyDictValues *values, Py_ssize_t ix)
2750
240k
{
2751
240k
    uint8_t *array = get_insertion_order_array(values);
2752
240k
    int size = values->size;
2753
240k
    assert(size <= values->capacity);
2754
240k
    int i;
2755
641k
    for (i = 0; array[i] != ix; i++) {
2756
400k
        assert(i < size);
2757
400k
    }
2758
240k
    assert(i < size);
2759
240k
    size--;
2760
561k
    for (; i < size; i++) {
2761
320k
        array[i] = array[i+1];
2762
320k
    }
2763
240k
    values->size = size;
2764
240k
}
2765
2766
static void
2767
delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
2768
               PyObject *old_value)
2769
3.23M
{
2770
3.23M
    PyObject *old_key;
2771
2772
3.23M
    ASSERT_DICT_LOCKED(mp);
2773
2774
3.23M
    Py_ssize_t hashpos = lookdict_index(mp->ma_keys, hash, ix);
2775
3.23M
    assert(hashpos >= 0);
2776
2777
3.23M
    STORE_USED(mp, mp->ma_used - 1);
2778
3.23M
    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.23M
    else {
2787
3.23M
        FT_ATOMIC_STORE_UINT32_RELAXED(mp->ma_keys->dk_version, 0);
2788
3.23M
        dictkeys_set_index(mp->ma_keys, hashpos, DKIX_DUMMY);
2789
3.23M
        if (DK_IS_UNICODE(mp->ma_keys)) {
2790
1.24M
            PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[ix];
2791
1.24M
            old_key = ep->me_key;
2792
1.24M
            STORE_KEY(ep, NULL);
2793
1.24M
            STORE_VALUE(ep, NULL);
2794
1.24M
        }
2795
1.98M
        else {
2796
1.98M
            PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[ix];
2797
1.98M
            old_key = ep->me_key;
2798
1.98M
            STORE_KEY(ep, NULL);
2799
1.98M
            STORE_VALUE(ep, NULL);
2800
1.98M
            STORE_HASH(ep, 0);
2801
1.98M
        }
2802
3.23M
        Py_DECREF(old_key);
2803
3.23M
    }
2804
3.23M
    Py_DECREF(old_value);
2805
2806
3.23M
    ASSERT_CONSISTENT(mp);
2807
3.23M
}
2808
2809
int
2810
PyDict_DelItem(PyObject *op, PyObject *key)
2811
2.44M
{
2812
2.44M
    assert(key);
2813
2.44M
    Py_hash_t hash = _PyObject_HashFast(key);
2814
2.44M
    if (hash == -1) {
2815
0
        dict_unhashable_type(key);
2816
0
        return -1;
2817
0
    }
2818
2819
2.44M
    return _PyDict_DelItem_KnownHash(op, key, hash);
2820
2.44M
}
2821
2822
static int
2823
delitem_knownhash_lock_held(PyObject *op, PyObject *key, Py_hash_t hash)
2824
2.46M
{
2825
2.46M
    Py_ssize_t ix;
2826
2.46M
    PyDictObject *mp;
2827
2.46M
    PyObject *old_value;
2828
2829
2.46M
    if (!PyDict_Check(op)) {
2830
0
        PyErr_BadInternalCall();
2831
0
        return -1;
2832
0
    }
2833
2834
2.46M
    ASSERT_DICT_LOCKED(op);
2835
2836
2.46M
    assert(key);
2837
2.46M
    assert(hash != -1);
2838
2.46M
    mp = (PyDictObject *)op;
2839
2.46M
    ix = _Py_dict_lookup(mp, key, hash, &old_value);
2840
2.46M
    if (ix == DKIX_ERROR)
2841
0
        return -1;
2842
2.46M
    if (ix == DKIX_EMPTY || old_value == NULL) {
2843
0
        _PyErr_SetKeyError(key);
2844
0
        return -1;
2845
0
    }
2846
2847
2.46M
    PyInterpreterState *interp = _PyInterpreterState_GET();
2848
2.46M
    _PyDict_NotifyEvent(interp, PyDict_EVENT_DELETED, mp, key, NULL);
2849
2.46M
    delitem_common(mp, hash, ix, old_value);
2850
2.46M
    return 0;
2851
2.46M
}
2852
2853
int
2854
_PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
2855
2.44M
{
2856
2.44M
    int res;
2857
2.44M
    Py_BEGIN_CRITICAL_SECTION(op);
2858
2.44M
    res = delitem_knownhash_lock_held(op, key, hash);
2859
2.44M
    Py_END_CRITICAL_SECTION();
2860
2.44M
    return res;
2861
2.44M
}
2862
2863
static int
2864
delitemif_lock_held(PyObject *op, PyObject *key,
2865
                    int (*predicate)(PyObject *value, void *arg),
2866
                    void *arg)
2867
2.78k
{
2868
2.78k
    Py_ssize_t ix;
2869
2.78k
    PyDictObject *mp;
2870
2.78k
    Py_hash_t hash;
2871
2.78k
    PyObject *old_value;
2872
2.78k
    int res;
2873
2874
2.78k
    ASSERT_DICT_LOCKED(op);
2875
2876
2.78k
    assert(key);
2877
2.78k
    hash = PyObject_Hash(key);
2878
2.78k
    if (hash == -1)
2879
0
        return -1;
2880
2.78k
    mp = (PyDictObject *)op;
2881
2.78k
    ix = _Py_dict_lookup(mp, key, hash, &old_value);
2882
2.78k
    if (ix == DKIX_ERROR) {
2883
0
        return -1;
2884
0
    }
2885
2.78k
    if (ix == DKIX_EMPTY || old_value == NULL) {
2886
0
        return 0;
2887
0
    }
2888
2889
2.78k
    res = predicate(old_value, arg);
2890
2.78k
    if (res == -1)
2891
0
        return -1;
2892
2893
2.78k
    if (res > 0) {
2894
2.78k
        PyInterpreterState *interp = _PyInterpreterState_GET();
2895
2.78k
        _PyDict_NotifyEvent(interp, PyDict_EVENT_DELETED, mp, key, NULL);
2896
2.78k
        delitem_common(mp, hash, ix, old_value);
2897
2.78k
        return 1;
2898
2.78k
    } else {
2899
0
        return 0;
2900
0
    }
2901
2.78k
}
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
2.78k
{
2912
2.78k
    assert(PyDict_Check(op));
2913
2.78k
    int res;
2914
2.78k
    Py_BEGIN_CRITICAL_SECTION(op);
2915
2.78k
    res = delitemif_lock_held(op, key, predicate, arg);
2916
2.78k
    Py_END_CRITICAL_SECTION();
2917
2.78k
    return res;
2918
2.78k
}
2919
2920
static void
2921
clear_lock_held(PyObject *op)
2922
589k
{
2923
589k
    PyDictObject *mp;
2924
589k
    PyDictKeysObject *oldkeys;
2925
589k
    PyDictValues *oldvalues;
2926
589k
    Py_ssize_t i, n;
2927
2928
589k
    ASSERT_DICT_LOCKED(op);
2929
2930
589k
    if (!PyDict_Check(op))
2931
0
        return;
2932
589k
    mp = ((PyDictObject *)op);
2933
589k
    oldkeys = mp->ma_keys;
2934
589k
    oldvalues = mp->ma_values;
2935
589k
    if (oldkeys == Py_EMPTY_KEYS) {
2936
294k
        return;
2937
294k
    }
2938
    /* Empty the dict... */
2939
295k
    PyInterpreterState *interp = _PyInterpreterState_GET();
2940
295k
    _PyDict_NotifyEvent(interp, PyDict_EVENT_CLEARED, mp, NULL, NULL);
2941
    // We don't inc ref empty keys because they're immortal
2942
295k
    ensure_shared_on_resize(mp);
2943
295k
    STORE_USED(mp, 0);
2944
295k
    if (oldvalues == NULL) {
2945
295k
        set_keys(mp, Py_EMPTY_KEYS);
2946
295k
        assert(oldkeys->dk_refcnt == 1);
2947
295k
        dictkeys_decref(oldkeys, IS_DICT_SHARED(mp));
2948
295k
    }
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
295k
    ASSERT_CONSISTENT(mp);
2965
295k
}
2966
2967
void
2968
0
_PyDict_Clear_LockHeld(PyObject *op) {
2969
0
    clear_lock_held(op);
2970
0
}
2971
2972
void
2973
PyDict_Clear(PyObject *op)
2974
589k
{
2975
589k
    Py_BEGIN_CRITICAL_SECTION(op);
2976
589k
    clear_lock_held(op);
2977
589k
    Py_END_CRITICAL_SECTION();
2978
589k
}
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
20.2M
{
2989
20.2M
    Py_ssize_t i;
2990
20.2M
    PyDictObject *mp;
2991
20.2M
    PyObject *key, *value;
2992
20.2M
    Py_hash_t hash;
2993
2994
20.2M
    if (!PyDict_Check(op))
2995
0
        return 0;
2996
2997
20.2M
    mp = (PyDictObject *)op;
2998
20.2M
    i = *ppos;
2999
20.2M
    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
20.2M
    else {
3010
20.2M
        Py_ssize_t n = mp->ma_keys->dk_nentries;
3011
20.2M
        if (i < 0 || i >= n)
3012
8.14M
            return 0;
3013
12.1M
        if (DK_IS_UNICODE(mp->ma_keys)) {
3014
12.0M
            PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(mp->ma_keys)[i];
3015
12.6M
            while (i < n && entry_ptr->me_value == NULL) {
3016
594k
                entry_ptr++;
3017
594k
                i++;
3018
594k
            }
3019
12.0M
            if (i >= n)
3020
294k
                return 0;
3021
11.7M
            key = entry_ptr->me_key;
3022
11.7M
            hash = unicode_get_hash(entry_ptr->me_key);
3023
11.7M
            value = entry_ptr->me_value;
3024
11.7M
        }
3025
76.3k
        else {
3026
76.3k
            PyDictKeyEntry *entry_ptr = &DK_ENTRIES(mp->ma_keys)[i];
3027
76.3k
            while (i < n && entry_ptr->me_value == NULL) {
3028
0
                entry_ptr++;
3029
0
                i++;
3030
0
            }
3031
76.3k
            if (i >= n)
3032
0
                return 0;
3033
76.3k
            key = entry_ptr->me_key;
3034
76.3k
            hash = entry_ptr->me_hash;
3035
76.3k
            value = entry_ptr->me_value;
3036
76.3k
        }
3037
12.1M
    }
3038
11.8M
    *ppos = i+1;
3039
11.8M
    if (pkey)
3040
11.8M
        *pkey = key;
3041
11.8M
    if (pvalue)
3042
11.7M
        *pvalue = value;
3043
11.8M
    if (phash)
3044
1.50M
        *phash = hash;
3045
11.8M
    return 1;
3046
20.2M
}
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
18.0M
{
3069
18.0M
    return _PyDict_Next(op, ppos, pkey, pvalue, NULL);
3070
18.0M
}
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
770k
{
3078
770k
    assert(PyDict_Check(mp));
3079
3080
770k
    ASSERT_DICT_LOCKED(mp);
3081
3082
770k
    if (mp->ma_used == 0) {
3083
0
        if (result) {
3084
0
            *result = NULL;
3085
0
        }
3086
0
        return 0;
3087
0
    }
3088
3089
770k
    PyObject *old_value;
3090
770k
    Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &old_value);
3091
770k
    if (ix == DKIX_ERROR) {
3092
0
        if (result) {
3093
0
            *result = NULL;
3094
0
        }
3095
0
        return -1;
3096
0
    }
3097
3098
770k
    if (ix == DKIX_EMPTY || old_value == NULL) {
3099
3.54k
        if (result) {
3100
974
            *result = NULL;
3101
974
        }
3102
3.54k
        return 0;
3103
3.54k
    }
3104
3105
767k
    assert(old_value != NULL);
3106
767k
    PyInterpreterState *interp = _PyInterpreterState_GET();
3107
767k
    _PyDict_NotifyEvent(interp, PyDict_EVENT_DELETED, mp, key, NULL);
3108
767k
    delitem_common(mp, hash, ix, Py_NewRef(old_value));
3109
3110
767k
    ASSERT_CONSISTENT(mp);
3111
767k
    if (result) {
3112
767k
        *result = old_value;
3113
767k
    }
3114
0
    else {
3115
0
        Py_DECREF(old_value);
3116
0
    }
3117
767k
    return 1;
3118
770k
}
3119
3120
static int
3121
pop_lock_held(PyObject *op, PyObject *key, PyObject **result)
3122
770k
{
3123
770k
    ASSERT_DICT_LOCKED(op);
3124
3125
770k
    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
770k
    PyDictObject *dict = (PyDictObject *)op;
3133
3134
770k
    if (dict->ma_used == 0) {
3135
12
        if (result) {
3136
12
            *result = NULL;
3137
12
        }
3138
12
        return 0;
3139
12
    }
3140
3141
770k
    Py_hash_t hash = _PyObject_HashFast(key);
3142
770k
    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
770k
    return _PyDict_Pop_KnownHash(dict, key, hash, result);
3150
770k
}
3151
3152
int
3153
PyDict_Pop(PyObject *op, PyObject *key, PyObject **result)
3154
770k
{
3155
770k
    int err;
3156
770k
    Py_BEGIN_CRITICAL_SECTION(op);
3157
770k
    err = pop_lock_held(op, key, result);
3158
770k
    Py_END_CRITICAL_SECTION();
3159
3160
770k
    return err;
3161
770k
}
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
294k
{
3184
294k
    PyObject *result;
3185
294k
    if (PyDict_Pop(dict, key, &result) == 0) {
3186
292
        if (default_value != NULL) {
3187
292
            return Py_NewRef(default_value);
3188
292
        }
3189
0
        _PyErr_SetKeyError(key);
3190
0
        return NULL;
3191
292
    }
3192
294k
    return result;
3193
294k
}
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
307
{
3257
307
    PyObject *it;       /* iter(iterable) */
3258
307
    PyObject *key;
3259
307
    PyObject *d;
3260
307
    int status;
3261
307
    PyInterpreterState *interp = _PyInterpreterState_GET();
3262
3263
307
    d = _PyObject_CallNoArgs(cls);
3264
307
    if (d == NULL)
3265
0
        return NULL;
3266
3267
3268
307
    if (PyDict_CheckExact(d)) {
3269
307
        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
307
        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
307
    }
3286
3287
307
    it = PyObject_GetIter(iterable);
3288
307
    if (it == NULL){
3289
0
        Py_DECREF(d);
3290
0
        return NULL;
3291
0
    }
3292
3293
307
    if (PyDict_CheckExact(d)) {
3294
307
        Py_BEGIN_CRITICAL_SECTION(d);
3295
1.45k
        while ((key = PyIter_Next(it)) != NULL) {
3296
1.14k
            status = setitem_lock_held((PyDictObject *)d, key, value);
3297
1.14k
            Py_DECREF(key);
3298
1.14k
            if (status < 0) {
3299
0
                assert(PyErr_Occurred());
3300
0
                goto dict_iter_exit;
3301
0
            }
3302
1.14k
        }
3303
307
dict_iter_exit:;
3304
307
        Py_END_CRITICAL_SECTION();
3305
307
    } 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
307
    if (PyErr_Occurred())
3315
0
        goto Fail;
3316
307
    Py_DECREF(it);
3317
307
    return d;
3318
3319
0
Fail:
3320
0
    Py_DECREF(it);
3321
0
    Py_DECREF(d);
3322
0
    return NULL;
3323
307
}
3324
3325
/* Methods */
3326
3327
static void
3328
dict_dealloc(PyObject *self)
3329
311M
{
3330
311M
    PyDictObject *mp = (PyDictObject *)self;
3331
311M
    PyInterpreterState *interp = _PyInterpreterState_GET();
3332
311M
    _PyObject_ResurrectStart(self);
3333
311M
    _PyDict_NotifyEvent(interp, PyDict_EVENT_DEALLOCATED, mp, NULL, NULL);
3334
311M
    if (_PyObject_ResurrectEnd(self)) {
3335
0
        return;
3336
0
    }
3337
311M
    PyDictValues *values = mp->ma_values;
3338
311M
    PyDictKeysObject *keys = mp->ma_keys;
3339
311M
    Py_ssize_t i, n;
3340
3341
    /* bpo-31095: UnTrack is needed before calling any callbacks */
3342
311M
    PyObject_GC_UnTrack(mp);
3343
311M
    if (values != NULL) {
3344
117
        if (values->embedded == 0) {
3345
3.62k
            for (i = 0, n = values->capacity; i < n; i++) {
3346
3.51k
                Py_XDECREF(values->values[i]);
3347
3.51k
            }
3348
117
            free_values(values, false);
3349
117
        }
3350
117
        dictkeys_decref(keys, false);
3351
117
    }
3352
311M
    else if (keys != NULL) {
3353
311M
        assert(keys->dk_refcnt == 1 || keys == Py_EMPTY_KEYS);
3354
311M
        dictkeys_decref(keys, false);
3355
311M
    }
3356
311M
    if (Py_IS_TYPE(mp, &PyDict_Type)) {
3357
311M
        _Py_FREELIST_FREE(dicts, mp, Py_TYPE(mp)->tp_free);
3358
311M
    }
3359
110
    else {
3360
110
        Py_TYPE(mp)->tp_free((PyObject *)mp);
3361
110
    }
3362
311M
}
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
764k
{
3464
764k
    return FT_ATOMIC_LOAD_SSIZE_RELAXED(((PyDictObject *)self)->ma_used);
3465
764k
}
3466
3467
static PyObject *
3468
dict_subscript(PyObject *self, PyObject *key)
3469
1.05M
{
3470
1.05M
    PyDictObject *mp = (PyDictObject *)self;
3471
1.05M
    Py_ssize_t ix;
3472
1.05M
    Py_hash_t hash;
3473
1.05M
    PyObject *value;
3474
3475
1.05M
    hash = _PyObject_HashFast(key);
3476
1.05M
    if (hash == -1) {
3477
0
        dict_unhashable_type(key);
3478
0
        return NULL;
3479
0
    }
3480
1.05M
    ix = _Py_dict_lookup_threadsafe(mp, key, hash, &value);
3481
1.05M
    if (ix == DKIX_ERROR)
3482
0
        return NULL;
3483
1.05M
    if (ix == DKIX_EMPTY || value == NULL) {
3484
358
        if (!PyDict_CheckExact(mp)) {
3485
            /* Look up __missing__ method if we're a subclass. */
3486
262
            PyObject *missing, *res;
3487
262
            missing = _PyObject_LookupSpecial(
3488
262
                    (PyObject *)mp, &_Py_ID(__missing__));
3489
262
            if (missing != NULL) {
3490
0
                res = PyObject_CallOneArg(missing, key);
3491
0
                Py_DECREF(missing);
3492
0
                return res;
3493
0
            }
3494
262
            else if (PyErr_Occurred())
3495
0
                return NULL;
3496
262
        }
3497
358
        _PyErr_SetKeyError(key);
3498
358
        return NULL;
3499
358
    }
3500
1.05M
    return value;
3501
1.05M
}
3502
3503
static int
3504
dict_ass_sub(PyObject *mp, PyObject *v, PyObject *w)
3505
464k
{
3506
464k
    if (w == NULL)
3507
461k
        return PyDict_DelItem(mp, v);
3508
2.45k
    else
3509
2.45k
        return PyDict_SetItem(mp, v, w);
3510
464k
}
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
13.2k
{
3521
13.2k
    ASSERT_DICT_LOCKED(dict);
3522
3523
13.2k
    if (dict == NULL || !PyDict_Check(dict)) {
3524
0
        PyErr_BadInternalCall();
3525
0
        return NULL;
3526
0
    }
3527
13.2k
    PyDictObject *mp = (PyDictObject *)dict;
3528
13.2k
    PyObject *v;
3529
13.2k
    Py_ssize_t n;
3530
3531
13.2k
  again:
3532
13.2k
    n = mp->ma_used;
3533
13.2k
    v = PyList_New(n);
3534
13.2k
    if (v == NULL)
3535
0
        return NULL;
3536
13.2k
    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
13.2k
    Py_ssize_t j = 0, pos = 0;
3546
13.2k
    PyObject *key;
3547
115k
    while (_PyDict_Next((PyObject*)mp, &pos, &key, NULL, NULL)) {
3548
101k
        assert(j < n);
3549
101k
        PyList_SET_ITEM(v, j, Py_NewRef(key));
3550
101k
        j++;
3551
101k
    }
3552
13.2k
    assert(j == n);
3553
13.2k
    return v;
3554
13.2k
}
3555
3556
PyObject *
3557
PyDict_Keys(PyObject *dict)
3558
13.2k
{
3559
13.2k
    PyObject *res;
3560
13.2k
    Py_BEGIN_CRITICAL_SECTION(dict);
3561
13.2k
    res = keys_lock_held(dict);
3562
13.2k
    Py_END_CRITICAL_SECTION();
3563
3564
13.2k
    return res;
3565
13.2k
}
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
307
{
3693
307
    return _PyDict_FromKeys((PyObject *)type, iterable, value);
3694
307
}
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
653
{
3700
653
    if (PyDict_CheckExact(arg)) {
3701
393
        return PyDict_Merge(self, arg, 1);
3702
393
    }
3703
260
    int has_keys = PyObject_HasAttrWithError(arg, &_Py_ID(keys));
3704
260
    if (has_keys < 0) {
3705
0
        return -1;
3706
0
    }
3707
260
    if (has_keys) {
3708
150
        return PyDict_Merge(self, arg, 1);
3709
150
    }
3710
110
    return PyDict_MergeFromSeq2(self, arg, 1);
3711
260
}
3712
3713
static int
3714
dict_update_common(PyObject *self, PyObject *args, PyObject *kwds,
3715
                   const char *methname)
3716
621
{
3717
621
    PyObject *arg = NULL;
3718
621
    int result = 0;
3719
3720
621
    if (!PyArg_UnpackTuple(args, methname, 0, 1, &arg)) {
3721
0
        result = -1;
3722
0
    }
3723
621
    else if (arg != NULL) {
3724
521
        result = dict_update_arg(self, arg);
3725
521
    }
3726
3727
621
    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
621
    return result;
3734
621
}
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
521
{
3742
521
    if (dict_update_common(self, args, kwds, "update") != -1)
3743
521
        Py_RETURN_NONE;
3744
0
    return NULL;
3745
521
}
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
110
{
3760
110
    PyObject *it;       /* iter(seq2) */
3761
110
    Py_ssize_t i;       /* index into seq2 of current element */
3762
110
    PyObject *item;     /* seq2[i] */
3763
110
    PyObject *fast;     /* item as a 2-tuple or 2-list */
3764
3765
110
    assert(d != NULL);
3766
110
    assert(PyDict_Check(d));
3767
110
    assert(seq2 != NULL);
3768
3769
110
    it = PyObject_GetIter(seq2);
3770
110
    if (it == NULL)
3771
0
        return -1;
3772
3773
1.46k
    for (i = 0; ; ++i) {
3774
1.46k
        PyObject *key, *value;
3775
1.46k
        Py_ssize_t n;
3776
3777
1.46k
        fast = NULL;
3778
1.46k
        item = PyIter_Next(it);
3779
1.46k
        if (item == NULL) {
3780
110
            if (PyErr_Occurred())
3781
0
                goto Fail;
3782
110
            break;
3783
110
        }
3784
3785
        /* Convert item to sequence, and verify length 2. */
3786
1.35k
        fast = PySequence_Fast(item, "object is not iterable");
3787
1.35k
        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
1.35k
        n = PySequence_Fast_GET_SIZE(fast);
3797
1.35k
        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
1.35k
        key = PySequence_Fast_GET_ITEM(fast, 0);
3807
1.35k
        value = PySequence_Fast_GET_ITEM(fast, 1);
3808
1.35k
        Py_INCREF(key);
3809
1.35k
        Py_INCREF(value);
3810
1.35k
        if (override) {
3811
1.35k
            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
1.35k
        }
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
1.35k
        Py_DECREF(key);
3826
1.35k
        Py_DECREF(value);
3827
1.35k
        Py_DECREF(fast);
3828
1.35k
        Py_DECREF(item);
3829
1.35k
    }
3830
3831
110
    i = 0;
3832
110
    ASSERT_CONSISTENT(d);
3833
110
    goto Return;
3834
0
Fail:
3835
0
    Py_XDECREF(item);
3836
0
    Py_XDECREF(fast);
3837
0
    i = -1;
3838
110
Return:
3839
110
    Py_DECREF(it);
3840
110
    return Py_SAFE_DOWNCAST(i, Py_ssize_t, int);
3841
0
}
3842
3843
int
3844
PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override)
3845
110
{
3846
110
    int res;
3847
110
    Py_BEGIN_CRITICAL_SECTION(d);
3848
110
    res = merge_from_seq2_lock_held(d, seq2, override);
3849
110
    Py_END_CRITICAL_SECTION();
3850
3851
110
    return res;
3852
110
}
3853
3854
static int
3855
dict_dict_merge(PyInterpreterState *interp, PyDictObject *mp, PyDictObject *other, int override)
3856
18.6M
{
3857
18.6M
    ASSERT_DICT_LOCKED(mp);
3858
18.6M
    ASSERT_DICT_LOCKED(other);
3859
3860
18.6M
    if (other == mp || other->ma_used == 0)
3861
        /* a.update(a) or a.update({}); nothing to do */
3862
17.7M
        return 0;
3863
887k
    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
885k
        override = 1;
3869
885k
        PyDictKeysObject *okeys = other->ma_keys;
3870
3871
        // If other is clean, combined, and just allocated, just clone it.
3872
885k
        if (mp->ma_values == NULL &&
3873
885k
            other->ma_values == NULL &&
3874
885k
            other->ma_used == okeys->dk_nentries &&
3875
885k
            (DK_LOG_SIZE(okeys) == PyDict_LOG_MINSIZE ||
3876
298k
             USABLE_FRACTION(DK_SIZE(okeys)/2) < other->ma_used)
3877
885k
        ) {
3878
298k
            _PyDict_NotifyEvent(interp, PyDict_EVENT_CLONED, mp, (PyObject *)other, NULL);
3879
298k
            PyDictKeysObject *keys = clone_combined_dict_keys(other);
3880
298k
            if (keys == NULL)
3881
0
                return -1;
3882
3883
298k
            ensure_shared_on_resize(mp);
3884
298k
            dictkeys_decref(mp->ma_keys, IS_DICT_SHARED(mp));
3885
298k
            set_keys(mp, keys);
3886
298k
            STORE_USED(mp, other->ma_used);
3887
298k
            ASSERT_CONSISTENT(mp);
3888
3889
298k
            if (_PyObject_GC_IS_TRACKED(other) && !_PyObject_GC_IS_TRACKED(mp)) {
3890
                /* Maintain tracking. */
3891
0
                _PyObject_GC_TRACK(mp);
3892
0
            }
3893
3894
298k
            return 0;
3895
298k
        }
3896
885k
    }
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
589k
    if (USABLE_FRACTION(DK_SIZE(mp->ma_keys)) < other->ma_used) {
3902
587k
        int unicode = DK_IS_UNICODE(other->ma_keys);
3903
587k
        if (dictresize(mp, estimate_log2_keysize(mp->ma_used + other->ma_used),
3904
587k
                        unicode)) {
3905
0
            return -1;
3906
0
        }
3907
587k
    }
3908
3909
589k
    Py_ssize_t orig_size = other->ma_used;
3910
589k
    Py_ssize_t pos = 0;
3911
589k
    Py_hash_t hash;
3912
589k
    PyObject *key, *value;
3913
3914
2.09M
    while (_PyDict_Next((PyObject*)other, &pos, &key, &value, &hash)) {
3915
1.50M
        int err = 0;
3916
1.50M
        Py_INCREF(key);
3917
1.50M
        Py_INCREF(value);
3918
1.50M
        if (override == 1) {
3919
1.50M
            err = insertdict(interp, mp,
3920
1.50M
                                Py_NewRef(key), hash, Py_NewRef(value));
3921
1.50M
        }
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.50M
        Py_DECREF(value);
3939
1.50M
        Py_DECREF(key);
3940
1.50M
        if (err != 0)
3941
0
            return -1;
3942
3943
1.50M
        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.50M
    }
3949
589k
    return 0;
3950
589k
}
3951
3952
static int
3953
dict_merge(PyInterpreterState *interp, PyObject *a, PyObject *b, int override)
3954
18.6M
{
3955
18.6M
    PyDictObject *mp, *other;
3956
3957
18.6M
    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
18.6M
    if (a == NULL || !PyDict_Check(a) || b == NULL) {
3965
0
        PyErr_BadInternalCall();
3966
0
        return -1;
3967
0
    }
3968
18.6M
    mp = (PyDictObject*)a;
3969
18.6M
    int res = 0;
3970
18.6M
    if (PyDict_Check(b) && (Py_TYPE(b)->tp_iter == dict_iter)) {
3971
18.6M
        other = (PyDictObject*)b;
3972
18.6M
        int res;
3973
18.6M
        Py_BEGIN_CRITICAL_SECTION2(a, b);
3974
18.6M
        res = dict_dict_merge(interp, (PyDictObject *)a, other, override);
3975
18.6M
        ASSERT_CONSISTENT(a);
3976
18.6M
        Py_END_CRITICAL_SECTION2();
3977
18.6M
        return res;
3978
18.6M
    }
3979
150
    else {
3980
        /* Do it the generic, slower way */
3981
150
        Py_BEGIN_CRITICAL_SECTION(a);
3982
150
        PyObject *keys = PyMapping_Keys(b);
3983
150
        PyObject *iter;
3984
150
        PyObject *key, *value;
3985
150
        int status;
3986
3987
150
        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
150
        iter = PyObject_GetIter(keys);
3998
150
        Py_DECREF(keys);
3999
150
        if (iter == NULL) {
4000
0
            res = -1;
4001
0
            goto slow_exit;
4002
0
        }
4003
4004
3.59k
        for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) {
4005
3.44k
            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
3.44k
            value = PyObject_GetItem(b, key);
4022
3.44k
            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
3.44k
            status = setitem_lock_held(mp, key, value);
4029
3.44k
            Py_DECREF(key);
4030
3.44k
            Py_DECREF(value);
4031
3.44k
            if (status < 0) {
4032
0
                Py_DECREF(iter);
4033
0
                res = -1;
4034
0
                goto slow_exit;
4035
0
                return -1;
4036
0
            }
4037
3.44k
        }
4038
150
        Py_DECREF(iter);
4039
150
        if (PyErr_Occurred()) {
4040
            /* Iterator completed, via error */
4041
0
            res = -1;
4042
0
            goto slow_exit;
4043
0
        }
4044
4045
150
slow_exit:
4046
150
        ASSERT_CONSISTENT(a);
4047
150
        Py_END_CRITICAL_SECTION();
4048
150
        return res;
4049
150
    }
4050
18.6M
}
4051
4052
int
4053
PyDict_Update(PyObject *a, PyObject *b)
4054
2.12k
{
4055
2.12k
    PyInterpreterState *interp = _PyInterpreterState_GET();
4056
2.12k
    return dict_merge(interp, a, b, 1);
4057
2.12k
}
4058
4059
int
4060
PyDict_Merge(PyObject *a, PyObject *b, int override)
4061
543
{
4062
543
    PyInterpreterState *interp = _PyInterpreterState_GET();
4063
    /* XXX Deprecate override not in (0, 1). */
4064
543
    return dict_merge(interp, a, b, override != 0);
4065
543
}
4066
4067
int
4068
_PyDict_MergeEx(PyObject *a, PyObject *b, int override)
4069
18.6M
{
4070
18.6M
    PyInterpreterState *interp = _PyInterpreterState_GET();
4071
18.6M
    return dict_merge(interp, a, b, override);
4072
18.6M
}
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
0
{
4084
0
    return PyDict_Copy((PyObject *)self);
4085
0
}
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
0
{
4093
0
    PyDictValues *newvalues = new_values(values->capacity);
4094
0
    if (newvalues == NULL) {
4095
0
        return NULL;
4096
0
    }
4097
0
    newvalues->size = values->size;
4098
0
    uint8_t *values_order = get_insertion_order_array(values);
4099
0
    uint8_t *new_values_order = get_insertion_order_array(newvalues);
4100
0
    memcpy(new_values_order, values_order, values->capacity);
4101
0
    for (int i = 0; i < values->capacity; i++) {
4102
0
        newvalues->values[i] = values->values[i];
4103
0
    }
4104
0
    assert(newvalues->embedded == 0);
4105
0
    return newvalues;
4106
0
}
4107
4108
static PyObject *
4109
copy_lock_held(PyObject *o)
4110
602k
{
4111
602k
    PyObject *copy;
4112
602k
    PyDictObject *mp;
4113
602k
    PyInterpreterState *interp = _PyInterpreterState_GET();
4114
4115
602k
    ASSERT_DICT_LOCKED(o);
4116
4117
602k
    mp = (PyDictObject *)o;
4118
602k
    if (mp->ma_used == 0) {
4119
        /* The dict is empty; just return a new dict. */
4120
295k
        return PyDict_New();
4121
295k
    }
4122
4123
307k
    if (_PyDict_HasSplitTable(mp)) {
4124
0
        PyDictObject *split_copy;
4125
0
        PyDictValues *newvalues = copy_values(mp->ma_values);
4126
0
        if (newvalues == NULL) {
4127
0
            return PyErr_NoMemory();
4128
0
        }
4129
0
        split_copy = PyObject_GC_New(PyDictObject, &PyDict_Type);
4130
0
        if (split_copy == NULL) {
4131
0
            free_values(newvalues, false);
4132
0
            return NULL;
4133
0
        }
4134
0
        for (size_t i = 0; i < newvalues->capacity; i++) {
4135
0
            Py_XINCREF(newvalues->values[i]);
4136
0
        }
4137
0
        split_copy->ma_values = newvalues;
4138
0
        split_copy->ma_keys = mp->ma_keys;
4139
0
        split_copy->ma_used = mp->ma_used;
4140
0
        split_copy->_ma_watcher_tag = 0;
4141
0
        dictkeys_incref(mp->ma_keys);
4142
0
        _PyObject_GC_TRACK(split_copy);
4143
0
        return (PyObject *)split_copy;
4144
0
    }
4145
4146
307k
    if (Py_TYPE(mp)->tp_iter == dict_iter &&
4147
307k
            mp->ma_values == NULL &&
4148
307k
            (mp->ma_used >= (mp->ma_keys->dk_nentries * 2) / 3))
4149
307k
    {
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
307k
        PyDictKeysObject *keys = clone_combined_dict_keys(mp);
4165
307k
        if (keys == NULL) {
4166
0
            return NULL;
4167
0
        }
4168
307k
        PyDictObject *new = (PyDictObject *)new_dict(keys, NULL, 0, 0);
4169
307k
        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
307k
        new->ma_used = mp->ma_used;
4176
307k
        ASSERT_CONSISTENT(new);
4177
307k
        return (PyObject *)new;
4178
307k
    }
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
602k
{
4192
602k
    if (o == NULL || !PyDict_Check(o)) {
4193
0
        PyErr_BadInternalCall();
4194
0
        return NULL;
4195
0
    }
4196
4197
602k
    PyObject *res;
4198
602k
    Py_BEGIN_CRITICAL_SECTION(o);
4199
4200
602k
    res = copy_lock_held(o);
4201
4202
602k
    Py_END_CRITICAL_SECTION();
4203
602k
    return res;
4204
602k
}
4205
4206
Py_ssize_t
4207
PyDict_Size(PyObject *mp)
4208
590k
{
4209
590k
    if (mp == NULL || !PyDict_Check(mp)) {
4210
0
        PyErr_BadInternalCall();
4211
0
        return -1;
4212
0
    }
4213
590k
    return FT_ATOMIC_LOAD_SSIZE_RELAXED(((PyDictObject *)mp)->ma_used);
4214
590k
}
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
51.2M
{
4328
51.2M
    int contains = PyDict_Contains((PyObject *)self, key);
4329
51.2M
    if (contains < 0) {
4330
0
        return NULL;
4331
0
    }
4332
51.2M
    if (contains) {
4333
47.0M
        Py_RETURN_TRUE;
4334
47.0M
    }
4335
51.2M
    Py_RETURN_FALSE;
4336
51.2M
}
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
592M
{
4352
592M
    PyObject *val = NULL;
4353
592M
    Py_hash_t hash;
4354
592M
    Py_ssize_t ix;
4355
4356
592M
    hash = _PyObject_HashFast(key);
4357
592M
    if (hash == -1) {
4358
0
        dict_unhashable_type(key);
4359
0
        return NULL;
4360
0
    }
4361
592M
    ix = _Py_dict_lookup_threadsafe(self, key, hash, &val);
4362
592M
    if (ix == DKIX_ERROR)
4363
0
        return NULL;
4364
592M
    if (ix == DKIX_EMPTY || val == NULL) {
4365
410M
        val = Py_NewRef(default_value);
4366
410M
    }
4367
592M
    return val;
4368
592M
}
4369
4370
static int
4371
dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_value,
4372
                    PyObject **result, int incref_result)
4373
114M
{
4374
114M
    PyDictObject *mp = (PyDictObject *)d;
4375
114M
    PyObject *value;
4376
114M
    Py_hash_t hash;
4377
114M
    PyInterpreterState *interp = _PyInterpreterState_GET();
4378
4379
114M
    ASSERT_DICT_LOCKED(d);
4380
4381
114M
    if (!PyDict_Check(d)) {
4382
0
        PyErr_BadInternalCall();
4383
0
        if (result) {
4384
0
            *result = NULL;
4385
0
        }
4386
0
        return -1;
4387
0
    }
4388
4389
114M
    hash = _PyObject_HashFast(key);
4390
114M
    if (hash == -1) {
4391
0
        dict_unhashable_type(key);
4392
0
        if (result) {
4393
0
            *result = NULL;
4394
0
        }
4395
0
        return -1;
4396
0
    }
4397
4398
114M
    if (mp->ma_keys == Py_EMPTY_KEYS) {
4399
448k
        if (insert_to_emptydict(interp, mp, Py_NewRef(key), hash,
4400
448k
                                Py_NewRef(default_value)) < 0) {
4401
0
            if (result) {
4402
0
                *result = NULL;
4403
0
            }
4404
0
            return -1;
4405
0
        }
4406
448k
        if (result) {
4407
448k
            *result = incref_result ? Py_NewRef(default_value) : default_value;
4408
448k
        }
4409
448k
        return 0;
4410
448k
    }
4411
4412
114M
    if (!PyUnicode_CheckExact(key) && DK_IS_UNICODE(mp->ma_keys)) {
4413
206
        if (insertion_resize(mp, 0) < 0) {
4414
0
            if (result) {
4415
0
                *result = NULL;
4416
0
            }
4417
0
            return -1;
4418
0
        }
4419
206
    }
4420
4421
114M
    if (_PyDict_HasSplitTable(mp)) {
4422
0
        Py_ssize_t ix = insert_split_key(mp->ma_keys, key, hash);
4423
0
        if (ix != DKIX_EMPTY) {
4424
0
            PyObject *value = mp->ma_values->values[ix];
4425
0
            int already_present = value != NULL;
4426
0
            if (!already_present) {
4427
0
                insert_split_value(interp, mp, key, default_value, ix);
4428
0
                value = default_value;
4429
0
            }
4430
0
            if (result) {
4431
0
                *result = incref_result ? Py_NewRef(value) : value;
4432
0
            }
4433
0
            return already_present;
4434
0
        }
4435
4436
        /* No space in shared keys. Resize and continue below. */
4437
0
        if (insertion_resize(mp, 1) < 0) {
4438
0
            goto error;
4439
0
        }
4440
0
    }
4441
4442
114M
    assert(!_PyDict_HasSplitTable(mp));
4443
4444
114M
    Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &value);
4445
114M
    if (ix == DKIX_ERROR) {
4446
0
        if (result) {
4447
0
            *result = NULL;
4448
0
        }
4449
0
        return -1;
4450
0
    }
4451
4452
114M
    if (ix == DKIX_EMPTY) {
4453
3.83M
        assert(!_PyDict_HasSplitTable(mp));
4454
3.83M
        value = default_value;
4455
4456
3.83M
        if (insert_combined_dict(interp, mp, hash, Py_NewRef(key), Py_NewRef(value)) < 0) {
4457
0
            Py_DECREF(key);
4458
0
            Py_DECREF(value);
4459
0
            if (result) {
4460
0
                *result = NULL;
4461
0
            }
4462
0
            return -1;
4463
0
        }
4464
4465
3.83M
        STORE_USED(mp, mp->ma_used + 1);
4466
3.83M
        assert(mp->ma_keys->dk_usable >= 0);
4467
3.83M
        ASSERT_CONSISTENT(mp);
4468
3.83M
        if (result) {
4469
3.81M
            *result = incref_result ? Py_NewRef(value) : value;
4470
3.81M
        }
4471
3.83M
        return 0;
4472
3.83M
    }
4473
4474
110M
    assert(value != NULL);
4475
110M
    ASSERT_CONSISTENT(mp);
4476
110M
    if (result) {
4477
110M
        *result = incref_result ? Py_NewRef(value) : value;
4478
110M
    }
4479
110M
    return 1;
4480
4481
0
error:
4482
0
    if (result) {
4483
0
        *result = NULL;
4484
0
    }
4485
0
    return -1;
4486
114M
}
4487
4488
int
4489
PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value,
4490
                     PyObject **result)
4491
4.78M
{
4492
4.78M
    int res;
4493
4.78M
    Py_BEGIN_CRITICAL_SECTION(d);
4494
4.78M
    res = dict_setdefault_ref_lock_held(d, key, default_value, result, 1);
4495
4.78M
    Py_END_CRITICAL_SECTION();
4496
4.78M
    return res;
4497
4.78M
}
4498
4499
PyObject *
4500
PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
4501
0
{
4502
0
    PyObject *result;
4503
0
    Py_BEGIN_CRITICAL_SECTION(d);
4504
0
    dict_setdefault_ref_lock_held(d, key, defaultobj, &result, 0);
4505
0
    Py_END_CRITICAL_SECTION();
4506
0
    return result;
4507
0
}
4508
4509
/*[clinic input]
4510
@critical_section
4511
dict.setdefault
4512
4513
    key: object
4514
    default: object = None
4515
    /
4516
4517
Insert key with a value of default if key is not in the dictionary.
4518
4519
Return the value for key if key is in the dictionary, else default.
4520
[clinic start generated code]*/
4521
4522
static PyObject *
4523
dict_setdefault_impl(PyDictObject *self, PyObject *key,
4524
                     PyObject *default_value)
4525
/*[clinic end generated code: output=f8c1101ebf69e220 input=9237af9a0a224302]*/
4526
110M
{
4527
110M
    PyObject *val;
4528
110M
    dict_setdefault_ref_lock_held((PyObject *)self, key, default_value, &val, 1);
4529
110M
    return val;
4530
110M
}
4531
4532
4533
/*[clinic input]
4534
dict.clear
4535
4536
Remove all items from the dict.
4537
[clinic start generated code]*/
4538
4539
static PyObject *
4540
dict_clear_impl(PyDictObject *self)
4541
/*[clinic end generated code: output=5139a830df00830a input=0bf729baba97a4c2]*/
4542
7.16k
{
4543
7.16k
    PyDict_Clear((PyObject *)self);
4544
7.16k
    Py_RETURN_NONE;
4545
7.16k
}
4546
4547
/*[clinic input]
4548
@permit_long_summary
4549
dict.pop
4550
4551
    key: object
4552
    default: object = NULL
4553
    /
4554
4555
D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
4556
4557
If the key is not found, return the default if given; otherwise,
4558
raise a KeyError.
4559
[clinic start generated code]*/
4560
4561
static PyObject *
4562
dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
4563
/*[clinic end generated code: output=3abb47b89f24c21c input=d409c7eb2de67e38]*/
4564
294k
{
4565
294k
    return dict_pop_default((PyObject*)self, key, default_value);
4566
294k
}
4567
4568
/*[clinic input]
4569
@critical_section
4570
dict.popitem
4571
4572
Remove and return a (key, value) pair as a 2-tuple.
4573
4574
Pairs are returned in LIFO (last-in, first-out) order.
4575
Raises KeyError if the dict is empty.
4576
[clinic start generated code]*/
4577
4578
static PyObject *
4579
dict_popitem_impl(PyDictObject *self)
4580
/*[clinic end generated code: output=e65fcb04420d230d input=ef28b4da5f0f762e]*/
4581
0
{
4582
0
    Py_ssize_t i, j;
4583
0
    PyObject *res;
4584
0
    PyInterpreterState *interp = _PyInterpreterState_GET();
4585
4586
0
    ASSERT_DICT_LOCKED(self);
4587
4588
    /* Allocate the result tuple before checking the size.  Believe it
4589
     * or not, this allocation could trigger a garbage collection which
4590
     * could empty the dict, so if we checked the size first and that
4591
     * happened, the result would be an infinite loop (searching for an
4592
     * entry that no longer exists).  Note that the usual popitem()
4593
     * idiom is "while d: k, v = d.popitem()". so needing to throw the
4594
     * tuple away if the dict *is* empty isn't a significant
4595
     * inefficiency -- possible, but unlikely in practice.
4596
     */
4597
0
    res = PyTuple_New(2);
4598
0
    if (res == NULL)
4599
0
        return NULL;
4600
0
    if (self->ma_used == 0) {
4601
0
        Py_DECREF(res);
4602
0
        PyErr_SetString(PyExc_KeyError, "popitem(): dictionary is empty");
4603
0
        return NULL;
4604
0
    }
4605
    /* Convert split table to combined table */
4606
0
    if (_PyDict_HasSplitTable(self)) {
4607
0
        if (dictresize(self, DK_LOG_SIZE(self->ma_keys), 1) < 0) {
4608
0
            Py_DECREF(res);
4609
0
            return NULL;
4610
0
        }
4611
0
    }
4612
0
    FT_ATOMIC_STORE_UINT32_RELAXED(self->ma_keys->dk_version, 0);
4613
4614
    /* Pop last item */
4615
0
    PyObject *key, *value;
4616
0
    Py_hash_t hash;
4617
0
    if (DK_IS_UNICODE(self->ma_keys)) {
4618
0
        PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(self->ma_keys);
4619
0
        i = self->ma_keys->dk_nentries - 1;
4620
0
        while (i >= 0 && ep0[i].me_value == NULL) {
4621
0
            i--;
4622
0
        }
4623
0
        assert(i >= 0);
4624
4625
0
        key = ep0[i].me_key;
4626
0
        _PyDict_NotifyEvent(interp, PyDict_EVENT_DELETED, self, key, NULL);
4627
0
        hash = unicode_get_hash(key);
4628
0
        value = ep0[i].me_value;
4629
0
        STORE_KEY(&ep0[i], NULL);
4630
0
        STORE_VALUE(&ep0[i], NULL);
4631
0
    }
4632
0
    else {
4633
0
        PyDictKeyEntry *ep0 = DK_ENTRIES(self->ma_keys);
4634
0
        i = self->ma_keys->dk_nentries - 1;
4635
0
        while (i >= 0 && ep0[i].me_value == NULL) {
4636
0
            i--;
4637
0
        }
4638
0
        assert(i >= 0);
4639
4640
0
        key = ep0[i].me_key;
4641
0
        _PyDict_NotifyEvent(interp, PyDict_EVENT_DELETED, self, key, NULL);
4642
0
        hash = ep0[i].me_hash;
4643
0
        value = ep0[i].me_value;
4644
0
        STORE_KEY(&ep0[i], NULL);
4645
0
        STORE_HASH(&ep0[i], -1);
4646
0
        STORE_VALUE(&ep0[i], NULL);
4647
0
    }
4648
4649
0
    j = lookdict_index(self->ma_keys, hash, i);
4650
0
    assert(j >= 0);
4651
0
    assert(dictkeys_get_index(self->ma_keys, j) == i);
4652
0
    dictkeys_set_index(self->ma_keys, j, DKIX_DUMMY);
4653
4654
0
    PyTuple_SET_ITEM(res, 0, key);
4655
0
    PyTuple_SET_ITEM(res, 1, value);
4656
    /* We can't dk_usable++ since there is DKIX_DUMMY in indices */
4657
0
    STORE_KEYS_NENTRIES(self->ma_keys, i);
4658
0
    STORE_USED(self, self->ma_used - 1);
4659
0
    ASSERT_CONSISTENT(self);
4660
0
    return res;
4661
0
}
4662
4663
static int
4664
dict_traverse(PyObject *op, visitproc visit, void *arg)
4665
26.1M
{
4666
26.1M
    PyDictObject *mp = (PyDictObject *)op;
4667
26.1M
    PyDictKeysObject *keys = mp->ma_keys;
4668
26.1M
    Py_ssize_t i, n = keys->dk_nentries;
4669
4670
26.1M
    if (DK_IS_UNICODE(keys)) {
4671
24.0M
        if (_PyDict_HasSplitTable(mp)) {
4672
1.57M
            if (!mp->ma_values->embedded) {
4673
7.58M
                for (i = 0; i < n; i++) {
4674
6.01M
                    Py_VISIT(mp->ma_values->values[i]);
4675
6.01M
                }
4676
1.57M
            }
4677
1.57M
        }
4678
22.5M
        else {
4679
22.5M
            PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
4680
274M
            for (i = 0; i < n; i++) {
4681
252M
                Py_VISIT(entries[i].me_value);
4682
252M
            }
4683
22.5M
        }
4684
24.0M
    }
4685
2.06M
    else {
4686
2.06M
        PyDictKeyEntry *entries = DK_ENTRIES(keys);
4687
28.2M
        for (i = 0; i < n; i++) {
4688
26.1M
            if (entries[i].me_value != NULL) {
4689
25.3M
                Py_VISIT(entries[i].me_value);
4690
25.3M
                Py_VISIT(entries[i].me_key);
4691
25.3M
            }
4692
26.1M
        }
4693
2.06M
    }
4694
26.1M
    return 0;
4695
26.1M
}
4696
4697
static int
4698
dict_tp_clear(PyObject *op)
4699
287k
{
4700
287k
    PyDict_Clear(op);
4701
287k
    return 0;
4702
287k
}
4703
4704
static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
4705
4706
static Py_ssize_t
4707
sizeof_lock_held(PyDictObject *mp)
4708
0
{
4709
0
    size_t res = _PyObject_SIZE(Py_TYPE(mp));
4710
0
    if (_PyDict_HasSplitTable(mp)) {
4711
0
        res += shared_keys_usable_size(mp->ma_keys) * sizeof(PyObject*);
4712
0
    }
4713
    /* If the dictionary is split, the keys portion is accounted-for
4714
       in the type object. */
4715
0
    if (mp->ma_keys->dk_refcnt == 1) {
4716
0
        res += _PyDict_KeysSize(mp->ma_keys);
4717
0
    }
4718
0
    assert(res <= (size_t)PY_SSIZE_T_MAX);
4719
0
    return (Py_ssize_t)res;
4720
0
}
4721
4722
Py_ssize_t
4723
_PyDict_SizeOf(PyDictObject *mp)
4724
0
{
4725
0
    Py_ssize_t res;
4726
0
    Py_BEGIN_CRITICAL_SECTION(mp);
4727
0
    res = sizeof_lock_held(mp);
4728
0
    Py_END_CRITICAL_SECTION();
4729
4730
0
    return res;
4731
0
}
4732
4733
size_t
4734
_PyDict_KeysSize(PyDictKeysObject *keys)
4735
605k
{
4736
605k
    size_t es = (keys->dk_kind == DICT_KEYS_GENERAL
4737
605k
                 ? sizeof(PyDictKeyEntry) : sizeof(PyDictUnicodeEntry));
4738
605k
    size_t size = sizeof(PyDictKeysObject);
4739
605k
    size += (size_t)1 << keys->dk_log2_index_bytes;
4740
605k
    size += USABLE_FRACTION((size_t)DK_SIZE(keys)) * es;
4741
605k
    return size;
4742
605k
}
4743
4744
/*[clinic input]
4745
dict.__sizeof__
4746
4747
Return the size of the dict in memory, in bytes.
4748
[clinic start generated code]*/
4749
4750
static PyObject *
4751
dict___sizeof___impl(PyDictObject *self)
4752
/*[clinic end generated code: output=44279379b3824bda input=4fec4ddfc44a4d1a]*/
4753
0
{
4754
0
    return PyLong_FromSsize_t(_PyDict_SizeOf(self));
4755
0
}
4756
4757
static PyObject *
4758
dict_or(PyObject *self, PyObject *other)
4759
0
{
4760
0
    if (!PyDict_Check(self) || !PyDict_Check(other)) {
4761
0
        Py_RETURN_NOTIMPLEMENTED;
4762
0
    }
4763
0
    PyObject *new = PyDict_Copy(self);
4764
0
    if (new == NULL) {
4765
0
        return NULL;
4766
0
    }
4767
0
    if (dict_update_arg(new, other)) {
4768
0
        Py_DECREF(new);
4769
0
        return NULL;
4770
0
    }
4771
0
    return new;
4772
0
}
4773
4774
static PyObject *
4775
dict_ior(PyObject *self, PyObject *other)
4776
0
{
4777
0
    if (dict_update_arg(self, other)) {
4778
0
        return NULL;
4779
0
    }
4780
0
    return Py_NewRef(self);
4781
0
}
4782
4783
PyDoc_STRVAR(getitem__doc__,
4784
"__getitem__($self, key, /)\n--\n\nReturn self[key].");
4785
4786
PyDoc_STRVAR(update__doc__,
4787
"D.update([E, ]**F) -> None.  Update D from mapping/iterable E and F.\n\
4788
If E is present and has a .keys() method, then does:  for k in E.keys(): D[k] = E[k]\n\
4789
If E is present and lacks a .keys() method, then does:  for k, v in E: D[k] = v\n\
4790
In either case, this is followed by: for k in F:  D[k] = F[k]");
4791
4792
/* Forward */
4793
4794
static PyMethodDef mapp_methods[] = {
4795
    DICT___CONTAINS___METHODDEF
4796
    {"__getitem__",     dict_subscript,                 METH_O | METH_COEXIST,
4797
     getitem__doc__},
4798
    DICT___SIZEOF___METHODDEF
4799
    DICT_GET_METHODDEF
4800
    DICT_SETDEFAULT_METHODDEF
4801
    DICT_POP_METHODDEF
4802
    DICT_POPITEM_METHODDEF
4803
    DICT_KEYS_METHODDEF
4804
    DICT_ITEMS_METHODDEF
4805
    DICT_VALUES_METHODDEF
4806
    {"update",          _PyCFunction_CAST(dict_update), METH_VARARGS | METH_KEYWORDS,
4807
     update__doc__},
4808
    DICT_FROMKEYS_METHODDEF
4809
    DICT_CLEAR_METHODDEF
4810
    DICT_COPY_METHODDEF
4811
    DICT___REVERSED___METHODDEF
4812
    {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
4813
    {NULL,              NULL}   /* sentinel */
4814
};
4815
4816
/* Return 1 if `key` is in dict `op`, 0 if not, and -1 on error. */
4817
int
4818
PyDict_Contains(PyObject *op, PyObject *key)
4819
63.5M
{
4820
63.5M
    Py_hash_t hash = _PyObject_HashFast(key);
4821
63.5M
    if (hash == -1) {
4822
0
        dict_unhashable_type(key);
4823
0
        return -1;
4824
0
    }
4825
4826
63.5M
    return _PyDict_Contains_KnownHash(op, key, hash);
4827
63.5M
}
4828
4829
int
4830
PyDict_ContainsString(PyObject *op, const char *key)
4831
1.38k
{
4832
1.38k
    PyObject *key_obj = PyUnicode_FromString(key);
4833
1.38k
    if (key_obj == NULL) {
4834
0
        return -1;
4835
0
    }
4836
1.38k
    int res = PyDict_Contains(op, key_obj);
4837
1.38k
    Py_DECREF(key_obj);
4838
1.38k
    return res;
4839
1.38k
}
4840
4841
/* Internal version of PyDict_Contains used when the hash value is already known */
4842
int
4843
_PyDict_Contains_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
4844
63.5M
{
4845
63.5M
    PyDictObject *mp = (PyDictObject *)op;
4846
63.5M
    PyObject *value;
4847
63.5M
    Py_ssize_t ix;
4848
4849
#ifdef Py_GIL_DISABLED
4850
    ix = _Py_dict_lookup_threadsafe(mp, key, hash, &value);
4851
#else
4852
63.5M
    ix = _Py_dict_lookup(mp, key, hash, &value);
4853
63.5M
#endif
4854
63.5M
    if (ix == DKIX_ERROR)
4855
0
        return -1;
4856
63.5M
    if (ix != DKIX_EMPTY && value != NULL) {
4857
#ifdef Py_GIL_DISABLED
4858
        Py_DECREF(value);
4859
#endif
4860
48.0M
        return 1;
4861
48.0M
    }
4862
15.4M
    return 0;
4863
63.5M
}
4864
4865
int
4866
_PyDict_ContainsId(PyObject *op, _Py_Identifier *key)
4867
0
{
4868
0
    PyObject *kv = _PyUnicode_FromId(key); /* borrowed */
4869
0
    if (kv == NULL) {
4870
0
        return -1;
4871
0
    }
4872
0
    return PyDict_Contains(op, kv);
4873
0
}
4874
4875
/* Hack to implement "key in dict" */
4876
static PySequenceMethods dict_as_sequence = {
4877
    0,                          /* sq_length */
4878
    0,                          /* sq_concat */
4879
    0,                          /* sq_repeat */
4880
    0,                          /* sq_item */
4881
    0,                          /* sq_slice */
4882
    0,                          /* sq_ass_item */
4883
    0,                          /* sq_ass_slice */
4884
    PyDict_Contains,            /* sq_contains */
4885
    0,                          /* sq_inplace_concat */
4886
    0,                          /* sq_inplace_repeat */
4887
};
4888
4889
static PyNumberMethods dict_as_number = {
4890
    .nb_or = dict_or,
4891
    .nb_inplace_or = dict_ior,
4892
};
4893
4894
static PyObject *
4895
dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
4896
17.1k
{
4897
17.1k
    assert(type != NULL);
4898
17.1k
    assert(type->tp_alloc != NULL);
4899
    // dict subclasses must implement the GC protocol
4900
17.1k
    assert(_PyType_IS_GC(type));
4901
4902
17.1k
    PyObject *self = type->tp_alloc(type, 0);
4903
17.1k
    if (self == NULL) {
4904
0
        return NULL;
4905
0
    }
4906
17.1k
    PyDictObject *d = (PyDictObject *)self;
4907
4908
17.1k
    d->ma_used = 0;
4909
17.1k
    d->_ma_watcher_tag = 0;
4910
    // We don't inc ref empty keys because they're immortal
4911
17.1k
    assert((Py_EMPTY_KEYS)->dk_refcnt == _Py_DICT_IMMORTAL_INITIAL_REFCNT);
4912
17.1k
    d->ma_keys = Py_EMPTY_KEYS;
4913
17.1k
    d->ma_values = NULL;
4914
17.1k
    ASSERT_CONSISTENT(d);
4915
17.1k
    if (!_PyObject_GC_IS_TRACKED(d)) {
4916
17.0k
        _PyObject_GC_TRACK(d);
4917
17.0k
    }
4918
17.1k
    return self;
4919
17.1k
}
4920
4921
static int
4922
dict_init(PyObject *self, PyObject *args, PyObject *kwds)
4923
100
{
4924
100
    return dict_update_common(self, args, kwds, "dict");
4925
100
}
4926
4927
static PyObject *
4928
dict_vectorcall(PyObject *type, PyObject * const*args,
4929
                size_t nargsf, PyObject *kwnames)
4930
17.0k
{
4931
17.0k
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
4932
17.0k
    if (!_PyArg_CheckPositional("dict", nargs, 0, 1)) {
4933
0
        return NULL;
4934
0
    }
4935
4936
17.0k
    PyObject *self = dict_new(_PyType_CAST(type), NULL, NULL);
4937
17.0k
    if (self == NULL) {
4938
0
        return NULL;
4939
0
    }
4940
17.0k
    if (nargs == 1) {
4941
132
        if (dict_update_arg(self, args[0]) < 0) {
4942
0
            Py_DECREF(self);
4943
0
            return NULL;
4944
0
        }
4945
132
        args++;
4946
132
    }
4947
17.0k
    if (kwnames != NULL) {
4948
77.4k
        for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(kwnames); i++) {
4949
60.8k
            if (PyDict_SetItem(self, PyTuple_GET_ITEM(kwnames, i), args[i]) < 0) {
4950
0
                Py_DECREF(self);
4951
0
                return NULL;
4952
0
            }
4953
60.8k
        }
4954
16.5k
    }
4955
17.0k
    return self;
4956
17.0k
}
4957
4958
static PyObject *
4959
dict_iter(PyObject *self)
4960
168k
{
4961
168k
    PyDictObject *dict = (PyDictObject *)self;
4962
168k
    return dictiter_new(dict, &PyDictIterKey_Type);
4963
168k
}
4964
4965
PyDoc_STRVAR(dictionary_doc,
4966
"dict() -> new empty dictionary\n"
4967
"dict(mapping) -> new dictionary initialized from a mapping object's\n"
4968
"    (key, value) pairs\n"
4969
"dict(iterable) -> new dictionary initialized as if via:\n"
4970
"    d = {}\n"
4971
"    for k, v in iterable:\n"
4972
"        d[k] = v\n"
4973
"dict(**kwargs) -> new dictionary initialized with the name=value pairs\n"
4974
"    in the keyword argument list.  For example:  dict(one=1, two=2)");
4975
4976
PyTypeObject PyDict_Type = {
4977
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
4978
    "dict",
4979
    sizeof(PyDictObject),
4980
    0,
4981
    dict_dealloc,                               /* tp_dealloc */
4982
    0,                                          /* tp_vectorcall_offset */
4983
    0,                                          /* tp_getattr */
4984
    0,                                          /* tp_setattr */
4985
    0,                                          /* tp_as_async */
4986
    dict_repr,                                  /* tp_repr */
4987
    &dict_as_number,                            /* tp_as_number */
4988
    &dict_as_sequence,                          /* tp_as_sequence */
4989
    &dict_as_mapping,                           /* tp_as_mapping */
4990
    PyObject_HashNotImplemented,                /* tp_hash */
4991
    0,                                          /* tp_call */
4992
    0,                                          /* tp_str */
4993
    PyObject_GenericGetAttr,                    /* tp_getattro */
4994
    0,                                          /* tp_setattro */
4995
    0,                                          /* tp_as_buffer */
4996
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
4997
        Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DICT_SUBCLASS |
4998
        _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_MAPPING,  /* tp_flags */
4999
    dictionary_doc,                             /* tp_doc */
5000
    dict_traverse,                              /* tp_traverse */
5001
    dict_tp_clear,                              /* tp_clear */
5002
    dict_richcompare,                           /* tp_richcompare */
5003
    0,                                          /* tp_weaklistoffset */
5004
    dict_iter,                                  /* tp_iter */
5005
    0,                                          /* tp_iternext */
5006
    mapp_methods,                               /* tp_methods */
5007
    0,                                          /* tp_members */
5008
    0,                                          /* tp_getset */
5009
    0,                                          /* tp_base */
5010
    0,                                          /* tp_dict */
5011
    0,                                          /* tp_descr_get */
5012
    0,                                          /* tp_descr_set */
5013
    0,                                          /* tp_dictoffset */
5014
    dict_init,                                  /* tp_init */
5015
    _PyType_AllocNoTrack,                       /* tp_alloc */
5016
    dict_new,                                   /* tp_new */
5017
    PyObject_GC_Del,                            /* tp_free */
5018
    .tp_vectorcall = dict_vectorcall,
5019
    .tp_version_tag = _Py_TYPE_VERSION_DICT,
5020
};
5021
5022
/* For backward compatibility with old dictionary interface */
5023
5024
PyObject *
5025
PyDict_GetItemString(PyObject *v, const char *key)
5026
0
{
5027
0
    PyObject *kv, *rv;
5028
0
    kv = PyUnicode_FromString(key);
5029
0
    if (kv == NULL) {
5030
0
        PyErr_FormatUnraisable(
5031
0
            "Exception ignored in PyDict_GetItemString(); consider using "
5032
0
            "PyDict_GetItemStringRef()");
5033
0
        return NULL;
5034
0
    }
5035
0
    rv = dict_getitem(v, kv,
5036
0
            "Exception ignored in PyDict_GetItemString(); consider using "
5037
0
            "PyDict_GetItemStringRef()");
5038
0
    Py_DECREF(kv);
5039
0
    return rv;  // borrowed reference
5040
0
}
5041
5042
int
5043
PyDict_GetItemStringRef(PyObject *v, const char *key, PyObject **result)
5044
272k
{
5045
272k
    PyObject *key_obj = PyUnicode_FromString(key);
5046
272k
    if (key_obj == NULL) {
5047
0
        *result = NULL;
5048
0
        return -1;
5049
0
    }
5050
272k
    int res = PyDict_GetItemRef(v, key_obj, result);
5051
272k
    Py_DECREF(key_obj);
5052
272k
    return res;
5053
272k
}
5054
5055
int
5056
_PyDict_SetItemId(PyObject *v, _Py_Identifier *key, PyObject *item)
5057
0
{
5058
0
    PyObject *kv;
5059
0
    kv = _PyUnicode_FromId(key); /* borrowed */
5060
0
    if (kv == NULL)
5061
0
        return -1;
5062
0
    return PyDict_SetItem(v, kv, item);
5063
0
}
5064
5065
int
5066
PyDict_SetItemString(PyObject *v, const char *key, PyObject *item)
5067
20.0k
{
5068
20.0k
    PyObject *kv;
5069
20.0k
    int err;
5070
20.0k
    kv = PyUnicode_FromString(key);
5071
20.0k
    if (kv == NULL)
5072
0
        return -1;
5073
20.0k
    PyInterpreterState *interp = _PyInterpreterState_GET();
5074
20.0k
    _PyUnicode_InternImmortal(interp, &kv); /* XXX Should we really? */
5075
20.0k
    err = PyDict_SetItem(v, kv, item);
5076
20.0k
    Py_DECREF(kv);
5077
20.0k
    return err;
5078
20.0k
}
5079
5080
int
5081
_PyDict_DelItemId(PyObject *v, _Py_Identifier *key)
5082
0
{
5083
0
    PyObject *kv = _PyUnicode_FromId(key); /* borrowed */
5084
0
    if (kv == NULL)
5085
0
        return -1;
5086
0
    return PyDict_DelItem(v, kv);
5087
0
}
5088
5089
int
5090
PyDict_DelItemString(PyObject *v, const char *key)
5091
0
{
5092
0
    PyObject *kv;
5093
0
    int err;
5094
0
    kv = PyUnicode_FromString(key);
5095
0
    if (kv == NULL)
5096
0
        return -1;
5097
0
    err = PyDict_DelItem(v, kv);
5098
0
    Py_DECREF(kv);
5099
0
    return err;
5100
0
}
5101
5102
/* Dictionary iterator types */
5103
5104
typedef struct {
5105
    PyObject_HEAD
5106
    PyDictObject *di_dict; /* Set to NULL when iterator is exhausted */
5107
    Py_ssize_t di_used;
5108
    Py_ssize_t di_pos;
5109
    PyObject* di_result; /* reusable result tuple for iteritems */
5110
    Py_ssize_t len;
5111
} dictiterobject;
5112
5113
static PyObject *
5114
dictiter_new(PyDictObject *dict, PyTypeObject *itertype)
5115
892k
{
5116
892k
    Py_ssize_t used;
5117
892k
    dictiterobject *di;
5118
892k
    di = PyObject_GC_New(dictiterobject, itertype);
5119
892k
    if (di == NULL) {
5120
0
        return NULL;
5121
0
    }
5122
892k
    di->di_dict = (PyDictObject*)Py_NewRef(dict);
5123
892k
    used = FT_ATOMIC_LOAD_SSIZE_RELAXED(dict->ma_used);
5124
892k
    di->di_used = used;
5125
892k
    di->len = used;
5126
892k
    if (itertype == &PyDictRevIterKey_Type ||
5127
892k
         itertype == &PyDictRevIterItem_Type ||
5128
892k
         itertype == &PyDictRevIterValue_Type) {
5129
0
        if (_PyDict_HasSplitTable(dict)) {
5130
0
            di->di_pos = used - 1;
5131
0
        }
5132
0
        else {
5133
0
            di->di_pos = load_keys_nentries(dict) - 1;
5134
0
        }
5135
0
    }
5136
892k
    else {
5137
892k
        di->di_pos = 0;
5138
892k
    }
5139
892k
    if (itertype == &PyDictIterItem_Type ||
5140
892k
        itertype == &PyDictRevIterItem_Type) {
5141
471k
        di->di_result = PyTuple_Pack(2, Py_None, Py_None);
5142
471k
        if (di->di_result == NULL) {
5143
0
            Py_DECREF(di);
5144
0
            return NULL;
5145
0
        }
5146
471k
    }
5147
420k
    else {
5148
420k
        di->di_result = NULL;
5149
420k
    }
5150
892k
    _PyObject_GC_TRACK(di);
5151
892k
    return (PyObject *)di;
5152
892k
}
5153
5154
static void
5155
dictiter_dealloc(PyObject *self)
5156
892k
{
5157
892k
    dictiterobject *di = (dictiterobject *)self;
5158
    /* bpo-31095: UnTrack is needed before calling any callbacks */
5159
892k
    _PyObject_GC_UNTRACK(di);
5160
892k
    Py_XDECREF(di->di_dict);
5161
892k
    Py_XDECREF(di->di_result);
5162
892k
    PyObject_GC_Del(di);
5163
892k
}
5164
5165
static int
5166
dictiter_traverse(PyObject *self, visitproc visit, void *arg)
5167
1.87k
{
5168
1.87k
    dictiterobject *di = (dictiterobject *)self;
5169
1.87k
    Py_VISIT(di->di_dict);
5170
1.87k
    Py_VISIT(di->di_result);
5171
1.87k
    return 0;
5172
1.87k
}
5173
5174
static PyObject *
5175
dictiter_len(PyObject *self, PyObject *Py_UNUSED(ignored))
5176
864
{
5177
864
    dictiterobject *di = (dictiterobject *)self;
5178
864
    Py_ssize_t len = 0;
5179
864
    if (di->di_dict != NULL && di->di_used == FT_ATOMIC_LOAD_SSIZE_RELAXED(di->di_dict->ma_used))
5180
864
        len = FT_ATOMIC_LOAD_SSIZE_RELAXED(di->len);
5181
864
    return PyLong_FromSize_t(len);
5182
864
}
5183
5184
PyDoc_STRVAR(length_hint_doc,
5185
             "Private method returning an estimate of len(list(it)).");
5186
5187
static PyObject *
5188
dictiter_reduce(PyObject *di, PyObject *Py_UNUSED(ignored));
5189
5190
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
5191
5192
static PyMethodDef dictiter_methods[] = {
5193
    {"__length_hint__", dictiter_len,                   METH_NOARGS,
5194
     length_hint_doc},
5195
     {"__reduce__",     dictiter_reduce,                METH_NOARGS,
5196
     reduce_doc},
5197
    {NULL,              NULL}           /* sentinel */
5198
};
5199
5200
#ifdef Py_GIL_DISABLED
5201
5202
static int
5203
dictiter_iternext_threadsafe(PyDictObject *d, PyObject *self,
5204
                             PyObject **out_key, PyObject **out_value);
5205
5206
#else /* Py_GIL_DISABLED */
5207
5208
static PyObject*
5209
dictiter_iternextkey_lock_held(PyDictObject *d, PyObject *self)
5210
2.32M
{
5211
2.32M
    dictiterobject *di = (dictiterobject *)self;
5212
2.32M
    PyObject *key;
5213
2.32M
    Py_ssize_t i;
5214
2.32M
    PyDictKeysObject *k;
5215
5216
2.32M
    assert (PyDict_Check(d));
5217
2.32M
    ASSERT_DICT_LOCKED(d);
5218
5219
2.32M
    if (di->di_used != d->ma_used) {
5220
0
        PyErr_SetString(PyExc_RuntimeError,
5221
0
                        "dictionary changed size during iteration");
5222
0
        di->di_used = -1; /* Make this state sticky */
5223
0
        return NULL;
5224
0
    }
5225
5226
2.32M
    i = di->di_pos;
5227
2.32M
    k = d->ma_keys;
5228
2.32M
    assert(i >= 0);
5229
2.32M
    if (_PyDict_HasSplitTable(d)) {
5230
0
        if (i >= d->ma_used)
5231
0
            goto fail;
5232
0
        int index = get_index_from_order(d, i);
5233
0
        key = LOAD_SHARED_KEY(DK_UNICODE_ENTRIES(k)[index].me_key);
5234
0
        assert(d->ma_values->values[index] != NULL);
5235
0
    }
5236
2.32M
    else {
5237
2.32M
        Py_ssize_t n = k->dk_nentries;
5238
2.32M
        if (DK_IS_UNICODE(k)) {
5239
2.32M
            PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
5240
2.32M
            while (i < n && entry_ptr->me_value == NULL) {
5241
332
                entry_ptr++;
5242
332
                i++;
5243
332
            }
5244
2.32M
            if (i >= n)
5245
420k
                goto fail;
5246
1.90M
            key = entry_ptr->me_key;
5247
1.90M
        }
5248
0
        else {
5249
0
            PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
5250
0
            while (i < n && entry_ptr->me_value == NULL) {
5251
0
                entry_ptr++;
5252
0
                i++;
5253
0
            }
5254
0
            if (i >= n)
5255
0
                goto fail;
5256
0
            key = entry_ptr->me_key;
5257
0
        }
5258
2.32M
    }
5259
    // We found an element (key), but did not expect it
5260
1.90M
    if (di->len == 0) {
5261
0
        PyErr_SetString(PyExc_RuntimeError,
5262
0
                        "dictionary keys changed during iteration");
5263
0
        goto fail;
5264
0
    }
5265
1.90M
    di->di_pos = i+1;
5266
1.90M
    di->len--;
5267
1.90M
    return Py_NewRef(key);
5268
5269
420k
fail:
5270
420k
    di->di_dict = NULL;
5271
420k
    Py_DECREF(d);
5272
420k
    return NULL;
5273
1.90M
}
5274
5275
#endif  /* Py_GIL_DISABLED */
5276
5277
static PyObject*
5278
dictiter_iternextkey(PyObject *self)
5279
2.32M
{
5280
2.32M
    dictiterobject *di = (dictiterobject *)self;
5281
2.32M
    PyDictObject *d = di->di_dict;
5282
5283
2.32M
    if (d == NULL)
5284
0
        return NULL;
5285
5286
2.32M
    PyObject *value;
5287
#ifdef Py_GIL_DISABLED
5288
    if (dictiter_iternext_threadsafe(d, self, &value, NULL) < 0) {
5289
        value = NULL;
5290
    }
5291
#else
5292
2.32M
    value = dictiter_iternextkey_lock_held(d, self);
5293
2.32M
#endif
5294
5295
2.32M
    return value;
5296
2.32M
}
5297
5298
PyTypeObject PyDictIterKey_Type = {
5299
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
5300
    "dict_keyiterator",                         /* tp_name */
5301
    sizeof(dictiterobject),                     /* tp_basicsize */
5302
    0,                                          /* tp_itemsize */
5303
    /* methods */
5304
    dictiter_dealloc,                           /* tp_dealloc */
5305
    0,                                          /* tp_vectorcall_offset */
5306
    0,                                          /* tp_getattr */
5307
    0,                                          /* tp_setattr */
5308
    0,                                          /* tp_as_async */
5309
    0,                                          /* tp_repr */
5310
    0,                                          /* tp_as_number */
5311
    0,                                          /* tp_as_sequence */
5312
    0,                                          /* tp_as_mapping */
5313
    0,                                          /* tp_hash */
5314
    0,                                          /* tp_call */
5315
    0,                                          /* tp_str */
5316
    PyObject_GenericGetAttr,                    /* tp_getattro */
5317
    0,                                          /* tp_setattro */
5318
    0,                                          /* tp_as_buffer */
5319
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
5320
    0,                                          /* tp_doc */
5321
    dictiter_traverse,                          /* tp_traverse */
5322
    0,                                          /* tp_clear */
5323
    0,                                          /* tp_richcompare */
5324
    0,                                          /* tp_weaklistoffset */
5325
    PyObject_SelfIter,                          /* tp_iter */
5326
    dictiter_iternextkey,                       /* tp_iternext */
5327
    dictiter_methods,                           /* tp_methods */
5328
    0,
5329
};
5330
5331
#ifndef Py_GIL_DISABLED
5332
5333
static PyObject *
5334
dictiter_iternextvalue_lock_held(PyDictObject *d, PyObject *self)
5335
3.06k
{
5336
3.06k
    dictiterobject *di = (dictiterobject *)self;
5337
3.06k
    PyObject *value;
5338
3.06k
    Py_ssize_t i;
5339
5340
3.06k
    assert (PyDict_Check(d));
5341
3.06k
    ASSERT_DICT_LOCKED(d);
5342
5343
3.06k
    if (di->di_used != d->ma_used) {
5344
0
        PyErr_SetString(PyExc_RuntimeError,
5345
0
                        "dictionary changed size during iteration");
5346
0
        di->di_used = -1; /* Make this state sticky */
5347
0
        return NULL;
5348
0
    }
5349
5350
3.06k
    i = di->di_pos;
5351
3.06k
    assert(i >= 0);
5352
3.06k
    if (_PyDict_HasSplitTable(d)) {
5353
0
        if (i >= d->ma_used)
5354
0
            goto fail;
5355
0
        int index = get_index_from_order(d, i);
5356
0
        value = d->ma_values->values[index];
5357
0
        assert(value != NULL);
5358
0
    }
5359
3.06k
    else {
5360
3.06k
        Py_ssize_t n = d->ma_keys->dk_nentries;
5361
3.06k
        if (DK_IS_UNICODE(d->ma_keys)) {
5362
3.06k
            PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(d->ma_keys)[i];
5363
3.06k
            while (i < n && entry_ptr->me_value == NULL) {
5364
0
                entry_ptr++;
5365
0
                i++;
5366
0
            }
5367
3.06k
            if (i >= n)
5368
82
                goto fail;
5369
2.97k
            value = entry_ptr->me_value;
5370
2.97k
        }
5371
0
        else {
5372
0
            PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i];
5373
0
            while (i < n && entry_ptr->me_value == NULL) {
5374
0
                entry_ptr++;
5375
0
                i++;
5376
0
            }
5377
0
            if (i >= n)
5378
0
                goto fail;
5379
0
            value = entry_ptr->me_value;
5380
0
        }
5381
3.06k
    }
5382
    // We found an element, but did not expect it
5383
2.97k
    if (di->len == 0) {
5384
0
        PyErr_SetString(PyExc_RuntimeError,
5385
0
                        "dictionary keys changed during iteration");
5386
0
        goto fail;
5387
0
    }
5388
2.97k
    di->di_pos = i+1;
5389
2.97k
    di->len--;
5390
2.97k
    return Py_NewRef(value);
5391
5392
82
fail:
5393
82
    di->di_dict = NULL;
5394
82
    Py_DECREF(d);
5395
82
    return NULL;
5396
2.97k
}
5397
5398
#endif  /* Py_GIL_DISABLED */
5399
5400
static PyObject *
5401
dictiter_iternextvalue(PyObject *self)
5402
3.06k
{
5403
3.06k
    dictiterobject *di = (dictiterobject *)self;
5404
3.06k
    PyDictObject *d = di->di_dict;
5405
5406
3.06k
    if (d == NULL)
5407
0
        return NULL;
5408
5409
3.06k
    PyObject *value;
5410
#ifdef Py_GIL_DISABLED
5411
    if (dictiter_iternext_threadsafe(d, self, NULL, &value) < 0) {
5412
        value = NULL;
5413
    }
5414
#else
5415
3.06k
    value = dictiter_iternextvalue_lock_held(d, self);
5416
3.06k
#endif
5417
5418
3.06k
    return value;
5419
3.06k
}
5420
5421
PyTypeObject PyDictIterValue_Type = {
5422
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
5423
    "dict_valueiterator",                       /* tp_name */
5424
    sizeof(dictiterobject),                     /* tp_basicsize */
5425
    0,                                          /* tp_itemsize */
5426
    /* methods */
5427
    dictiter_dealloc,                           /* tp_dealloc */
5428
    0,                                          /* tp_vectorcall_offset */
5429
    0,                                          /* tp_getattr */
5430
    0,                                          /* tp_setattr */
5431
    0,                                          /* tp_as_async */
5432
    0,                                          /* tp_repr */
5433
    0,                                          /* tp_as_number */
5434
    0,                                          /* tp_as_sequence */
5435
    0,                                          /* tp_as_mapping */
5436
    0,                                          /* tp_hash */
5437
    0,                                          /* tp_call */
5438
    0,                                          /* tp_str */
5439
    PyObject_GenericGetAttr,                    /* tp_getattro */
5440
    0,                                          /* tp_setattro */
5441
    0,                                          /* tp_as_buffer */
5442
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
5443
    0,                                          /* tp_doc */
5444
    dictiter_traverse,                          /* tp_traverse */
5445
    0,                                          /* tp_clear */
5446
    0,                                          /* tp_richcompare */
5447
    0,                                          /* tp_weaklistoffset */
5448
    PyObject_SelfIter,                          /* tp_iter */
5449
    dictiter_iternextvalue,                     /* tp_iternext */
5450
    dictiter_methods,                           /* tp_methods */
5451
    0,
5452
};
5453
5454
static int
5455
dictiter_iternextitem_lock_held(PyDictObject *d, PyObject *self,
5456
                                PyObject **out_key, PyObject **out_value)
5457
2.54M
{
5458
2.54M
    dictiterobject *di = (dictiterobject *)self;
5459
2.54M
    PyObject *key, *value;
5460
2.54M
    Py_ssize_t i;
5461
5462
2.54M
    assert (PyDict_Check(d));
5463
2.54M
    ASSERT_DICT_LOCKED(d);
5464
5465
2.54M
    if (di->di_used != d->ma_used) {
5466
0
        PyErr_SetString(PyExc_RuntimeError,
5467
0
                        "dictionary changed size during iteration");
5468
0
        di->di_used = -1; /* Make this state sticky */
5469
0
        return -1;
5470
0
    }
5471
5472
2.54M
    i = FT_ATOMIC_LOAD_SSIZE_RELAXED(di->di_pos);
5473
5474
2.54M
    assert(i >= 0);
5475
2.54M
    if (_PyDict_HasSplitTable(d)) {
5476
10
        if (i >= d->ma_used)
5477
8
            goto fail;
5478
2
        int index = get_index_from_order(d, i);
5479
2
        key = LOAD_SHARED_KEY(DK_UNICODE_ENTRIES(d->ma_keys)[index].me_key);
5480
2
        value = d->ma_values->values[index];
5481
2
        assert(value != NULL);
5482
2
    }
5483
2.54M
    else {
5484
2.54M
        Py_ssize_t n = d->ma_keys->dk_nentries;
5485
2.54M
        if (DK_IS_UNICODE(d->ma_keys)) {
5486
2.54M
            PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(d->ma_keys)[i];
5487
2.55M
            while (i < n && entry_ptr->me_value == NULL) {
5488
8.91k
                entry_ptr++;
5489
8.91k
                i++;
5490
8.91k
            }
5491
2.54M
            if (i >= n)
5492
471k
                goto fail;
5493
2.07M
            key = entry_ptr->me_key;
5494
2.07M
            value = entry_ptr->me_value;
5495
2.07M
        }
5496
26
        else {
5497
26
            PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i];
5498
26
            while (i < n && entry_ptr->me_value == NULL) {
5499
0
                entry_ptr++;
5500
0
                i++;
5501
0
            }
5502
26
            if (i >= n)
5503
2
                goto fail;
5504
24
            key = entry_ptr->me_key;
5505
24
            value = entry_ptr->me_value;
5506
24
        }
5507
2.54M
    }
5508
    // We found an element, but did not expect it
5509
2.07M
    if (di->len == 0) {
5510
0
        PyErr_SetString(PyExc_RuntimeError,
5511
0
                        "dictionary keys changed during iteration");
5512
0
        goto fail;
5513
0
    }
5514
2.07M
    di->di_pos = i+1;
5515
2.07M
    di->len--;
5516
2.07M
    if (out_key != NULL) {
5517
2.07M
        *out_key = Py_NewRef(key);
5518
2.07M
    }
5519
2.07M
    if (out_value != NULL) {
5520
2.07M
        *out_value = Py_NewRef(value);
5521
2.07M
    }
5522
2.07M
    return 0;
5523
5524
471k
fail:
5525
471k
    di->di_dict = NULL;
5526
471k
    Py_DECREF(d);
5527
471k
    return -1;
5528
2.07M
}
5529
5530
#ifdef Py_GIL_DISABLED
5531
5532
// Grabs the key and/or value from the provided locations and if successful
5533
// returns them with an increased reference count.  If either one is unsuccessful
5534
// nothing is incref'd and returns -1.
5535
static int
5536
acquire_key_value(PyObject **key_loc, PyObject *value, PyObject **value_loc,
5537
                  PyObject **out_key, PyObject **out_value)
5538
{
5539
    if (out_key) {
5540
        *out_key = _Py_TryXGetRef(key_loc);
5541
        if (*out_key == NULL) {
5542
            return -1;
5543
        }
5544
    }
5545
5546
    if (out_value) {
5547
        if (!_Py_TryIncrefCompare(value_loc, value)) {
5548
            if (out_key) {
5549
                Py_DECREF(*out_key);
5550
            }
5551
            return -1;
5552
        }
5553
        *out_value = value;
5554
    }
5555
5556
    return 0;
5557
}
5558
5559
static int
5560
dictiter_iternext_threadsafe(PyDictObject *d, PyObject *self,
5561
                             PyObject **out_key, PyObject **out_value)
5562
{
5563
    int res;
5564
    dictiterobject *di = (dictiterobject *)self;
5565
    Py_ssize_t i;
5566
    PyDictKeysObject *k;
5567
5568
    assert (PyDict_Check(d));
5569
5570
    if (di->di_used != _Py_atomic_load_ssize_relaxed(&d->ma_used)) {
5571
        PyErr_SetString(PyExc_RuntimeError,
5572
                        "dictionary changed size during iteration");
5573
        di->di_used = -1; /* Make this state sticky */
5574
        return -1;
5575
    }
5576
5577
    ensure_shared_on_read(d);
5578
5579
    i = _Py_atomic_load_ssize_relaxed(&di->di_pos);
5580
    k = _Py_atomic_load_ptr_acquire(&d->ma_keys);
5581
    assert(i >= 0);
5582
    if (_PyDict_HasSplitTable(d)) {
5583
        PyDictValues *values = _Py_atomic_load_ptr_relaxed(&d->ma_values);
5584
        if (values == NULL) {
5585
            goto concurrent_modification;
5586
        }
5587
5588
        Py_ssize_t used = (Py_ssize_t)_Py_atomic_load_uint8(&values->size);
5589
        if (i >= used) {
5590
            goto fail;
5591
        }
5592
5593
        // We're racing against writes to the order from delete_index_from_values, but
5594
        // single threaded can suffer from concurrent modification to those as well and
5595
        // can have either duplicated or skipped attributes, so we strive to do no better
5596
        // here.
5597
        int index = get_index_from_order(d, i);
5598
        PyObject *value = _Py_atomic_load_ptr(&values->values[index]);
5599
        if (acquire_key_value(&DK_UNICODE_ENTRIES(k)[index].me_key, value,
5600
                               &values->values[index], out_key, out_value) < 0) {
5601
            goto try_locked;
5602
        }
5603
    }
5604
    else {
5605
        Py_ssize_t n = _Py_atomic_load_ssize_relaxed(&k->dk_nentries);
5606
        if (DK_IS_UNICODE(k)) {
5607
            PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
5608
            PyObject *value;
5609
            while (i < n &&
5610
                  (value = _Py_atomic_load_ptr(&entry_ptr->me_value)) == NULL) {
5611
                entry_ptr++;
5612
                i++;
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
        else {
5623
            PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
5624
            PyObject *value;
5625
            while (i < n &&
5626
                  (value = _Py_atomic_load_ptr(&entry_ptr->me_value)) == NULL) {
5627
                entry_ptr++;
5628
                i++;
5629
            }
5630
5631
            if (i >= n)
5632
                goto fail;
5633
5634
            if (acquire_key_value(&entry_ptr->me_key, value,
5635
                                   &entry_ptr->me_value, out_key, out_value) < 0) {
5636
                goto try_locked;
5637
            }
5638
        }
5639
    }
5640
    // We found an element (key), but did not expect it
5641
    Py_ssize_t len;
5642
    if ((len = _Py_atomic_load_ssize_relaxed(&di->len)) == 0) {
5643
        goto concurrent_modification;
5644
    }
5645
5646
    _Py_atomic_store_ssize_relaxed(&di->di_pos, i + 1);
5647
    _Py_atomic_store_ssize_relaxed(&di->len, len - 1);
5648
    return 0;
5649
5650
concurrent_modification:
5651
    PyErr_SetString(PyExc_RuntimeError,
5652
                    "dictionary keys changed during iteration");
5653
5654
fail:
5655
    di->di_dict = NULL;
5656
    Py_DECREF(d);
5657
    return -1;
5658
5659
try_locked:
5660
    Py_BEGIN_CRITICAL_SECTION(d);
5661
    res = dictiter_iternextitem_lock_held(d, self, out_key, out_value);
5662
    Py_END_CRITICAL_SECTION();
5663
    return res;
5664
}
5665
5666
#endif
5667
5668
static bool
5669
has_unique_reference(PyObject *op)
5670
2.07M
{
5671
#ifdef Py_GIL_DISABLED
5672
    return (_Py_IsOwnedByCurrentThread(op) &&
5673
            op->ob_ref_local == 1 &&
5674
            _Py_atomic_load_ssize_relaxed(&op->ob_ref_shared) == 0);
5675
#else
5676
2.07M
    return Py_REFCNT(op) == 1;
5677
2.07M
#endif
5678
2.07M
}
5679
5680
static bool
5681
acquire_iter_result(PyObject *result)
5682
2.07M
{
5683
2.07M
    if (has_unique_reference(result)) {
5684
2.06M
        Py_INCREF(result);
5685
2.06M
        return true;
5686
2.06M
    }
5687
7.67k
    return false;
5688
2.07M
}
5689
5690
static PyObject *
5691
dictiter_iternextitem(PyObject *self)
5692
2.54M
{
5693
2.54M
    dictiterobject *di = (dictiterobject *)self;
5694
2.54M
    PyDictObject *d = di->di_dict;
5695
5696
2.54M
    if (d == NULL)
5697
0
        return NULL;
5698
5699
2.54M
    PyObject *key, *value;
5700
#ifdef Py_GIL_DISABLED
5701
    if (dictiter_iternext_threadsafe(d, self, &key, &value) == 0) {
5702
#else
5703
2.54M
    if (dictiter_iternextitem_lock_held(d, self, &key, &value) == 0) {
5704
5705
2.07M
#endif
5706
2.07M
        PyObject *result = di->di_result;
5707
2.07M
        if (acquire_iter_result(result)) {
5708
2.06M
            PyObject *oldkey = PyTuple_GET_ITEM(result, 0);
5709
2.06M
            PyObject *oldvalue = PyTuple_GET_ITEM(result, 1);
5710
2.06M
            PyTuple_SET_ITEM(result, 0, key);
5711
2.06M
            PyTuple_SET_ITEM(result, 1, value);
5712
2.06M
            Py_DECREF(oldkey);
5713
2.06M
            Py_DECREF(oldvalue);
5714
            // bpo-42536: The GC may have untracked this result tuple. Since we're
5715
            // recycling it, make sure it's tracked again:
5716
2.06M
            _PyTuple_Recycle(result);
5717
2.06M
        }
5718
7.67k
        else {
5719
7.67k
            result = PyTuple_New(2);
5720
7.67k
            if (result == NULL)
5721
0
                return NULL;
5722
7.67k
            PyTuple_SET_ITEM(result, 0, key);
5723
7.67k
            PyTuple_SET_ITEM(result, 1, value);
5724
7.67k
        }
5725
2.07M
        return result;
5726
2.07M
    }
5727
471k
    return NULL;
5728
2.54M
}
5729
5730
PyTypeObject PyDictIterItem_Type = {
5731
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
5732
    "dict_itemiterator",                        /* tp_name */
5733
    sizeof(dictiterobject),                     /* tp_basicsize */
5734
    0,                                          /* tp_itemsize */
5735
    /* methods */
5736
    dictiter_dealloc,                           /* tp_dealloc */
5737
    0,                                          /* tp_vectorcall_offset */
5738
    0,                                          /* tp_getattr */
5739
    0,                                          /* tp_setattr */
5740
    0,                                          /* tp_as_async */
5741
    0,                                          /* tp_repr */
5742
    0,                                          /* tp_as_number */
5743
    0,                                          /* tp_as_sequence */
5744
    0,                                          /* tp_as_mapping */
5745
    0,                                          /* tp_hash */
5746
    0,                                          /* tp_call */
5747
    0,                                          /* tp_str */
5748
    PyObject_GenericGetAttr,                    /* tp_getattro */
5749
    0,                                          /* tp_setattro */
5750
    0,                                          /* tp_as_buffer */
5751
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
5752
    0,                                          /* tp_doc */
5753
    dictiter_traverse,                          /* tp_traverse */
5754
    0,                                          /* tp_clear */
5755
    0,                                          /* tp_richcompare */
5756
    0,                                          /* tp_weaklistoffset */
5757
    PyObject_SelfIter,                          /* tp_iter */
5758
    dictiter_iternextitem,                      /* tp_iternext */
5759
    dictiter_methods,                           /* tp_methods */
5760
    0,
5761
};
5762
5763
5764
/* dictreviter */
5765
5766
static PyObject *
5767
dictreviter_iter_lock_held(PyDictObject *d, PyObject *self)
5768
0
{
5769
0
    dictiterobject *di = (dictiterobject *)self;
5770
5771
0
    assert (PyDict_Check(d));
5772
0
    ASSERT_DICT_LOCKED(d);
5773
5774
0
    if (di->di_used != d->ma_used) {
5775
0
        PyErr_SetString(PyExc_RuntimeError,
5776
0
                         "dictionary changed size during iteration");
5777
0
        di->di_used = -1; /* Make this state sticky */
5778
0
        return NULL;
5779
0
    }
5780
5781
0
    Py_ssize_t i = di->di_pos;
5782
0
    PyDictKeysObject *k = d->ma_keys;
5783
0
    PyObject *key, *value, *result;
5784
5785
0
    if (i < 0) {
5786
0
        goto fail;
5787
0
    }
5788
0
    if (_PyDict_HasSplitTable(d)) {
5789
0
        int index = get_index_from_order(d, i);
5790
0
        key = LOAD_SHARED_KEY(DK_UNICODE_ENTRIES(k)[index].me_key);
5791
0
        value = d->ma_values->values[index];
5792
0
        assert (value != NULL);
5793
0
    }
5794
0
    else {
5795
0
        if (DK_IS_UNICODE(k)) {
5796
0
            PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
5797
0
            while (entry_ptr->me_value == NULL) {
5798
0
                if (--i < 0) {
5799
0
                    goto fail;
5800
0
                }
5801
0
                entry_ptr--;
5802
0
            }
5803
0
            key = entry_ptr->me_key;
5804
0
            value = entry_ptr->me_value;
5805
0
        }
5806
0
        else {
5807
0
            PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
5808
0
            while (entry_ptr->me_value == NULL) {
5809
0
                if (--i < 0) {
5810
0
                    goto fail;
5811
0
                }
5812
0
                entry_ptr--;
5813
0
            }
5814
0
            key = entry_ptr->me_key;
5815
0
            value = entry_ptr->me_value;
5816
0
        }
5817
0
    }
5818
0
    di->di_pos = i-1;
5819
0
    di->len--;
5820
5821
0
    if (Py_IS_TYPE(di, &PyDictRevIterKey_Type)) {
5822
0
        return Py_NewRef(key);
5823
0
    }
5824
0
    else if (Py_IS_TYPE(di, &PyDictRevIterValue_Type)) {
5825
0
        return Py_NewRef(value);
5826
0
    }
5827
0
    else if (Py_IS_TYPE(di, &PyDictRevIterItem_Type)) {
5828
0
        result = di->di_result;
5829
0
        if (Py_REFCNT(result) == 1) {
5830
0
            PyObject *oldkey = PyTuple_GET_ITEM(result, 0);
5831
0
            PyObject *oldvalue = PyTuple_GET_ITEM(result, 1);
5832
0
            PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
5833
0
            PyTuple_SET_ITEM(result, 1, Py_NewRef(value));
5834
0
            Py_INCREF(result);
5835
0
            Py_DECREF(oldkey);
5836
0
            Py_DECREF(oldvalue);
5837
            // bpo-42536: The GC may have untracked this result tuple. Since
5838
            // we're recycling it, make sure it's tracked again:
5839
0
            _PyTuple_Recycle(result);
5840
0
        }
5841
0
        else {
5842
0
            result = PyTuple_New(2);
5843
0
            if (result == NULL) {
5844
0
                return NULL;
5845
0
            }
5846
0
            PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
5847
0
            PyTuple_SET_ITEM(result, 1, Py_NewRef(value));
5848
0
        }
5849
0
        return result;
5850
0
    }
5851
0
    else {
5852
0
        Py_UNREACHABLE();
5853
0
    }
5854
5855
0
fail:
5856
0
    di->di_dict = NULL;
5857
0
    Py_DECREF(d);
5858
0
    return NULL;
5859
0
}
5860
5861
static PyObject *
5862
dictreviter_iternext(PyObject *self)
5863
0
{
5864
0
    dictiterobject *di = (dictiterobject *)self;
5865
0
    PyDictObject *d = di->di_dict;
5866
5867
0
    if (d == NULL)
5868
0
        return NULL;
5869
5870
0
    PyObject *value;
5871
0
    Py_BEGIN_CRITICAL_SECTION(d);
5872
0
    value = dictreviter_iter_lock_held(d, self);
5873
0
    Py_END_CRITICAL_SECTION();
5874
5875
0
    return value;
5876
0
}
5877
5878
PyTypeObject PyDictRevIterKey_Type = {
5879
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
5880
    "dict_reversekeyiterator",
5881
    sizeof(dictiterobject),
5882
    .tp_dealloc = dictiter_dealloc,
5883
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
5884
    .tp_traverse = dictiter_traverse,
5885
    .tp_iter = PyObject_SelfIter,
5886
    .tp_iternext = dictreviter_iternext,
5887
    .tp_methods = dictiter_methods
5888
};
5889
5890
5891
/*[clinic input]
5892
dict.__reversed__
5893
5894
Return a reverse iterator over the dict keys.
5895
[clinic start generated code]*/
5896
5897
static PyObject *
5898
dict___reversed___impl(PyDictObject *self)
5899
/*[clinic end generated code: output=e674483336d1ed51 input=23210ef3477d8c4d]*/
5900
0
{
5901
0
    assert (PyDict_Check(self));
5902
0
    return dictiter_new(self, &PyDictRevIterKey_Type);
5903
0
}
5904
5905
static PyObject *
5906
dictiter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
5907
0
{
5908
0
    dictiterobject *di = (dictiterobject *)self;
5909
    /* copy the iterator state */
5910
0
    dictiterobject tmp = *di;
5911
0
    Py_XINCREF(tmp.di_dict);
5912
0
    PyObject *list = PySequence_List((PyObject*)&tmp);
5913
0
    Py_XDECREF(tmp.di_dict);
5914
0
    if (list == NULL) {
5915
0
        return NULL;
5916
0
    }
5917
0
    return Py_BuildValue("N(N)", _PyEval_GetBuiltin(&_Py_ID(iter)), list);
5918
0
}
5919
5920
PyTypeObject PyDictRevIterItem_Type = {
5921
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
5922
    "dict_reverseitemiterator",
5923
    sizeof(dictiterobject),
5924
    .tp_dealloc = dictiter_dealloc,
5925
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
5926
    .tp_traverse = dictiter_traverse,
5927
    .tp_iter = PyObject_SelfIter,
5928
    .tp_iternext = dictreviter_iternext,
5929
    .tp_methods = dictiter_methods
5930
};
5931
5932
PyTypeObject PyDictRevIterValue_Type = {
5933
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
5934
    "dict_reversevalueiterator",
5935
    sizeof(dictiterobject),
5936
    .tp_dealloc = dictiter_dealloc,
5937
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
5938
    .tp_traverse = dictiter_traverse,
5939
    .tp_iter = PyObject_SelfIter,
5940
    .tp_iternext = dictreviter_iternext,
5941
    .tp_methods = dictiter_methods
5942
};
5943
5944
/***********************************************/
5945
/* View objects for keys(), items(), values(). */
5946
/***********************************************/
5947
5948
/* The instance lay-out is the same for all three; but the type differs. */
5949
5950
static void
5951
dictview_dealloc(PyObject *self)
5952
723k
{
5953
723k
    _PyDictViewObject *dv = (_PyDictViewObject *)self;
5954
    /* bpo-31095: UnTrack is needed before calling any callbacks */
5955
723k
    _PyObject_GC_UNTRACK(dv);
5956
723k
    Py_XDECREF(dv->dv_dict);
5957
723k
    PyObject_GC_Del(dv);
5958
723k
}
5959
5960
static int
5961
dictview_traverse(PyObject *self, visitproc visit, void *arg)
5962
57
{
5963
57
    _PyDictViewObject *dv = (_PyDictViewObject *)self;
5964
57
    Py_VISIT(dv->dv_dict);
5965
57
    return 0;
5966
57
}
5967
5968
static Py_ssize_t
5969
dictview_len(PyObject *self)
5970
0
{
5971
0
    _PyDictViewObject *dv = (_PyDictViewObject *)self;
5972
0
    Py_ssize_t len = 0;
5973
0
    if (dv->dv_dict != NULL)
5974
0
        len = FT_ATOMIC_LOAD_SSIZE_RELAXED(dv->dv_dict->ma_used);
5975
0
    return len;
5976
0
}
5977
5978
PyObject *
5979
_PyDictView_New(PyObject *dict, PyTypeObject *type)
5980
723k
{
5981
723k
    _PyDictViewObject *dv;
5982
723k
    if (dict == NULL) {
5983
0
        PyErr_BadInternalCall();
5984
0
        return NULL;
5985
0
    }
5986
723k
    if (!PyDict_Check(dict)) {
5987
        /* XXX Get rid of this restriction later */
5988
0
        PyErr_Format(PyExc_TypeError,
5989
0
                     "%s() requires a dict argument, not '%s'",
5990
0
                     type->tp_name, Py_TYPE(dict)->tp_name);
5991
0
        return NULL;
5992
0
    }
5993
723k
    dv = PyObject_GC_New(_PyDictViewObject, type);
5994
723k
    if (dv == NULL)
5995
0
        return NULL;
5996
723k
    dv->dv_dict = (PyDictObject *)Py_NewRef(dict);
5997
723k
    _PyObject_GC_TRACK(dv);
5998
723k
    return (PyObject *)dv;
5999
723k
}
6000
6001
static PyObject *
6002
0
dictview_mapping(PyObject *view, void *Py_UNUSED(ignored)) {
6003
0
    assert(view != NULL);
6004
0
    assert(PyDictKeys_Check(view)
6005
0
           || PyDictValues_Check(view)
6006
0
           || PyDictItems_Check(view));
6007
0
    PyObject *mapping = (PyObject *)((_PyDictViewObject *)view)->dv_dict;
6008
0
    return PyDictProxy_New(mapping);
6009
0
}
6010
6011
static PyGetSetDef dictview_getset[] = {
6012
    {"mapping", dictview_mapping, NULL,
6013
     PyDoc_STR("dictionary that this view refers to"), NULL},
6014
    {0}
6015
};
6016
6017
/* TODO(guido): The views objects are not complete:
6018
6019
 * support more set operations
6020
 * support arbitrary mappings?
6021
   - either these should be static or exported in dictobject.h
6022
   - if public then they should probably be in builtins
6023
*/
6024
6025
/* Return 1 if self is a subset of other, iterating over self;
6026
   0 if not; -1 if an error occurred. */
6027
static int
6028
all_contained_in(PyObject *self, PyObject *other)
6029
0
{
6030
0
    PyObject *iter = PyObject_GetIter(self);
6031
0
    int ok = 1;
6032
6033
0
    if (iter == NULL)
6034
0
        return -1;
6035
0
    for (;;) {
6036
0
        PyObject *next = PyIter_Next(iter);
6037
0
        if (next == NULL) {
6038
0
            if (PyErr_Occurred())
6039
0
                ok = -1;
6040
0
            break;
6041
0
        }
6042
0
        ok = PySequence_Contains(other, next);
6043
0
        Py_DECREF(next);
6044
0
        if (ok <= 0)
6045
0
            break;
6046
0
    }
6047
0
    Py_DECREF(iter);
6048
0
    return ok;
6049
0
}
6050
6051
static PyObject *
6052
dictview_richcompare(PyObject *self, PyObject *other, int op)
6053
0
{
6054
0
    Py_ssize_t len_self, len_other;
6055
0
    int ok;
6056
0
    PyObject *result;
6057
6058
0
    assert(self != NULL);
6059
0
    assert(PyDictViewSet_Check(self));
6060
0
    assert(other != NULL);
6061
6062
0
    if (!PyAnySet_Check(other) && !PyDictViewSet_Check(other))
6063
0
        Py_RETURN_NOTIMPLEMENTED;
6064
6065
0
    len_self = PyObject_Size(self);
6066
0
    if (len_self < 0)
6067
0
        return NULL;
6068
0
    len_other = PyObject_Size(other);
6069
0
    if (len_other < 0)
6070
0
        return NULL;
6071
6072
0
    ok = 0;
6073
0
    switch(op) {
6074
6075
0
    case Py_NE:
6076
0
    case Py_EQ:
6077
0
        if (len_self == len_other)
6078
0
            ok = all_contained_in(self, other);
6079
0
        if (op == Py_NE && ok >= 0)
6080
0
            ok = !ok;
6081
0
        break;
6082
6083
0
    case Py_LT:
6084
0
        if (len_self < len_other)
6085
0
            ok = all_contained_in(self, other);
6086
0
        break;
6087
6088
0
      case Py_LE:
6089
0
          if (len_self <= len_other)
6090
0
              ok = all_contained_in(self, other);
6091
0
          break;
6092
6093
0
    case Py_GT:
6094
0
        if (len_self > len_other)
6095
0
            ok = all_contained_in(other, self);
6096
0
        break;
6097
6098
0
    case Py_GE:
6099
0
        if (len_self >= len_other)
6100
0
            ok = all_contained_in(other, self);
6101
0
        break;
6102
6103
0
    }
6104
0
    if (ok < 0)
6105
0
        return NULL;
6106
0
    result = ok ? Py_True : Py_False;
6107
0
    return Py_NewRef(result);
6108
0
}
6109
6110
static PyObject *
6111
dictview_repr(PyObject *self)
6112
0
{
6113
0
    _PyDictViewObject *dv = (_PyDictViewObject *)self;
6114
0
    PyObject *seq;
6115
0
    PyObject *result = NULL;
6116
0
    Py_ssize_t rc;
6117
6118
0
    rc = Py_ReprEnter((PyObject *)dv);
6119
0
    if (rc != 0) {
6120
0
        return rc > 0 ? PyUnicode_FromString("...") : NULL;
6121
0
    }
6122
0
    seq = PySequence_List((PyObject *)dv);
6123
0
    if (seq == NULL) {
6124
0
        goto Done;
6125
0
    }
6126
0
    result = PyUnicode_FromFormat("%s(%R)", Py_TYPE(dv)->tp_name, seq);
6127
0
    Py_DECREF(seq);
6128
6129
0
Done:
6130
0
    Py_ReprLeave((PyObject *)dv);
6131
0
    return result;
6132
0
}
6133
6134
/*** dict_keys ***/
6135
6136
static PyObject *
6137
dictkeys_iter(PyObject *self)
6138
251k
{
6139
251k
    _PyDictViewObject *dv = (_PyDictViewObject *)self;
6140
251k
    if (dv->dv_dict == NULL) {
6141
0
        Py_RETURN_NONE;
6142
0
    }
6143
251k
    return dictiter_new(dv->dv_dict, &PyDictIterKey_Type);
6144
251k
}
6145
6146
static int
6147
dictkeys_contains(PyObject *self, PyObject *obj)
6148
0
{
6149
0
    _PyDictViewObject *dv = (_PyDictViewObject *)self;
6150
0
    if (dv->dv_dict == NULL)
6151
0
        return 0;
6152
0
    return PyDict_Contains((PyObject *)dv->dv_dict, obj);
6153
0
}
6154
6155
static PySequenceMethods dictkeys_as_sequence = {
6156
    dictview_len,                       /* sq_length */
6157
    0,                                  /* sq_concat */
6158
    0,                                  /* sq_repeat */
6159
    0,                                  /* sq_item */
6160
    0,                                  /* sq_slice */
6161
    0,                                  /* sq_ass_item */
6162
    0,                                  /* sq_ass_slice */
6163
    dictkeys_contains,                  /* sq_contains */
6164
};
6165
6166
// Create a set object from dictviews object.
6167
// Returns a new reference.
6168
// This utility function is used by set operations.
6169
static PyObject*
6170
dictviews_to_set(PyObject *self)
6171
0
{
6172
0
    PyObject *left = self;
6173
0
    if (PyDictKeys_Check(self)) {
6174
        // PySet_New() has fast path for the dict object.
6175
0
        PyObject *dict = (PyObject *)((_PyDictViewObject *)self)->dv_dict;
6176
0
        if (PyDict_CheckExact(dict)) {
6177
0
            left = dict;
6178
0
        }
6179
0
    }
6180
0
    return PySet_New(left);
6181
0
}
6182
6183
static PyObject*
6184
dictviews_sub(PyObject *self, PyObject *other)
6185
0
{
6186
0
    PyObject *result = dictviews_to_set(self);
6187
0
    if (result == NULL) {
6188
0
        return NULL;
6189
0
    }
6190
6191
0
    PyObject *tmp = PyObject_CallMethodOneArg(
6192
0
            result, &_Py_ID(difference_update), other);
6193
0
    if (tmp == NULL) {
6194
0
        Py_DECREF(result);
6195
0
        return NULL;
6196
0
    }
6197
6198
0
    Py_DECREF(tmp);
6199
0
    return result;
6200
0
}
6201
6202
static int
6203
dictitems_contains(PyObject *dv, PyObject *obj);
6204
6205
PyObject *
6206
_PyDictView_Intersect(PyObject* self, PyObject *other)
6207
0
{
6208
0
    PyObject *result;
6209
0
    PyObject *it;
6210
0
    PyObject *key;
6211
0
    Py_ssize_t len_self;
6212
0
    int rv;
6213
0
    objobjproc dict_contains;
6214
6215
    /* Python interpreter swaps parameters when dict view
6216
       is on right side of & */
6217
0
    if (!PyDictViewSet_Check(self)) {
6218
0
        PyObject *tmp = other;
6219
0
        other = self;
6220
0
        self = tmp;
6221
0
    }
6222
6223
0
    len_self = dictview_len(self);
6224
6225
    /* if other is a set and self is smaller than other,
6226
       reuse set intersection logic */
6227
0
    if (PySet_CheckExact(other) && len_self <= PyObject_Size(other)) {
6228
0
        return PyObject_CallMethodObjArgs(
6229
0
                other, &_Py_ID(intersection), self, NULL);
6230
0
    }
6231
6232
    /* if other is another dict view, and it is bigger than self,
6233
       swap them */
6234
0
    if (PyDictViewSet_Check(other)) {
6235
0
        Py_ssize_t len_other = dictview_len(other);
6236
0
        if (len_other > len_self) {
6237
0
            PyObject *tmp = other;
6238
0
            other = self;
6239
0
            self = tmp;
6240
0
        }
6241
0
    }
6242
6243
    /* at this point, two things should be true
6244
       1. self is a dictview
6245
       2. if other is a dictview then it is smaller than self */
6246
0
    result = PySet_New(NULL);
6247
0
    if (result == NULL)
6248
0
        return NULL;
6249
6250
0
    it = PyObject_GetIter(other);
6251
0
    if (it == NULL) {
6252
0
        Py_DECREF(result);
6253
0
        return NULL;
6254
0
    }
6255
6256
0
    if (PyDictKeys_Check(self)) {
6257
0
        dict_contains = dictkeys_contains;
6258
0
    }
6259
    /* else PyDictItems_Check(self) */
6260
0
    else {
6261
0
        dict_contains = dictitems_contains;
6262
0
    }
6263
6264
0
    while ((key = PyIter_Next(it)) != NULL) {
6265
0
        rv = dict_contains(self, key);
6266
0
        if (rv < 0) {
6267
0
            goto error;
6268
0
        }
6269
0
        if (rv) {
6270
0
            if (PySet_Add(result, key)) {
6271
0
                goto error;
6272
0
            }
6273
0
        }
6274
0
        Py_DECREF(key);
6275
0
    }
6276
0
    Py_DECREF(it);
6277
0
    if (PyErr_Occurred()) {
6278
0
        Py_DECREF(result);
6279
0
        return NULL;
6280
0
    }
6281
0
    return result;
6282
6283
0
error:
6284
0
    Py_DECREF(it);
6285
0
    Py_DECREF(result);
6286
0
    Py_DECREF(key);
6287
0
    return NULL;
6288
0
}
6289
6290
static PyObject*
6291
dictviews_or(PyObject* self, PyObject *other)
6292
0
{
6293
0
    PyObject *result = dictviews_to_set(self);
6294
0
    if (result == NULL) {
6295
0
        return NULL;
6296
0
    }
6297
6298
0
    if (_PySet_Update(result, other) < 0) {
6299
0
        Py_DECREF(result);
6300
0
        return NULL;
6301
0
    }
6302
0
    return result;
6303
0
}
6304
6305
static PyObject *
6306
dictitems_xor_lock_held(PyObject *d1, PyObject *d2)
6307
0
{
6308
0
    ASSERT_DICT_LOCKED(d1);
6309
0
    ASSERT_DICT_LOCKED(d2);
6310
6311
0
    PyObject *temp_dict = copy_lock_held(d1);
6312
0
    if (temp_dict == NULL) {
6313
0
        return NULL;
6314
0
    }
6315
0
    PyObject *result_set = PySet_New(NULL);
6316
0
    if (result_set == NULL) {
6317
0
        Py_CLEAR(temp_dict);
6318
0
        return NULL;
6319
0
    }
6320
6321
0
    PyObject *key = NULL, *val1 = NULL, *val2 = NULL;
6322
0
    Py_ssize_t pos = 0;
6323
0
    Py_hash_t hash;
6324
6325
0
    while (_PyDict_Next(d2, &pos, &key, &val2, &hash)) {
6326
0
        Py_INCREF(key);
6327
0
        Py_INCREF(val2);
6328
0
        val1 = _PyDict_GetItem_KnownHash(temp_dict, key, hash);
6329
6330
0
        int to_delete;
6331
0
        if (val1 == NULL) {
6332
0
            if (PyErr_Occurred()) {
6333
0
                goto error;
6334
0
            }
6335
0
            to_delete = 0;
6336
0
        }
6337
0
        else {
6338
0
            Py_INCREF(val1);
6339
0
            to_delete = PyObject_RichCompareBool(val1, val2, Py_EQ);
6340
0
            if (to_delete < 0) {
6341
0
                goto error;
6342
0
            }
6343
0
        }
6344
6345
0
        if (to_delete) {
6346
0
            if (_PyDict_DelItem_KnownHash(temp_dict, key, hash) < 0) {
6347
0
                goto error;
6348
0
            }
6349
0
        }
6350
0
        else {
6351
0
            PyObject *pair = PyTuple_Pack(2, key, val2);
6352
0
            if (pair == NULL) {
6353
0
                goto error;
6354
0
            }
6355
0
            if (PySet_Add(result_set, pair) < 0) {
6356
0
                Py_DECREF(pair);
6357
0
                goto error;
6358
0
            }
6359
0
            Py_DECREF(pair);
6360
0
        }
6361
0
        Py_DECREF(key);
6362
0
        Py_XDECREF(val1);
6363
0
        Py_DECREF(val2);
6364
0
    }
6365
0
    key = val1 = val2 = NULL;
6366
6367
0
    PyObject *remaining_pairs = PyObject_CallMethodNoArgs(
6368
0
            temp_dict, &_Py_ID(items));
6369
0
    if (remaining_pairs == NULL) {
6370
0
        goto error;
6371
0
    }
6372
0
    if (_PySet_Update(result_set, remaining_pairs) < 0) {
6373
0
        Py_DECREF(remaining_pairs);
6374
0
        goto error;
6375
0
    }
6376
0
    Py_DECREF(temp_dict);
6377
0
    Py_DECREF(remaining_pairs);
6378
0
    return result_set;
6379
6380
0
error:
6381
0
    Py_XDECREF(temp_dict);
6382
0
    Py_XDECREF(result_set);
6383
0
    Py_XDECREF(key);
6384
0
    Py_XDECREF(val1);
6385
0
    Py_XDECREF(val2);
6386
0
    return NULL;
6387
0
}
6388
6389
static PyObject *
6390
dictitems_xor(PyObject *self, PyObject *other)
6391
0
{
6392
0
    assert(PyDictItems_Check(self));
6393
0
    assert(PyDictItems_Check(other));
6394
0
    PyObject *d1 = (PyObject *)((_PyDictViewObject *)self)->dv_dict;
6395
0
    PyObject *d2 = (PyObject *)((_PyDictViewObject *)other)->dv_dict;
6396
6397
0
    PyObject *res;
6398
0
    Py_BEGIN_CRITICAL_SECTION2(d1, d2);
6399
0
    res = dictitems_xor_lock_held(d1, d2);
6400
0
    Py_END_CRITICAL_SECTION2();
6401
6402
0
    return res;
6403
0
}
6404
6405
static PyObject*
6406
dictviews_xor(PyObject* self, PyObject *other)
6407
0
{
6408
0
    if (PyDictItems_Check(self) && PyDictItems_Check(other)) {
6409
0
        return dictitems_xor(self, other);
6410
0
    }
6411
0
    PyObject *result = dictviews_to_set(self);
6412
0
    if (result == NULL) {
6413
0
        return NULL;
6414
0
    }
6415
6416
0
    PyObject *tmp = PyObject_CallMethodOneArg(
6417
0
            result, &_Py_ID(symmetric_difference_update), other);
6418
0
    if (tmp == NULL) {
6419
0
        Py_DECREF(result);
6420
0
        return NULL;
6421
0
    }
6422
6423
0
    Py_DECREF(tmp);
6424
0
    return result;
6425
0
}
6426
6427
static PyNumberMethods dictviews_as_number = {
6428
    0,                                  /*nb_add*/
6429
    dictviews_sub,                      /*nb_subtract*/
6430
    0,                                  /*nb_multiply*/
6431
    0,                                  /*nb_remainder*/
6432
    0,                                  /*nb_divmod*/
6433
    0,                                  /*nb_power*/
6434
    0,                                  /*nb_negative*/
6435
    0,                                  /*nb_positive*/
6436
    0,                                  /*nb_absolute*/
6437
    0,                                  /*nb_bool*/
6438
    0,                                  /*nb_invert*/
6439
    0,                                  /*nb_lshift*/
6440
    0,                                  /*nb_rshift*/
6441
    _PyDictView_Intersect,              /*nb_and*/
6442
    dictviews_xor,                      /*nb_xor*/
6443
    dictviews_or,                       /*nb_or*/
6444
};
6445
6446
static PyObject*
6447
dictviews_isdisjoint(PyObject *self, PyObject *other)
6448
0
{
6449
0
    PyObject *it;
6450
0
    PyObject *item = NULL;
6451
6452
0
    if (self == other) {
6453
0
        if (dictview_len(self) == 0)
6454
0
            Py_RETURN_TRUE;
6455
0
        else
6456
0
            Py_RETURN_FALSE;
6457
0
    }
6458
6459
    /* Iterate over the shorter object (only if other is a set,
6460
     * because PySequence_Contains may be expensive otherwise): */
6461
0
    if (PyAnySet_Check(other) || PyDictViewSet_Check(other)) {
6462
0
        Py_ssize_t len_self = dictview_len(self);
6463
0
        Py_ssize_t len_other = PyObject_Size(other);
6464
0
        if (len_other == -1)
6465
0
            return NULL;
6466
6467
0
        if ((len_other > len_self)) {
6468
0
            PyObject *tmp = other;
6469
0
            other = self;
6470
0
            self = tmp;
6471
0
        }
6472
0
    }
6473
6474
0
    it = PyObject_GetIter(other);
6475
0
    if (it == NULL)
6476
0
        return NULL;
6477
6478
0
    while ((item = PyIter_Next(it)) != NULL) {
6479
0
        int contains = PySequence_Contains(self, item);
6480
0
        Py_DECREF(item);
6481
0
        if (contains == -1) {
6482
0
            Py_DECREF(it);
6483
0
            return NULL;
6484
0
        }
6485
6486
0
        if (contains) {
6487
0
            Py_DECREF(it);
6488
0
            Py_RETURN_FALSE;
6489
0
        }
6490
0
    }
6491
0
    Py_DECREF(it);
6492
0
    if (PyErr_Occurred())
6493
0
        return NULL; /* PyIter_Next raised an exception. */
6494
0
    Py_RETURN_TRUE;
6495
0
}
6496
6497
PyDoc_STRVAR(isdisjoint_doc,
6498
"Return True if the view and the given iterable have a null intersection.");
6499
6500
static PyObject* dictkeys_reversed(PyObject *dv, PyObject *Py_UNUSED(ignored));
6501
6502
PyDoc_STRVAR(reversed_keys_doc,
6503
"Return a reverse iterator over the dict keys.");
6504
6505
static PyMethodDef dictkeys_methods[] = {
6506
    {"isdisjoint",      dictviews_isdisjoint,           METH_O,
6507
     isdisjoint_doc},
6508
    {"__reversed__",    dictkeys_reversed,              METH_NOARGS,
6509
     reversed_keys_doc},
6510
    {NULL,              NULL}           /* sentinel */
6511
};
6512
6513
PyTypeObject PyDictKeys_Type = {
6514
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
6515
    "dict_keys",                                /* tp_name */
6516
    sizeof(_PyDictViewObject),                  /* tp_basicsize */
6517
    0,                                          /* tp_itemsize */
6518
    /* methods */
6519
    dictview_dealloc,                           /* tp_dealloc */
6520
    0,                                          /* tp_vectorcall_offset */
6521
    0,                                          /* tp_getattr */
6522
    0,                                          /* tp_setattr */
6523
    0,                                          /* tp_as_async */
6524
    dictview_repr,                              /* tp_repr */
6525
    &dictviews_as_number,                       /* tp_as_number */
6526
    &dictkeys_as_sequence,                      /* tp_as_sequence */
6527
    0,                                          /* tp_as_mapping */
6528
    0,                                          /* tp_hash */
6529
    0,                                          /* tp_call */
6530
    0,                                          /* tp_str */
6531
    PyObject_GenericGetAttr,                    /* tp_getattro */
6532
    0,                                          /* tp_setattro */
6533
    0,                                          /* tp_as_buffer */
6534
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
6535
    0,                                          /* tp_doc */
6536
    dictview_traverse,                          /* tp_traverse */
6537
    0,                                          /* tp_clear */
6538
    dictview_richcompare,                       /* tp_richcompare */
6539
    0,                                          /* tp_weaklistoffset */
6540
    dictkeys_iter,                              /* tp_iter */
6541
    0,                                          /* tp_iternext */
6542
    dictkeys_methods,                           /* tp_methods */
6543
    .tp_getset = dictview_getset,
6544
};
6545
6546
/*[clinic input]
6547
dict.keys
6548
6549
Return a set-like object providing a view on the dict's keys.
6550
[clinic start generated code]*/
6551
6552
static PyObject *
6553
dict_keys_impl(PyDictObject *self)
6554
/*[clinic end generated code: output=aac2830c62990358 input=42f48a7a771212a7]*/
6555
251k
{
6556
251k
    return _PyDictView_New((PyObject *)self, &PyDictKeys_Type);
6557
251k
}
6558
6559
static PyObject *
6560
dictkeys_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
6561
0
{
6562
0
    _PyDictViewObject *dv = (_PyDictViewObject *)self;
6563
0
    if (dv->dv_dict == NULL) {
6564
0
        Py_RETURN_NONE;
6565
0
    }
6566
0
    return dictiter_new(dv->dv_dict, &PyDictRevIterKey_Type);
6567
0
}
6568
6569
/*** dict_items ***/
6570
6571
static PyObject *
6572
dictitems_iter(PyObject *self)
6573
471k
{
6574
471k
    _PyDictViewObject *dv = (_PyDictViewObject *)self;
6575
471k
    if (dv->dv_dict == NULL) {
6576
0
        Py_RETURN_NONE;
6577
0
    }
6578
471k
    return dictiter_new(dv->dv_dict, &PyDictIterItem_Type);
6579
471k
}
6580
6581
static int
6582
dictitems_contains(PyObject *self, PyObject *obj)
6583
0
{
6584
0
    _PyDictViewObject *dv = (_PyDictViewObject *)self;
6585
0
    int result;
6586
0
    PyObject *key, *value, *found;
6587
0
    if (dv->dv_dict == NULL)
6588
0
        return 0;
6589
0
    if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 2)
6590
0
        return 0;
6591
0
    key = PyTuple_GET_ITEM(obj, 0);
6592
0
    value = PyTuple_GET_ITEM(obj, 1);
6593
0
    result = PyDict_GetItemRef((PyObject *)dv->dv_dict, key, &found);
6594
0
    if (result == 1) {
6595
0
        result = PyObject_RichCompareBool(found, value, Py_EQ);
6596
0
        Py_DECREF(found);
6597
0
    }
6598
0
    return result;
6599
0
}
6600
6601
static PySequenceMethods dictitems_as_sequence = {
6602
    dictview_len,                       /* sq_length */
6603
    0,                                  /* sq_concat */
6604
    0,                                  /* sq_repeat */
6605
    0,                                  /* sq_item */
6606
    0,                                  /* sq_slice */
6607
    0,                                  /* sq_ass_item */
6608
    0,                                  /* sq_ass_slice */
6609
    dictitems_contains,                 /* sq_contains */
6610
};
6611
6612
static PyObject* dictitems_reversed(PyObject *dv, PyObject *Py_UNUSED(ignored));
6613
6614
PyDoc_STRVAR(reversed_items_doc,
6615
"Return a reverse iterator over the dict items.");
6616
6617
static PyMethodDef dictitems_methods[] = {
6618
    {"isdisjoint",      dictviews_isdisjoint,           METH_O,
6619
     isdisjoint_doc},
6620
    {"__reversed__",    dictitems_reversed,             METH_NOARGS,
6621
     reversed_items_doc},
6622
    {NULL,              NULL}           /* sentinel */
6623
};
6624
6625
PyTypeObject PyDictItems_Type = {
6626
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
6627
    "dict_items",                               /* tp_name */
6628
    sizeof(_PyDictViewObject),                  /* tp_basicsize */
6629
    0,                                          /* tp_itemsize */
6630
    /* methods */
6631
    dictview_dealloc,                           /* tp_dealloc */
6632
    0,                                          /* tp_vectorcall_offset */
6633
    0,                                          /* tp_getattr */
6634
    0,                                          /* tp_setattr */
6635
    0,                                          /* tp_as_async */
6636
    dictview_repr,                              /* tp_repr */
6637
    &dictviews_as_number,                       /* tp_as_number */
6638
    &dictitems_as_sequence,                     /* tp_as_sequence */
6639
    0,                                          /* tp_as_mapping */
6640
    0,                                          /* tp_hash */
6641
    0,                                          /* tp_call */
6642
    0,                                          /* tp_str */
6643
    PyObject_GenericGetAttr,                    /* tp_getattro */
6644
    0,                                          /* tp_setattro */
6645
    0,                                          /* tp_as_buffer */
6646
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
6647
    0,                                          /* tp_doc */
6648
    dictview_traverse,                          /* tp_traverse */
6649
    0,                                          /* tp_clear */
6650
    dictview_richcompare,                       /* tp_richcompare */
6651
    0,                                          /* tp_weaklistoffset */
6652
    dictitems_iter,                             /* tp_iter */
6653
    0,                                          /* tp_iternext */
6654
    dictitems_methods,                          /* tp_methods */
6655
    .tp_getset = dictview_getset,
6656
};
6657
6658
/*[clinic input]
6659
dict.items
6660
6661
Return a set-like object providing a view on the dict's items.
6662
[clinic start generated code]*/
6663
6664
static PyObject *
6665
dict_items_impl(PyDictObject *self)
6666
/*[clinic end generated code: output=88c7db7150c7909a input=87c822872eb71f5a]*/
6667
471k
{
6668
471k
    return _PyDictView_New((PyObject *)self, &PyDictItems_Type);
6669
471k
}
6670
6671
static PyObject *
6672
dictitems_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
6673
0
{
6674
0
    _PyDictViewObject *dv = (_PyDictViewObject *)self;
6675
0
    if (dv->dv_dict == NULL) {
6676
0
        Py_RETURN_NONE;
6677
0
    }
6678
0
    return dictiter_new(dv->dv_dict, &PyDictRevIterItem_Type);
6679
0
}
6680
6681
/*** dict_values ***/
6682
6683
static PyObject *
6684
dictvalues_iter(PyObject *self)
6685
98
{
6686
98
    _PyDictViewObject *dv = (_PyDictViewObject *)self;
6687
98
    if (dv->dv_dict == NULL) {
6688
0
        Py_RETURN_NONE;
6689
0
    }
6690
98
    return dictiter_new(dv->dv_dict, &PyDictIterValue_Type);
6691
98
}
6692
6693
static PySequenceMethods dictvalues_as_sequence = {
6694
    dictview_len,                       /* sq_length */
6695
    0,                                  /* sq_concat */
6696
    0,                                  /* sq_repeat */
6697
    0,                                  /* sq_item */
6698
    0,                                  /* sq_slice */
6699
    0,                                  /* sq_ass_item */
6700
    0,                                  /* sq_ass_slice */
6701
    0,                                  /* sq_contains */
6702
};
6703
6704
static PyObject* dictvalues_reversed(PyObject *dv, PyObject *Py_UNUSED(ignored));
6705
6706
PyDoc_STRVAR(reversed_values_doc,
6707
"Return a reverse iterator over the dict values.");
6708
6709
static PyMethodDef dictvalues_methods[] = {
6710
    {"__reversed__",    dictvalues_reversed,            METH_NOARGS,
6711
     reversed_values_doc},
6712
    {NULL,              NULL}           /* sentinel */
6713
};
6714
6715
PyTypeObject PyDictValues_Type = {
6716
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
6717
    "dict_values",                              /* tp_name */
6718
    sizeof(_PyDictViewObject),                  /* tp_basicsize */
6719
    0,                                          /* tp_itemsize */
6720
    /* methods */
6721
    dictview_dealloc,                           /* tp_dealloc */
6722
    0,                                          /* tp_vectorcall_offset */
6723
    0,                                          /* tp_getattr */
6724
    0,                                          /* tp_setattr */
6725
    0,                                          /* tp_as_async */
6726
    dictview_repr,                              /* tp_repr */
6727
    0,                                          /* tp_as_number */
6728
    &dictvalues_as_sequence,                    /* tp_as_sequence */
6729
    0,                                          /* tp_as_mapping */
6730
    0,                                          /* tp_hash */
6731
    0,                                          /* tp_call */
6732
    0,                                          /* tp_str */
6733
    PyObject_GenericGetAttr,                    /* tp_getattro */
6734
    0,                                          /* tp_setattro */
6735
    0,                                          /* tp_as_buffer */
6736
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
6737
    0,                                          /* tp_doc */
6738
    dictview_traverse,                          /* tp_traverse */
6739
    0,                                          /* tp_clear */
6740
    0,                                          /* tp_richcompare */
6741
    0,                                          /* tp_weaklistoffset */
6742
    dictvalues_iter,                            /* tp_iter */
6743
    0,                                          /* tp_iternext */
6744
    dictvalues_methods,                         /* tp_methods */
6745
    .tp_getset = dictview_getset,
6746
};
6747
6748
/*[clinic input]
6749
dict.values
6750
6751
Return an object providing a view on the dict's values.
6752
[clinic start generated code]*/
6753
6754
static PyObject *
6755
dict_values_impl(PyDictObject *self)
6756
/*[clinic end generated code: output=ce9f2e9e8a959dd4 input=b46944f85493b230]*/
6757
116
{
6758
116
    return _PyDictView_New((PyObject *)self, &PyDictValues_Type);
6759
116
}
6760
6761
static PyObject *
6762
dictvalues_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
6763
0
{
6764
0
    _PyDictViewObject *dv = (_PyDictViewObject *)self;
6765
0
    if (dv->dv_dict == NULL) {
6766
0
        Py_RETURN_NONE;
6767
0
    }
6768
0
    return dictiter_new(dv->dv_dict, &PyDictRevIterValue_Type);
6769
0
}
6770
6771
6772
/* Returns NULL if cannot allocate a new PyDictKeysObject,
6773
   but does not set an error */
6774
PyDictKeysObject *
6775
_PyDict_NewKeysForClass(PyHeapTypeObject *cls)
6776
298k
{
6777
298k
    PyDictKeysObject *keys = new_keys_object(NEXT_LOG2_SHARED_KEYS_MAX_SIZE, 1);
6778
298k
    if (keys == NULL) {
6779
0
        PyErr_Clear();
6780
0
    }
6781
298k
    else {
6782
298k
        assert(keys->dk_nentries == 0);
6783
        /* Set to max size+1 as it will shrink by one before each new object */
6784
298k
        keys->dk_usable = SHARED_KEYS_MAX_SIZE;
6785
298k
        keys->dk_kind = DICT_KEYS_SPLIT;
6786
298k
    }
6787
298k
    if (cls->ht_type.tp_dict) {
6788
298k
        PyObject *attrs = PyDict_GetItem(cls->ht_type.tp_dict, &_Py_ID(__static_attributes__));
6789
298k
        if (attrs != NULL && PyTuple_Check(attrs)) {
6790
6.92k
            for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(attrs); i++) {
6791
3.64k
                PyObject *key = PyTuple_GET_ITEM(attrs, i);
6792
3.64k
                Py_hash_t hash;
6793
3.64k
                if (PyUnicode_CheckExact(key) && (hash = unicode_get_hash(key)) != -1) {
6794
3.64k
                    if (insert_split_key(keys, key, hash) == DKIX_EMPTY) {
6795
0
                        break;
6796
0
                    }
6797
3.64k
                }
6798
3.64k
            }
6799
3.27k
        }
6800
298k
    }
6801
298k
    return keys;
6802
298k
}
6803
6804
void
6805
_PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp)
6806
27.8M
{
6807
27.8M
    assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE);
6808
27.8M
    assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES);
6809
27.8M
    assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
6810
27.8M
    PyDictKeysObject *keys = CACHED_KEYS(tp);
6811
27.8M
    assert(keys != NULL);
6812
27.8M
    OBJECT_STAT_INC(inline_values);
6813
#ifdef Py_GIL_DISABLED
6814
    Py_ssize_t usable = _Py_atomic_load_ssize_relaxed(&keys->dk_usable);
6815
    if (usable > 1) {
6816
        LOCK_KEYS(keys);
6817
        if (keys->dk_usable > 1) {
6818
            _Py_atomic_store_ssize(&keys->dk_usable, keys->dk_usable - 1);
6819
        }
6820
        UNLOCK_KEYS(keys);
6821
    }
6822
#else
6823
27.8M
    if (keys->dk_usable > 1) {
6824
300k
        keys->dk_usable--;
6825
300k
    }
6826
27.8M
#endif
6827
27.8M
    size_t size = shared_keys_usable_size(keys);
6828
27.8M
    PyDictValues *values = _PyObject_InlineValues(obj);
6829
27.8M
    assert(size < 256);
6830
27.8M
    values->capacity = (uint8_t)size;
6831
27.8M
    values->size = 0;
6832
27.8M
    values->embedded = 1;
6833
27.8M
    values->valid = 1;
6834
168M
    for (size_t i = 0; i < size; i++) {
6835
141M
        values->values[i] = NULL;
6836
141M
    }
6837
27.8M
    _PyObject_ManagedDictPointer(obj)->dict = NULL;
6838
27.8M
}
6839
6840
static PyDictObject *
6841
make_dict_from_instance_attributes(PyDictKeysObject *keys, PyDictValues *values)
6842
694k
{
6843
694k
    dictkeys_incref(keys);
6844
694k
    Py_ssize_t used = 0;
6845
694k
    size_t size = shared_keys_usable_size(keys);
6846
2.12M
    for (size_t i = 0; i < size; i++) {
6847
1.42M
        PyObject *val = values->values[i];
6848
1.42M
        if (val != NULL) {
6849
1.10M
            used += 1;
6850
1.10M
        }
6851
1.42M
    }
6852
694k
    PyDictObject *res = (PyDictObject *)new_dict(keys, values, used, 0);
6853
694k
    return res;
6854
694k
}
6855
6856
PyDictObject *
6857
_PyObject_MaterializeManagedDict_LockHeld(PyObject *obj)
6858
4
{
6859
4
    ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(obj);
6860
6861
4
    OBJECT_STAT_INC(dict_materialized_on_request);
6862
6863
4
    PyDictValues *values = _PyObject_InlineValues(obj);
6864
4
    PyDictObject *dict;
6865
4
    if (values->valid) {
6866
4
        PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
6867
4
        dict = make_dict_from_instance_attributes(keys, values);
6868
4
    }
6869
0
    else {
6870
0
        dict = (PyDictObject *)PyDict_New();
6871
0
    }
6872
4
    FT_ATOMIC_STORE_PTR_RELEASE(_PyObject_ManagedDictPointer(obj)->dict,
6873
4
                                dict);
6874
4
    return dict;
6875
4
}
6876
6877
PyDictObject *
6878
_PyObject_MaterializeManagedDict(PyObject *obj)
6879
3.23M
{
6880
3.23M
    PyDictObject *dict = _PyObject_GetManagedDict(obj);
6881
3.23M
    if (dict != NULL) {
6882
3.23M
        return dict;
6883
3.23M
    }
6884
6885
4
    Py_BEGIN_CRITICAL_SECTION(obj);
6886
6887
#ifdef Py_GIL_DISABLED
6888
    dict = _PyObject_GetManagedDict(obj);
6889
    if (dict != NULL) {
6890
        // We raced with another thread creating the dict
6891
        goto exit;
6892
    }
6893
#endif
6894
4
    dict = _PyObject_MaterializeManagedDict_LockHeld(obj);
6895
6896
#ifdef Py_GIL_DISABLED
6897
exit:
6898
#endif
6899
4
    Py_END_CRITICAL_SECTION();
6900
4
    return dict;
6901
3.23M
}
6902
6903
int
6904
_PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value)
6905
14.0M
{
6906
14.0M
    if (value == NULL) {
6907
10.7k
        Py_hash_t hash = _PyObject_HashFast(name);
6908
10.7k
        if (hash == -1) {
6909
0
            dict_unhashable_type(name);
6910
0
            return -1;
6911
0
        }
6912
10.7k
        return delitem_knownhash_lock_held((PyObject *)dict, name, hash);
6913
14.0M
    } else {
6914
14.0M
        return setitem_lock_held(dict, name, value);
6915
14.0M
    }
6916
14.0M
}
6917
6918
// Called with either the object's lock or the dict's lock held
6919
// depending on whether or not a dict has been materialized for
6920
// the object.
6921
static int
6922
store_instance_attr_lock_held(PyObject *obj, PyDictValues *values,
6923
                              PyObject *name, PyObject *value)
6924
17.3M
{
6925
17.3M
    PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
6926
17.3M
    assert(keys != NULL);
6927
17.3M
    assert(values != NULL);
6928
17.3M
    assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_INLINE_VALUES);
6929
17.3M
    Py_ssize_t ix = DKIX_EMPTY;
6930
17.3M
    PyDictObject *dict = _PyObject_GetManagedDict(obj);
6931
17.3M
    assert(dict == NULL || ((PyDictObject *)dict)->ma_values == values);
6932
17.3M
    if (PyUnicode_CheckExact(name)) {
6933
17.3M
        Py_hash_t hash = unicode_get_hash(name);
6934
17.3M
        if (hash == -1) {
6935
0
            hash = PyUnicode_Type.tp_hash(name);
6936
0
            assert(hash != -1);
6937
0
        }
6938
6939
17.3M
        ix = insert_split_key(keys, name, hash);
6940
6941
#ifdef Py_STATS
6942
        if (ix == DKIX_EMPTY) {
6943
            if (PyUnicode_CheckExact(name)) {
6944
                if (shared_keys_usable_size(keys) == SHARED_KEYS_MAX_SIZE) {
6945
                    OBJECT_STAT_INC(dict_materialized_too_big);
6946
                }
6947
                else {
6948
                    OBJECT_STAT_INC(dict_materialized_new_key);
6949
                }
6950
            }
6951
            else {
6952
                OBJECT_STAT_INC(dict_materialized_str_subclass);
6953
            }
6954
        }
6955
#endif
6956
17.3M
    }
6957
6958
17.3M
    if (ix == DKIX_EMPTY) {
6959
694k
        int res;
6960
694k
        if (dict == NULL) {
6961
            // Make the dict but don't publish it in the object
6962
            // so that no one else will see it.
6963
694k
            dict = make_dict_from_instance_attributes(keys, values);
6964
694k
            if (dict == NULL ||
6965
694k
                _PyDict_SetItem_LockHeld(dict, name, value) < 0) {
6966
0
                Py_XDECREF(dict);
6967
0
                return -1;
6968
0
            }
6969
6970
694k
            FT_ATOMIC_STORE_PTR_RELEASE(_PyObject_ManagedDictPointer(obj)->dict,
6971
694k
                                        (PyDictObject *)dict);
6972
694k
            return 0;
6973
694k
        }
6974
6975
0
        _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(dict);
6976
6977
0
        res = _PyDict_SetItem_LockHeld(dict, name, value);
6978
0
        return res;
6979
694k
    }
6980
6981
16.6M
    PyObject *old_value = values->values[ix];
6982
16.6M
    if (old_value == NULL && value == NULL) {
6983
0
        PyErr_Format(PyExc_AttributeError,
6984
0
                        "'%.100s' object has no attribute '%U'",
6985
0
                        Py_TYPE(obj)->tp_name, name);
6986
0
        (void)_PyObject_SetAttributeErrorContext(obj, name);
6987
0
        return -1;
6988
0
    }
6989
6990
16.6M
    if (dict) {
6991
0
        PyInterpreterState *interp = _PyInterpreterState_GET();
6992
0
        PyDict_WatchEvent event = (old_value == NULL ? PyDict_EVENT_ADDED :
6993
0
                                   value == NULL ? PyDict_EVENT_DELETED :
6994
0
                                   PyDict_EVENT_MODIFIED);
6995
0
        _PyDict_NotifyEvent(interp, event, dict, name, value);
6996
0
    }
6997
6998
16.6M
    FT_ATOMIC_STORE_PTR_RELEASE(values->values[ix], Py_XNewRef(value));
6999
7000
16.6M
    if (old_value == NULL) {
7001
13.0M
        _PyDictValues_AddToInsertionOrder(values, ix);
7002
13.0M
        if (dict) {
7003
0
            assert(dict->ma_values == values);
7004
0
            STORE_USED(dict, dict->ma_used + 1);
7005
0
        }
7006
13.0M
    }
7007
3.56M
    else {
7008
3.56M
        if (value == NULL) {
7009
240k
            delete_index_from_values(values, ix);
7010
240k
            if (dict) {
7011
0
                assert(dict->ma_values == values);
7012
0
                STORE_USED(dict, dict->ma_used - 1);
7013
0
            }
7014
240k
        }
7015
3.56M
        Py_DECREF(old_value);
7016
3.56M
    }
7017
16.6M
    return 0;
7018
16.6M
}
7019
7020
static inline int
7021
store_instance_attr_dict(PyObject *obj, PyDictObject *dict, PyObject *name, PyObject *value)
7022
367k
{
7023
367k
    PyDictValues *values = _PyObject_InlineValues(obj);
7024
367k
    int res;
7025
367k
    Py_BEGIN_CRITICAL_SECTION(dict);
7026
367k
    if (dict->ma_values == values) {
7027
0
        res = store_instance_attr_lock_held(obj, values, name, value);
7028
0
    }
7029
367k
    else {
7030
367k
        res = _PyDict_SetItem_LockHeld(dict, name, value);
7031
367k
    }
7032
367k
    Py_END_CRITICAL_SECTION();
7033
367k
    return res;
7034
367k
}
7035
7036
int
7037
_PyObject_StoreInstanceAttribute(PyObject *obj, PyObject *name, PyObject *value)
7038
17.7M
{
7039
17.7M
    PyDictValues *values = _PyObject_InlineValues(obj);
7040
17.7M
    if (!FT_ATOMIC_LOAD_UINT8(values->valid)) {
7041
367k
        PyDictObject *dict = _PyObject_GetManagedDict(obj);
7042
367k
        if (dict == NULL) {
7043
0
            dict = (PyDictObject *)PyObject_GenericGetDict(obj, NULL);
7044
0
            if (dict == NULL) {
7045
0
                return -1;
7046
0
            }
7047
0
            int res = store_instance_attr_dict(obj, dict, name, value);
7048
0
            Py_DECREF(dict);
7049
0
            return res;
7050
0
        }
7051
367k
        return store_instance_attr_dict(obj, dict, name, value);
7052
367k
    }
7053
7054
#ifdef Py_GIL_DISABLED
7055
    // We have a valid inline values, at least for now...  There are two potential
7056
    // races with having the values become invalid.  One is the dictionary
7057
    // being detached from the object.  The other is if someone is inserting
7058
    // into the dictionary directly and therefore causing it to resize.
7059
    //
7060
    // If we haven't materialized the dictionary yet we lock on the object, which
7061
    // will also be used to prevent the dictionary from being materialized while
7062
    // we're doing the insertion.  If we race and the dictionary gets created
7063
    // then we'll need to release the object lock and lock the dictionary to
7064
    // prevent resizing.
7065
    PyDictObject *dict = _PyObject_GetManagedDict(obj);
7066
    if (dict == NULL) {
7067
        int res;
7068
        Py_BEGIN_CRITICAL_SECTION(obj);
7069
        dict = _PyObject_GetManagedDict(obj);
7070
7071
        if (dict == NULL) {
7072
            res = store_instance_attr_lock_held(obj, values, name, value);
7073
        }
7074
        Py_END_CRITICAL_SECTION();
7075
7076
        if (dict == NULL) {
7077
            return res;
7078
        }
7079
    }
7080
    return store_instance_attr_dict(obj, dict, name, value);
7081
#else
7082
17.3M
    return store_instance_attr_lock_held(obj, values, name, value);
7083
17.7M
#endif
7084
17.7M
}
7085
7086
/* Sanity check for managed dicts */
7087
#if 0
7088
#define CHECK(val) assert(val); if (!(val)) { return 0; }
7089
7090
int
7091
_PyObject_ManagedDictValidityCheck(PyObject *obj)
7092
{
7093
    PyTypeObject *tp = Py_TYPE(obj);
7094
    CHECK(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
7095
    PyManagedDictPointer *managed_dict = _PyObject_ManagedDictPointer(obj);
7096
    if (_PyManagedDictPointer_IsValues(*managed_dict)) {
7097
        PyDictValues *values = _PyManagedDictPointer_GetValues(*managed_dict);
7098
        int size = ((uint8_t *)values)[-2];
7099
        int count = 0;
7100
        PyDictKeysObject *keys = CACHED_KEYS(tp);
7101
        for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
7102
            if (values->values[i] != NULL) {
7103
                count++;
7104
            }
7105
        }
7106
        CHECK(size == count);
7107
    }
7108
    else {
7109
        if (managed_dict->dict != NULL) {
7110
            CHECK(PyDict_Check(managed_dict->dict));
7111
        }
7112
    }
7113
    return 1;
7114
}
7115
#endif
7116
7117
// Attempts to get an instance attribute from the inline values. Returns true
7118
// if successful, or false if the caller needs to lookup in the dictionary.
7119
bool
7120
_PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr)
7121
49.2M
{
7122
49.2M
    assert(PyUnicode_CheckExact(name));
7123
49.2M
    PyDictValues *values = _PyObject_InlineValues(obj);
7124
49.2M
    if (!FT_ATOMIC_LOAD_UINT8(values->valid)) {
7125
4.91M
        return false;
7126
4.91M
    }
7127
7128
44.3M
    PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
7129
44.3M
    assert(keys != NULL);
7130
44.3M
    Py_ssize_t ix = _PyDictKeys_StringLookupSplit(keys, name);
7131
44.3M
    if (ix == DKIX_EMPTY) {
7132
18.1M
        *attr = NULL;
7133
18.1M
        return true;
7134
18.1M
    }
7135
7136
#ifdef Py_GIL_DISABLED
7137
    PyObject *value = _Py_atomic_load_ptr_acquire(&values->values[ix]);
7138
    if (value == NULL) {
7139
        if (FT_ATOMIC_LOAD_UINT8(values->valid)) {
7140
            *attr = NULL;
7141
            return true;
7142
        }
7143
    }
7144
    else if (_Py_TryIncrefCompare(&values->values[ix], value)) {
7145
        *attr = value;
7146
        return true;
7147
    }
7148
7149
    PyDictObject *dict = _PyObject_GetManagedDict(obj);
7150
    if (dict == NULL) {
7151
        // No dict, lock the object to prevent one from being
7152
        // materialized...
7153
        bool success = false;
7154
        Py_BEGIN_CRITICAL_SECTION(obj);
7155
7156
        dict = _PyObject_GetManagedDict(obj);
7157
        if (dict == NULL) {
7158
            // Still no dict, we can read from the values
7159
            assert(values->valid);
7160
            value = values->values[ix];
7161
            *attr = _Py_XNewRefWithLock(value);
7162
            success = true;
7163
        }
7164
7165
        Py_END_CRITICAL_SECTION();
7166
7167
        if (success) {
7168
            return true;
7169
        }
7170
    }
7171
7172
    // We have a dictionary, we'll need to lock it to prevent
7173
    // the values from being resized.
7174
    assert(dict != NULL);
7175
7176
    bool success;
7177
    Py_BEGIN_CRITICAL_SECTION(dict);
7178
7179
    if (dict->ma_values == values && FT_ATOMIC_LOAD_UINT8(values->valid)) {
7180
        value = _Py_atomic_load_ptr_relaxed(&values->values[ix]);
7181
        *attr = _Py_XNewRefWithLock(value);
7182
        success = true;
7183
    } else {
7184
        // Caller needs to lookup from the dictionary
7185
        success = false;
7186
    }
7187
7188
    Py_END_CRITICAL_SECTION();
7189
7190
    return success;
7191
#else
7192
26.2M
    PyObject *value = values->values[ix];
7193
26.2M
    *attr = Py_XNewRef(value);
7194
26.2M
    return true;
7195
44.3M
#endif
7196
44.3M
}
7197
7198
int
7199
_PyObject_IsInstanceDictEmpty(PyObject *obj)
7200
0
{
7201
0
    PyTypeObject *tp = Py_TYPE(obj);
7202
0
    if (tp->tp_dictoffset == 0) {
7203
0
        return 1;
7204
0
    }
7205
0
    PyDictObject *dict;
7206
0
    if (tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
7207
0
        PyDictValues *values = _PyObject_InlineValues(obj);
7208
0
        if (FT_ATOMIC_LOAD_UINT8(values->valid)) {
7209
0
            PyDictKeysObject *keys = CACHED_KEYS(tp);
7210
0
            for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
7211
0
                if (FT_ATOMIC_LOAD_PTR_RELAXED(values->values[i]) != NULL) {
7212
0
                    return 0;
7213
0
                }
7214
0
            }
7215
0
            return 1;
7216
0
        }
7217
0
        dict = _PyObject_GetManagedDict(obj);
7218
0
    }
7219
0
    else if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
7220
0
        dict = _PyObject_GetManagedDict(obj);
7221
0
    }
7222
0
    else {
7223
0
        PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
7224
0
        dict = (PyDictObject *)*dictptr;
7225
0
    }
7226
0
    if (dict == NULL) {
7227
0
        return 1;
7228
0
    }
7229
0
    return FT_ATOMIC_LOAD_SSIZE_RELAXED(((PyDictObject *)dict)->ma_used) == 0;
7230
0
}
7231
7232
int
7233
PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
7234
33.3M
{
7235
33.3M
    PyTypeObject *tp = Py_TYPE(obj);
7236
33.3M
    if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
7237
0
        return 0;
7238
0
    }
7239
33.3M
    if (tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
7240
31.7M
        PyDictValues *values = _PyObject_InlineValues(obj);
7241
31.7M
        if (values->valid) {
7242
249M
            for (Py_ssize_t i = 0; i < values->capacity; i++) {
7243
217M
                Py_VISIT(values->values[i]);
7244
217M
            }
7245
31.4M
            return 0;
7246
31.4M
        }
7247
31.7M
    }
7248
1.91M
    Py_VISIT(_PyObject_ManagedDictPointer(obj)->dict);
7249
1.91M
    return 0;
7250
1.91M
}
7251
7252
static void
7253
clear_inline_values(PyDictValues *values)
7254
27.1M
{
7255
27.1M
    if (values->valid) {
7256
27.1M
        FT_ATOMIC_STORE_UINT8(values->valid, 0);
7257
166M
        for (Py_ssize_t i = 0; i < values->capacity; i++) {
7258
139M
            Py_CLEAR(values->values[i]);
7259
139M
        }
7260
27.1M
    }
7261
27.1M
}
7262
7263
static void
7264
set_dict_inline_values(PyObject *obj, PyDictObject *new_dict)
7265
0
{
7266
0
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(obj);
7267
7268
0
    PyDictValues *values = _PyObject_InlineValues(obj);
7269
7270
0
    Py_XINCREF(new_dict);
7271
0
    FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict, new_dict);
7272
7273
0
    clear_inline_values(values);
7274
0
}
7275
7276
#ifdef Py_GIL_DISABLED
7277
7278
// Trys and sets the dictionary for an object in the easy case when our current
7279
// dictionary is either completely not materialized or is a dictionary which
7280
// does not point at the inline values.
7281
static bool
7282
try_set_dict_inline_only_or_other_dict(PyObject *obj, PyObject *new_dict, PyDictObject **cur_dict)
7283
{
7284
    bool replaced = false;
7285
    Py_BEGIN_CRITICAL_SECTION(obj);
7286
7287
    PyDictObject *dict = *cur_dict = _PyObject_GetManagedDict(obj);
7288
    if (dict == NULL) {
7289
        // We only have inline values, we can just completely replace them.
7290
        set_dict_inline_values(obj, (PyDictObject *)new_dict);
7291
        replaced = true;
7292
        goto exit_lock;
7293
    }
7294
7295
    if (FT_ATOMIC_LOAD_PTR_RELAXED(dict->ma_values) != _PyObject_InlineValues(obj)) {
7296
        // We have a materialized dict which doesn't point at the inline values,
7297
        // We get to simply swap dictionaries and free the old dictionary.
7298
        FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict,
7299
                            (PyDictObject *)Py_XNewRef(new_dict));
7300
        replaced = true;
7301
        goto exit_lock;
7302
    }
7303
    else {
7304
        // We have inline values, we need to lock the dict and the object
7305
        // at the same time to safely dematerialize them. To do that while releasing
7306
        // the object lock we need a strong reference to the current dictionary.
7307
        Py_INCREF(dict);
7308
    }
7309
exit_lock:
7310
    Py_END_CRITICAL_SECTION();
7311
    return replaced;
7312
}
7313
7314
// Replaces a dictionary that is probably the dictionary which has been
7315
// materialized and points at the inline values. We could have raced
7316
// and replaced it with another dictionary though.
7317
static int
7318
replace_dict_probably_inline_materialized(PyObject *obj, PyDictObject *inline_dict,
7319
                                          PyDictObject *cur_dict, PyObject *new_dict)
7320
{
7321
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(obj);
7322
7323
    if (cur_dict == inline_dict) {
7324
        assert(FT_ATOMIC_LOAD_PTR_RELAXED(inline_dict->ma_values) == _PyObject_InlineValues(obj));
7325
7326
        int err = _PyDict_DetachFromObject(inline_dict, obj);
7327
        if (err != 0) {
7328
            assert(new_dict == NULL);
7329
            return err;
7330
        }
7331
    }
7332
7333
    FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict,
7334
                        (PyDictObject *)Py_XNewRef(new_dict));
7335
    return 0;
7336
}
7337
7338
#endif
7339
7340
static void
7341
decref_maybe_delay(PyObject *obj, bool delay)
7342
0
{
7343
0
    if (delay) {
7344
0
        _PyObject_XDecRefDelayed(obj);
7345
0
    }
7346
0
    else {
7347
0
        Py_XDECREF(obj);
7348
0
    }
7349
0
}
7350
7351
int
7352
_PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
7353
0
{
7354
0
    assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
7355
#ifndef NDEBUG
7356
    Py_BEGIN_CRITICAL_SECTION(obj);
7357
    assert(_PyObject_InlineValuesConsistencyCheck(obj));
7358
    Py_END_CRITICAL_SECTION();
7359
#endif
7360
0
    int err = 0;
7361
0
    PyTypeObject *tp = Py_TYPE(obj);
7362
0
    if (tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
7363
#ifdef Py_GIL_DISABLED
7364
        PyDictObject *prev_dict;
7365
        if (!try_set_dict_inline_only_or_other_dict(obj, new_dict, &prev_dict)) {
7366
            // We had a materialized dictionary which pointed at the inline
7367
            // values. We need to lock both the object and the dict at the
7368
            // same time to safely replace it. We can't merely lock the dictionary
7369
            // while the object is locked because it could suspend the object lock.
7370
            PyDictObject *cur_dict;
7371
7372
            assert(prev_dict != NULL);
7373
            Py_BEGIN_CRITICAL_SECTION2(obj, prev_dict);
7374
7375
            // We could have had another thread race in between the call to
7376
            // try_set_dict_inline_only_or_other_dict where we locked the object
7377
            // and when we unlocked and re-locked the dictionary.
7378
            cur_dict = _PyObject_GetManagedDict(obj);
7379
7380
            err = replace_dict_probably_inline_materialized(obj, prev_dict,
7381
                                                            cur_dict, new_dict);
7382
7383
            Py_END_CRITICAL_SECTION2();
7384
7385
            // Decref for the dictionary we incref'd in try_set_dict_inline_only_or_other_dict
7386
            // while the object was locked
7387
            decref_maybe_delay((PyObject *)prev_dict, prev_dict != cur_dict);
7388
            if (err != 0) {
7389
                return err;
7390
            }
7391
7392
            prev_dict = cur_dict;
7393
        }
7394
7395
        if (prev_dict != NULL) {
7396
            // decref for the dictionary that we replaced
7397
            decref_maybe_delay((PyObject *)prev_dict, true);
7398
        }
7399
7400
        return 0;
7401
#else
7402
0
        PyDictObject *dict = _PyObject_GetManagedDict(obj);
7403
0
        if (dict == NULL) {
7404
0
            set_dict_inline_values(obj, (PyDictObject *)new_dict);
7405
0
            return 0;
7406
0
        }
7407
0
        if (_PyDict_DetachFromObject(dict, obj) == 0) {
7408
0
            _PyObject_ManagedDictPointer(obj)->dict = (PyDictObject *)Py_XNewRef(new_dict);
7409
0
            Py_DECREF(dict);
7410
0
            return 0;
7411
0
        }
7412
0
        assert(new_dict == NULL);
7413
0
        return -1;
7414
0
#endif
7415
0
    }
7416
0
    else {
7417
0
        PyDictObject *dict;
7418
7419
0
        Py_BEGIN_CRITICAL_SECTION(obj);
7420
7421
0
        dict = _PyObject_ManagedDictPointer(obj)->dict;
7422
7423
0
        FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict,
7424
0
                            (PyDictObject *)Py_XNewRef(new_dict));
7425
7426
0
        Py_END_CRITICAL_SECTION();
7427
0
        decref_maybe_delay((PyObject *)dict, true);
7428
0
    }
7429
0
    assert(_PyObject_InlineValuesConsistencyCheck(obj));
7430
0
    return err;
7431
0
}
7432
7433
static int
7434
detach_dict_from_object(PyDictObject *mp, PyObject *obj)
7435
0
{
7436
0
    assert(_PyObject_ManagedDictPointer(obj)->dict == mp);
7437
0
    assert(_PyObject_InlineValuesConsistencyCheck(obj));
7438
7439
0
    if (FT_ATOMIC_LOAD_PTR_RELAXED(mp->ma_values) != _PyObject_InlineValues(obj)) {
7440
0
        return 0;
7441
0
    }
7442
7443
    // We could be called with an unlocked dict when the caller knows the
7444
    // values are already detached, so we assert after inline values check.
7445
0
    ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(mp);
7446
0
    assert(mp->ma_values->embedded == 1);
7447
0
    assert(mp->ma_values->valid == 1);
7448
0
    assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_INLINE_VALUES);
7449
7450
0
    PyDictValues *values = copy_values(mp->ma_values);
7451
7452
0
    if (values == NULL) {
7453
0
        PyErr_NoMemory();
7454
0
        return -1;
7455
0
    }
7456
0
    mp->ma_values = values;
7457
7458
0
    invalidate_and_clear_inline_values(_PyObject_InlineValues(obj));
7459
7460
0
    assert(_PyObject_InlineValuesConsistencyCheck(obj));
7461
0
    ASSERT_CONSISTENT(mp);
7462
0
    return 0;
7463
0
}
7464
7465
7466
void
7467
PyObject_ClearManagedDict(PyObject *obj)
7468
27.8M
{
7469
    // This is called when the object is being freed or cleared
7470
    // by the GC and therefore known to have no references.
7471
27.8M
    if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
7472
27.8M
        PyDictObject *dict = _PyObject_GetManagedDict(obj);
7473
27.8M
        if (dict == NULL) {
7474
            // We have no materialized dictionary and inline values
7475
            // that just need to be cleared.
7476
            // No dict to clear, we're done
7477
27.1M
            clear_inline_values(_PyObject_InlineValues(obj));
7478
27.1M
            return;
7479
27.1M
        }
7480
694k
        else if (FT_ATOMIC_LOAD_PTR_RELAXED(dict->ma_values) ==
7481
694k
                    _PyObject_InlineValues(obj)) {
7482
            // We have a materialized object which points at the inline
7483
            // values. We need to materialize the keys. Nothing can modify
7484
            // this object, but we need to lock the dictionary.
7485
0
            int err;
7486
0
            Py_BEGIN_CRITICAL_SECTION(dict);
7487
0
            err = detach_dict_from_object(dict, obj);
7488
0
            Py_END_CRITICAL_SECTION();
7489
7490
0
            if (err) {
7491
                /* Must be out of memory */
7492
0
                assert(PyErr_Occurred() == PyExc_MemoryError);
7493
0
                PyErr_FormatUnraisable("Exception ignored while "
7494
0
                                       "clearing an object managed dict");
7495
                /* Clear the dict */
7496
0
                Py_BEGIN_CRITICAL_SECTION(dict);
7497
0
                PyDictKeysObject *oldkeys = dict->ma_keys;
7498
0
                set_keys(dict, Py_EMPTY_KEYS);
7499
0
                dict->ma_values = NULL;
7500
0
                dictkeys_decref(oldkeys, IS_DICT_SHARED(dict));
7501
0
                STORE_USED(dict, 0);
7502
0
                clear_inline_values(_PyObject_InlineValues(obj));
7503
0
                Py_END_CRITICAL_SECTION();
7504
0
            }
7505
0
        }
7506
27.8M
    }
7507
694k
    Py_CLEAR(_PyObject_ManagedDictPointer(obj)->dict);
7508
694k
}
7509
7510
int
7511
_PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
7512
0
{
7513
0
    ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(obj);
7514
7515
0
    return detach_dict_from_object(mp, obj);
7516
0
}
7517
7518
static inline PyObject *
7519
ensure_managed_dict(PyObject *obj)
7520
8
{
7521
8
    PyDictObject *dict = _PyObject_GetManagedDict(obj);
7522
8
    if (dict == NULL) {
7523
4
        PyTypeObject *tp = Py_TYPE(obj);
7524
4
        if ((tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) &&
7525
4
            FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(obj)->valid)) {
7526
4
            dict = _PyObject_MaterializeManagedDict(obj);
7527
4
        }
7528
0
        else {
7529
#ifdef Py_GIL_DISABLED
7530
            // Check again that we're not racing with someone else creating the dict
7531
            Py_BEGIN_CRITICAL_SECTION(obj);
7532
            dict = _PyObject_GetManagedDict(obj);
7533
            if (dict != NULL) {
7534
                goto done;
7535
            }
7536
#endif
7537
0
            dict = (PyDictObject *)new_dict_with_shared_keys(CACHED_KEYS(tp));
7538
0
            FT_ATOMIC_STORE_PTR_RELEASE(_PyObject_ManagedDictPointer(obj)->dict,
7539
0
                                        (PyDictObject *)dict);
7540
7541
#ifdef Py_GIL_DISABLED
7542
done:
7543
            Py_END_CRITICAL_SECTION();
7544
#endif
7545
0
        }
7546
4
    }
7547
8
    return (PyObject *)dict;
7548
8
}
7549
7550
static inline PyObject *
7551
ensure_nonmanaged_dict(PyObject *obj, PyObject **dictptr)
7552
12.9M
{
7553
12.9M
    PyDictKeysObject *cached;
7554
7555
12.9M
    PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*dictptr);
7556
12.9M
    if (dict == NULL) {
7557
#ifdef Py_GIL_DISABLED
7558
        Py_BEGIN_CRITICAL_SECTION(obj);
7559
        dict = *dictptr;
7560
        if (dict != NULL) {
7561
            goto done;
7562
        }
7563
#endif
7564
9.16M
        PyTypeObject *tp = Py_TYPE(obj);
7565
9.16M
        if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && (cached = CACHED_KEYS(tp))) {
7566
2.71k
            assert(!_PyType_HasFeature(tp, Py_TPFLAGS_INLINE_VALUES));
7567
2.71k
            dict = new_dict_with_shared_keys(cached);
7568
2.71k
        }
7569
9.16M
        else {
7570
9.16M
            dict = PyDict_New();
7571
9.16M
        }
7572
9.16M
        FT_ATOMIC_STORE_PTR_RELEASE(*dictptr, dict);
7573
#ifdef Py_GIL_DISABLED
7574
done:
7575
        Py_END_CRITICAL_SECTION();
7576
#endif
7577
9.16M
    }
7578
12.9M
    return dict;
7579
12.9M
}
7580
7581
PyObject *
7582
PyObject_GenericGetDict(PyObject *obj, void *context)
7583
470
{
7584
470
    PyTypeObject *tp = Py_TYPE(obj);
7585
470
    if (_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT)) {
7586
8
        return Py_XNewRef(ensure_managed_dict(obj));
7587
8
    }
7588
462
    else {
7589
462
        PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
7590
462
        if (dictptr == NULL) {
7591
0
            PyErr_SetString(PyExc_AttributeError,
7592
0
                            "This object has no __dict__");
7593
0
            return NULL;
7594
0
        }
7595
7596
462
        return Py_XNewRef(ensure_nonmanaged_dict(obj, dictptr));
7597
462
    }
7598
470
}
7599
7600
int
7601
_PyObjectDict_SetItem(PyTypeObject *tp, PyObject *obj, PyObject **dictptr,
7602
                      PyObject *key, PyObject *value)
7603
12.9M
{
7604
12.9M
    PyObject *dict;
7605
12.9M
    int res;
7606
7607
12.9M
    assert(dictptr != NULL);
7608
12.9M
    dict = ensure_nonmanaged_dict(obj, dictptr);
7609
12.9M
    if (dict == NULL) {
7610
0
        return -1;
7611
0
    }
7612
7613
12.9M
    Py_BEGIN_CRITICAL_SECTION(dict);
7614
12.9M
    res = _PyDict_SetItem_LockHeld((PyDictObject *)dict, key, value);
7615
12.9M
    ASSERT_CONSISTENT(dict);
7616
12.9M
    Py_END_CRITICAL_SECTION();
7617
12.9M
    return res;
7618
12.9M
}
7619
7620
void
7621
_PyDictKeys_DecRef(PyDictKeysObject *keys)
7622
295k
{
7623
295k
    dictkeys_decref(keys, false);
7624
295k
}
7625
7626
static inline uint32_t
7627
get_next_dict_keys_version(PyInterpreterState *interp)
7628
12.7k
{
7629
#ifdef Py_GIL_DISABLED
7630
    uint32_t v;
7631
    do {
7632
        v = _Py_atomic_load_uint32_relaxed(
7633
            &interp->dict_state.next_keys_version);
7634
        if (v == 0) {
7635
            return 0;
7636
        }
7637
    } while (!_Py_atomic_compare_exchange_uint32(
7638
        &interp->dict_state.next_keys_version, &v, v + 1));
7639
#else
7640
12.7k
    if (interp->dict_state.next_keys_version == 0) {
7641
0
        return 0;
7642
0
    }
7643
12.7k
    uint32_t v = interp->dict_state.next_keys_version++;
7644
12.7k
#endif
7645
12.7k
    return v;
7646
12.7k
}
7647
7648
// In free-threaded builds the caller must ensure that the keys object is not
7649
// being mutated concurrently by another thread.
7650
uint32_t
7651
_PyDictKeys_GetVersionForCurrentState(PyInterpreterState *interp,
7652
                                      PyDictKeysObject *dictkeys)
7653
608k
{
7654
608k
    uint32_t dk_version = FT_ATOMIC_LOAD_UINT32_RELAXED(dictkeys->dk_version);
7655
608k
    if (dk_version != 0) {
7656
596k
        return dk_version;
7657
596k
    }
7658
12.7k
    dk_version = get_next_dict_keys_version(interp);
7659
12.7k
    FT_ATOMIC_STORE_UINT32_RELAXED(dictkeys->dk_version, dk_version);
7660
12.7k
    return dk_version;
7661
608k
}
7662
7663
uint32_t
7664
_PyDict_GetKeysVersionForCurrentState(PyInterpreterState *interp,
7665
                                      PyDictObject *dict)
7666
21.1k
{
7667
21.1k
    ASSERT_DICT_LOCKED((PyObject *) dict);
7668
21.1k
    uint32_t dk_version =
7669
21.1k
        _PyDictKeys_GetVersionForCurrentState(interp, dict->ma_keys);
7670
21.1k
    ensure_shared_on_keys_version_assignment(dict);
7671
21.1k
    return dk_version;
7672
21.1k
}
7673
7674
static inline int
7675
validate_watcher_id(PyInterpreterState *interp, int watcher_id)
7676
16
{
7677
16
    if (watcher_id < 0 || watcher_id >= DICT_MAX_WATCHERS) {
7678
0
        PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id);
7679
0
        return -1;
7680
0
    }
7681
16
    if (!interp->dict_state.watchers[watcher_id]) {
7682
0
        PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id);
7683
0
        return -1;
7684
0
    }
7685
16
    return 0;
7686
16
}
7687
7688
int
7689
PyDict_Watch(int watcher_id, PyObject* dict)
7690
16
{
7691
16
    if (!PyDict_Check(dict)) {
7692
0
        PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary");
7693
0
        return -1;
7694
0
    }
7695
16
    PyInterpreterState *interp = _PyInterpreterState_GET();
7696
16
    if (validate_watcher_id(interp, watcher_id)) {
7697
0
        return -1;
7698
0
    }
7699
16
    ((PyDictObject*)dict)->_ma_watcher_tag |= (1LL << watcher_id);
7700
16
    return 0;
7701
16
}
7702
7703
int
7704
PyDict_Unwatch(int watcher_id, PyObject* dict)
7705
0
{
7706
0
    if (!PyDict_Check(dict)) {
7707
0
        PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary");
7708
0
        return -1;
7709
0
    }
7710
0
    PyInterpreterState *interp = _PyInterpreterState_GET();
7711
0
    if (validate_watcher_id(interp, watcher_id)) {
7712
0
        return -1;
7713
0
    }
7714
0
    ((PyDictObject*)dict)->_ma_watcher_tag &= ~(1LL << watcher_id);
7715
0
    return 0;
7716
0
}
7717
7718
int
7719
PyDict_AddWatcher(PyDict_WatchCallback callback)
7720
0
{
7721
0
    PyInterpreterState *interp = _PyInterpreterState_GET();
7722
7723
    /* Start at 2, as 0 and 1 are reserved for CPython */
7724
0
    for (int i = 2; i < DICT_MAX_WATCHERS; i++) {
7725
0
        if (!interp->dict_state.watchers[i]) {
7726
0
            interp->dict_state.watchers[i] = callback;
7727
0
            return i;
7728
0
        }
7729
0
    }
7730
7731
0
    PyErr_SetString(PyExc_RuntimeError, "no more dict watcher IDs available");
7732
0
    return -1;
7733
0
}
7734
7735
int
7736
PyDict_ClearWatcher(int watcher_id)
7737
0
{
7738
0
    PyInterpreterState *interp = _PyInterpreterState_GET();
7739
0
    if (validate_watcher_id(interp, watcher_id)) {
7740
0
        return -1;
7741
0
    }
7742
0
    interp->dict_state.watchers[watcher_id] = NULL;
7743
0
    return 0;
7744
0
}
7745
7746
static const char *
7747
0
dict_event_name(PyDict_WatchEvent event) {
7748
0
    switch (event) {
7749
0
        #define CASE(op)                \
7750
0
        case PyDict_EVENT_##op:         \
7751
0
            return "PyDict_EVENT_" #op;
7752
0
        PY_FOREACH_DICT_EVENT(CASE)
7753
0
        #undef CASE
7754
0
    }
7755
0
    Py_UNREACHABLE();
7756
0
}
7757
7758
void
7759
_PyDict_SendEvent(int watcher_bits,
7760
                  PyDict_WatchEvent event,
7761
                  PyDictObject *mp,
7762
                  PyObject *key,
7763
                  PyObject *value)
7764
0
{
7765
0
    PyInterpreterState *interp = _PyInterpreterState_GET();
7766
0
    for (int i = 0; i < DICT_MAX_WATCHERS; i++) {
7767
0
        if (watcher_bits & 1) {
7768
0
            PyDict_WatchCallback cb = interp->dict_state.watchers[i];
7769
0
            if (cb && (cb(event, (PyObject*)mp, key, value) < 0)) {
7770
                // We don't want to resurrect the dict by potentially having an
7771
                // unraisablehook keep a reference to it, so we don't pass the
7772
                // dict as context, just an informative string message.  Dict
7773
                // repr can call arbitrary code, so we invent a simpler version.
7774
0
                PyErr_FormatUnraisable(
7775
0
                    "Exception ignored in %s watcher callback for <dict at %p>",
7776
0
                    dict_event_name(event), mp);
7777
0
            }
7778
0
        }
7779
0
        watcher_bits >>= 1;
7780
0
    }
7781
0
}
7782
7783
#ifndef NDEBUG
7784
static int
7785
_PyObject_InlineValuesConsistencyCheck(PyObject *obj)
7786
{
7787
    if ((Py_TYPE(obj)->tp_flags & Py_TPFLAGS_INLINE_VALUES) == 0) {
7788
        return 1;
7789
    }
7790
    assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
7791
    PyDictObject *dict = _PyObject_GetManagedDict(obj);
7792
    if (dict == NULL) {
7793
        return 1;
7794
    }
7795
    if (dict->ma_values == _PyObject_InlineValues(obj) ||
7796
        _PyObject_InlineValues(obj)->valid == 0) {
7797
        return 1;
7798
    }
7799
    assert(0);
7800
    return 0;
7801
}
7802
#endif