Coverage Report

Created: 2025-07-04 06:49

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