Coverage Report

Created: 2026-01-10 06:41

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