Coverage Report

Created: 2026-03-08 06:40

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