Coverage Report

Created: 2026-01-17 06:16

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