Coverage Report

Created: 2026-03-23 06:45

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