Coverage Report

Created: 2025-11-02 06:30

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