Coverage Report

Created: 2025-07-11 06:24

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