Coverage Report

Created: 2026-01-13 06:09

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