Coverage Report

Created: 2025-11-09 06:26

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