Coverage Report

Created: 2025-07-18 06:09

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