Coverage Report

Created: 2026-02-26 06:25

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