Coverage Report

Created: 2026-02-09 07:07

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