Coverage Report

Created: 2026-06-09 06:53

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