#define PyDict_LOG_MINSIZE …
#define PyDict_MINSIZE …
#include "Python.h"
#include "pycore_bitutils.h"
#include "pycore_call.h"
#include "pycore_ceval.h"
#include "pycore_code.h"
#include "pycore_critical_section.h"
#include "pycore_dict.h"
#include "pycore_freelist.h"
#include "pycore_gc.h"
#include "pycore_object.h"
#include "pycore_pyatomic_ft_wrappers.h"
#include "pycore_pyerrors.h"
#include "pycore_pystate.h"
#include "pycore_setobject.h"
#include "stringlib/eq.h"
#include <stdbool.h>
#ifdef Py_GIL_DISABLED
static inline void
ASSERT_DICT_LOCKED(PyObject *op)
{
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
}
#define ASSERT_DICT_LOCKED …
#define ASSERT_WORLD_STOPPED_OR_DICT_LOCKED …
#define ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED …
#define IS_DICT_SHARED …
#define SET_DICT_SHARED …
#define LOAD_INDEX …
#define STORE_INDEX …
#define ASSERT_OWNED_OR_SHARED …
#define LOCK_KEYS_IF_SPLIT …
#define UNLOCK_KEYS_IF_SPLIT …
static inline Py_ssize_t
load_keys_nentries(PyDictObject *mp)
{
PyDictKeysObject *keys = _Py_atomic_load_ptr(&mp->ma_keys);
return _Py_atomic_load_ssize(&keys->dk_nentries);
}
static inline void
set_keys(PyDictObject *mp, PyDictKeysObject *keys)
{
ASSERT_OWNED_OR_SHARED(mp);
_Py_atomic_store_ptr_release(&mp->ma_keys, keys);
}
static inline void
set_values(PyDictObject *mp, PyDictValues *values)
{
ASSERT_OWNED_OR_SHARED(mp);
_Py_atomic_store_ptr_release(&mp->ma_values, values);
}
#define LOCK_KEYS …
#define UNLOCK_KEYS …
#define ASSERT_KEYS_LOCKED …
#define LOAD_SHARED_KEY …
#define STORE_SHARED_KEY …
#define INCREF_KEYS …
#define DECREF_KEYS …
#define LOAD_KEYS_NENTRIES …
#define INCREF_KEYS_FT …
#define DECREF_KEYS_FT …
static inline void split_keys_entry_added(PyDictKeysObject *keys)
{
ASSERT_KEYS_LOCKED(keys);
_Py_atomic_store_ssize_relaxed(&keys->dk_nentries, keys->dk_nentries + 1);
_Py_atomic_store_ssize_release(&keys->dk_usable, keys->dk_usable - 1);
}
#else
#define ASSERT_DICT_LOCKED(op) …
#define ASSERT_WORLD_STOPPED_OR_DICT_LOCKED(op) …
#define ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(op) …
#define LOCK_KEYS(keys) …
#define UNLOCK_KEYS(keys) …
#define ASSERT_KEYS_LOCKED(keys) …
#define LOAD_SHARED_KEY(key) …
#define STORE_SHARED_KEY(key, value) …
#define INCREF_KEYS(dk) …
#define DECREF_KEYS(dk) …
#define LOAD_KEYS_NENTRIES(keys) …
#define INCREF_KEYS_FT(dk) …
#define DECREF_KEYS_FT(dk, shared) …
#define LOCK_KEYS_IF_SPLIT(keys, kind) …
#define UNLOCK_KEYS_IF_SPLIT(keys, kind) …
#define IS_DICT_SHARED(mp) …
#define SET_DICT_SHARED(mp) …
#define LOAD_INDEX(keys, size, idx) …
#define STORE_INDEX(keys, size, idx, value) …
static inline void split_keys_entry_added(PyDictKeysObject *keys)
{ … }
static inline void
set_keys(PyDictObject *mp, PyDictKeysObject *keys)
{ … }
static inline void
set_values(PyDictObject *mp, PyDictValues *values)
{ … }
static inline Py_ssize_t
load_keys_nentries(PyDictObject *mp)
{ … }
#endif
#define STORE_KEY(ep, key) …
#define STORE_VALUE(ep, value) …
#define STORE_SPLIT_VALUE(mp, idx, value) …
#define STORE_HASH(ep, hash) …
#define STORE_KEYS_USABLE(keys, usable) …
#define STORE_KEYS_NENTRIES(keys, nentries) …
#define STORE_USED(mp, used) …
#define PERTURB_SHIFT …
static int dictresize(PyInterpreterState *interp, PyDictObject *mp,
uint8_t log_newsize, int unicode);
static PyObject* dict_iter(PyObject *dict);
static int
setitem_lock_held(PyDictObject *mp, PyObject *key, PyObject *value);
static int
dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_value,
PyObject **result, int incref_result);
#ifndef NDEBUG
static int _PyObject_InlineValuesConsistencyCheck(PyObject *obj);
#endif
#include "clinic/dictobject.c.h"
static inline Py_hash_t
unicode_get_hash(PyObject *o)
{ … }
void
_PyDict_DebugMallocStats(FILE *out)
{ … }
#define DK_MASK(dk) …
#define _Py_DICT_IMMORTAL_INITIAL_REFCNT …
static void free_keys_object(PyDictKeysObject *keys, bool use_qsbr);
static inline void
dictkeys_incref(PyDictKeysObject *dk)
{ … }
static inline void
dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk, bool use_qsbr)
{ … }
static inline Py_ssize_t
dictkeys_get_index(const PyDictKeysObject *keys, Py_ssize_t i)
{ … }
static inline void
dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix)
{ … }
#define USABLE_FRACTION(n) …
static inline uint8_t
calculate_log2_keysize(Py_ssize_t minsize)
{ … }
static inline uint8_t
estimate_log2_keysize(Py_ssize_t n)
{ … }
#define GROWTH_RATE(d) …
static PyDictKeysObject empty_keys_struct = …;
#define Py_EMPTY_KEYS …
#ifdef DEBUG_PYDICT
#define ASSERT_CONSISTENT …
#else
#define ASSERT_CONSISTENT(op) …
#endif
static inline int
get_index_from_order(PyDictObject *mp, Py_ssize_t i)
{ … }
#ifdef DEBUG_PYDICT
static void
dump_entries(PyDictKeysObject *dk)
{
for (Py_ssize_t i = 0; i < dk->dk_nentries; i++) {
if (DK_IS_UNICODE(dk)) {
PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(dk)[i];
printf("key=%p value=%p\n", ep->me_key, ep->me_value);
}
else {
PyDictKeyEntry *ep = &DK_ENTRIES(dk)[i];
printf("key=%p hash=%lx value=%p\n", ep->me_key, ep->me_hash, ep->me_value);
}
}
}
#endif
int
_PyDict_CheckConsistency(PyObject *op, int check_content)
{ … }
static PyDictKeysObject*
new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode)
{ … }
static void
free_keys_object(PyDictKeysObject *keys, bool use_qsbr)
{ … }
static size_t
values_size_from_count(size_t count)
{ … }
#define CACHED_KEYS(tp) …
static inline PyDictValues*
new_values(size_t size)
{ … }
static inline void
free_values(PyDictValues *values, bool use_qsbr)
{ … }
static PyObject *
new_dict(PyInterpreterState *interp,
PyDictKeysObject *keys, PyDictValues *values,
Py_ssize_t used, int free_values_on_failure)
{ … }
static PyObject *
new_dict_with_shared_keys(PyInterpreterState *interp, PyDictKeysObject *keys)
{ … }
static PyDictKeysObject *
clone_combined_dict_keys(PyDictObject *orig)
{ … }
PyObject *
PyDict_New(void)
{ … }
static Py_ssize_t
lookdict_index(PyDictKeysObject *k, Py_hash_t hash, Py_ssize_t index)
{ … }
static inline Py_ALWAYS_INLINE Py_ssize_t
do_lookup(PyDictObject *mp, PyDictKeysObject *dk, PyObject *key, Py_hash_t hash,
int (*check_lookup)(PyDictObject *, PyDictKeysObject *, void *, Py_ssize_t ix, PyObject *key, Py_hash_t))
{ … }
static inline int
compare_unicode_generic(PyDictObject *mp, PyDictKeysObject *dk,
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
{ … }
static Py_ssize_t
unicodekeys_lookup_generic(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
{ … }
static inline int
compare_unicode_unicode(PyDictObject *mp, PyDictKeysObject *dk,
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
{ … }
static Py_ssize_t _Py_HOT_FUNCTION
unicodekeys_lookup_unicode(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
{ … }
static inline int
compare_generic(PyDictObject *mp, PyDictKeysObject *dk,
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
{ … }
static Py_ssize_t
dictkeys_generic_lookup(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
{ … }
Py_ssize_t
_PyDictKeys_StringLookup(PyDictKeysObject* dk, PyObject *key)
{ … }
#ifdef Py_GIL_DISABLED
static Py_ssize_t
unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject* dk, PyObject *key,
Py_hash_t hash);
#endif
Py_ssize_t
_Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr)
{ … }
#ifdef Py_GIL_DISABLED
static inline void
ensure_shared_on_read(PyDictObject *mp)
{
if (!_Py_IsOwnedByCurrentThread((PyObject *)mp) && !IS_DICT_SHARED(mp)) {
Py_BEGIN_CRITICAL_SECTION(mp);
if (!IS_DICT_SHARED(mp)) {
SET_DICT_SHARED(mp);
}
Py_END_CRITICAL_SECTION();
}
}
#endif
static inline void
ensure_shared_on_resize(PyDictObject *mp)
{ … }
static inline void
ensure_shared_on_keys_version_assignment(PyDictObject *mp)
{ … }
#ifdef Py_GIL_DISABLED
static inline Py_ALWAYS_INLINE int
compare_unicode_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
{
PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
assert(startkey == NULL || PyUnicode_CheckExact(ep->me_key));
assert(!PyUnicode_CheckExact(key));
if (startkey != NULL) {
if (!_Py_TryIncrefCompare(&ep->me_key, startkey)) {
return DKIX_KEY_CHANGED;
}
if (unicode_get_hash(startkey) == hash) {
int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
Py_DECREF(startkey);
if (cmp < 0) {
return DKIX_ERROR;
}
if (dk == _Py_atomic_load_ptr_relaxed(&mp->ma_keys) &&
startkey == _Py_atomic_load_ptr_relaxed(&ep->me_key)) {
return cmp;
}
else {
return DKIX_KEY_CHANGED;
}
}
else {
Py_DECREF(startkey);
}
}
return 0;
}
static Py_ssize_t
unicodekeys_lookup_generic_threadsafe(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
{
return do_lookup(mp, dk, key, hash, compare_unicode_generic_threadsafe);
}
static inline Py_ALWAYS_INLINE int
compare_unicode_unicode_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
{
PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
assert(startkey == NULL || PyUnicode_CheckExact(startkey));
if (startkey == key) {
return 1;
}
if (startkey != NULL) {
if (_Py_IsImmortal(startkey)) {
return unicode_get_hash(startkey) == hash && unicode_eq(startkey, key);
}
else {
if (!_Py_TryIncrefCompare(&ep->me_key, startkey)) {
return DKIX_KEY_CHANGED;
}
if (unicode_get_hash(startkey) == hash && unicode_eq(startkey, key)) {
Py_DECREF(startkey);
return 1;
}
Py_DECREF(startkey);
}
}
return 0;
}
static Py_ssize_t _Py_HOT_FUNCTION
unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
{
return do_lookup(NULL, dk, key, hash, compare_unicode_unicode_threadsafe);
}
static inline Py_ALWAYS_INLINE int
compare_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
{
PyDictKeyEntry *ep = &((PyDictKeyEntry *)ep0)[ix];
PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
if (startkey == key) {
return 1;
}
Py_ssize_t ep_hash = _Py_atomic_load_ssize_relaxed(&ep->me_hash);
if (ep_hash == hash) {
if (startkey == NULL || !_Py_TryIncrefCompare(&ep->me_key, startkey)) {
return DKIX_KEY_CHANGED;
}
int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
Py_DECREF(startkey);
if (cmp < 0) {
return DKIX_ERROR;
}
if (dk == _Py_atomic_load_ptr_relaxed(&mp->ma_keys) &&
startkey == _Py_atomic_load_ptr_relaxed(&ep->me_key)) {
return cmp;
}
else {
return DKIX_KEY_CHANGED;
}
}
return 0;
}
static Py_ssize_t
dictkeys_generic_lookup_threadsafe(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
{
return do_lookup(mp, dk, key, hash, compare_generic_threadsafe);
}
Py_ssize_t
_Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr)
{
PyDictKeysObject *dk;
DictKeysKind kind;
Py_ssize_t ix;
PyObject *value;
ensure_shared_on_read(mp);
dk = _Py_atomic_load_ptr(&mp->ma_keys);
kind = dk->dk_kind;
if (kind != DICT_KEYS_GENERAL) {
if (PyUnicode_CheckExact(key)) {
ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash);
}
else {
ix = unicodekeys_lookup_generic_threadsafe(mp, dk, key, hash);
}
if (ix == DKIX_KEY_CHANGED) {
goto read_failed;
}
if (ix >= 0) {
if (kind == DICT_KEYS_SPLIT) {
PyDictValues *values = _Py_atomic_load_ptr(&mp->ma_values);
if (values == NULL)
goto read_failed;
uint8_t capacity = _Py_atomic_load_uint8_relaxed(&values->capacity);
if (ix >= (Py_ssize_t)capacity)
goto read_failed;
value = _Py_TryXGetRef(&values->values[ix]);
if (value == NULL)
goto read_failed;
if (values != _Py_atomic_load_ptr(&mp->ma_values)) {
Py_DECREF(value);
goto read_failed;
}
}
else {
value = _Py_TryXGetRef(&DK_UNICODE_ENTRIES(dk)[ix].me_value);
if (value == NULL) {
goto read_failed;
}
if (dk != _Py_atomic_load_ptr(&mp->ma_keys)) {
Py_DECREF(value);
goto read_failed;
}
}
}
else {
value = NULL;
}
}
else {
ix = dictkeys_generic_lookup_threadsafe(mp, dk, key, hash);
if (ix == DKIX_KEY_CHANGED) {
goto read_failed;
}
if (ix >= 0) {
value = _Py_TryXGetRef(&DK_ENTRIES(dk)[ix].me_value);
if (value == NULL)
goto read_failed;
if (dk != _Py_atomic_load_ptr(&mp->ma_keys)) {
Py_DECREF(value);
goto read_failed;
}
}
else {
value = NULL;
}
}
*value_addr = value;
return ix;
read_failed:
Py_BEGIN_CRITICAL_SECTION(mp);
ix = _Py_dict_lookup(mp, key, hash, &value);
*value_addr = value;
if (value != NULL) {
assert(ix >= 0);
_Py_NewRefWithLock(value);
}
Py_END_CRITICAL_SECTION();
return ix;
}
Py_ssize_t
_Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr)
{
PyDictKeysObject *dk = _Py_atomic_load_ptr(&mp->ma_keys);
if (dk->dk_kind == DICT_KEYS_UNICODE && PyUnicode_CheckExact(key)) {
Py_ssize_t ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash);
if (ix == DKIX_EMPTY) {
*value_addr = PyStackRef_NULL;
return ix;
}
else if (ix >= 0) {
PyObject **addr_of_value = &DK_UNICODE_ENTRIES(dk)[ix].me_value;
PyObject *value = _Py_atomic_load_ptr(addr_of_value);
if (value == NULL) {
*value_addr = PyStackRef_NULL;
return DKIX_EMPTY;
}
if (_Py_IsImmortal(value) || _PyObject_HasDeferredRefcount(value)) {
*value_addr = (_PyStackRef){ .bits = (uintptr_t)value | Py_TAG_DEFERRED };
return ix;
}
if (_Py_TryIncrefCompare(addr_of_value, value)) {
*value_addr = PyStackRef_FromPyObjectSteal(value);
return ix;
}
}
}
PyObject *obj;
Py_ssize_t ix = _Py_dict_lookup_threadsafe(mp, key, hash, &obj);
if (ix >= 0 && obj != NULL) {
*value_addr = PyStackRef_FromPyObjectSteal(obj);
}
else {
*value_addr = PyStackRef_NULL;
}
return ix;
}
#else
Py_ssize_t
_Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr)
{ … }
Py_ssize_t
_Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr)
{ … }
#endif
int
_PyDict_HasOnlyStringKeys(PyObject *dict)
{ … }
void
_PyDict_EnablePerThreadRefcounting(PyObject *op)
{ … }
static inline int
is_unusable_slot(Py_ssize_t ix)
{ … }
static Py_ssize_t
find_empty_slot(PyDictKeysObject *keys, Py_hash_t hash)
{ … }
static int
insertion_resize(PyInterpreterState *interp, PyDictObject *mp, int unicode)
{ … }
static inline int
insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
Py_hash_t hash, PyObject *key, PyObject *value)
{ … }
static Py_ssize_t
insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash)
{ … }
static void
insert_split_value(PyInterpreterState *interp, PyDictObject *mp, PyObject *key, PyObject *value, Py_ssize_t ix)
{ … }
static int
insertdict(PyInterpreterState *interp, PyDictObject *mp,
PyObject *key, Py_hash_t hash, PyObject *value)
{ … }
static int
insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp,
PyObject *key, Py_hash_t hash, PyObject *value)
{ … }
static void
build_indices_generic(PyDictKeysObject *keys, PyDictKeyEntry *ep, Py_ssize_t n)
{ … }
static void
build_indices_unicode(PyDictKeysObject *keys, PyDictUnicodeEntry *ep, Py_ssize_t n)
{ … }
static int
dictresize(PyInterpreterState *interp, PyDictObject *mp,
uint8_t log2_newsize, int unicode)
{ … }
static PyObject *
dict_new_presized(PyInterpreterState *interp, Py_ssize_t minused, bool unicode)
{ … }
PyObject *
_PyDict_NewPresized(Py_ssize_t minused)
{ … }
PyObject *
_PyDict_FromItems(PyObject *const *keys, Py_ssize_t keys_offset,
PyObject *const *values, Py_ssize_t values_offset,
Py_ssize_t length)
{ … }
static PyObject *
dict_getitem(PyObject *op, PyObject *key, const char *warnmsg)
{ … }
PyObject *
PyDict_GetItem(PyObject *op, PyObject *key)
{ … }
Py_ssize_t
_PyDict_LookupIndex(PyDictObject *mp, PyObject *key)
{ … }
PyObject *
_PyDict_GetItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
{ … }
int
_PyDict_GetItemRef_KnownHash_LockHeld(PyDictObject *op, PyObject *key,
Py_hash_t hash, PyObject **result)
{ … }
int
_PyDict_GetItemRef_KnownHash(PyDictObject *op, PyObject *key, Py_hash_t hash, PyObject **result)
{ … }
int
PyDict_GetItemRef(PyObject *op, PyObject *key, PyObject **result)
{ … }
int
_PyDict_GetItemRef_Unicode_LockHeld(PyDictObject *op, PyObject *key, PyObject **result)
{ … }
PyObject *
PyDict_GetItemWithError(PyObject *op, PyObject *key)
{ … }
PyObject *
_PyDict_GetItemWithError(PyObject *dp, PyObject *kv)
{ … }
PyObject *
_PyDict_GetItemIdWithError(PyObject *dp, _Py_Identifier *key)
{ … }
PyObject *
_PyDict_GetItemStringWithError(PyObject *v, const char *key)
{ … }
PyObject *
_PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
{ … }
void
_PyDict_LoadGlobalStackRef(PyDictObject *globals, PyDictObject *builtins, PyObject *key, _PyStackRef *res)
{ … }
PyObject *
_PyDict_LoadBuiltinsFromGlobals(PyObject *globals)
{ … }
static int
setitem_take2_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
{ … }
int
_PyDict_SetItem_Take2(PyDictObject *mp, PyObject *key, PyObject *value)
{ … }
int
PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value)
{ … }
static int
setitem_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
{ … }
int
_PyDict_SetItem_KnownHash_LockHeld(PyDictObject *mp, PyObject *key, PyObject *value,
Py_hash_t hash)
{ … }
int
_PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
Py_hash_t hash)
{ … }
static void
delete_index_from_values(PyDictValues *values, Py_ssize_t ix)
{ … }
static void
delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
PyObject *old_value)
{ … }
int
PyDict_DelItem(PyObject *op, PyObject *key)
{ … }
static int
delitem_knownhash_lock_held(PyObject *op, PyObject *key, Py_hash_t hash)
{ … }
int
_PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
{ … }
static int
delitemif_lock_held(PyObject *op, PyObject *key,
int (*predicate)(PyObject *value, void *arg),
void *arg)
{ … }
int
_PyDict_DelItemIf(PyObject *op, PyObject *key,
int (*predicate)(PyObject *value, void *arg),
void *arg)
{ … }
static void
clear_lock_held(PyObject *op)
{ … }
void
PyDict_Clear(PyObject *op)
{ … }
int
_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
PyObject **pvalue, Py_hash_t *phash)
{ … }
int
PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue)
{ … }
int
_PyDict_Pop_KnownHash(PyDictObject *mp, PyObject *key, Py_hash_t hash,
PyObject **result)
{ … }
static int
pop_lock_held(PyObject *op, PyObject *key, PyObject **result)
{ … }
int
PyDict_Pop(PyObject *op, PyObject *key, PyObject **result)
{ … }
int
PyDict_PopString(PyObject *op, const char *key, PyObject **result)
{ … }
PyObject *
_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value)
{ … }
static PyDictObject *
dict_dict_fromkeys(PyInterpreterState *interp, PyDictObject *mp,
PyObject *iterable, PyObject *value)
{ … }
static PyDictObject *
dict_set_fromkeys(PyInterpreterState *interp, PyDictObject *mp,
PyObject *iterable, PyObject *value)
{ … }
PyObject *
_PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
{ … }
static void
dict_dealloc(PyObject *self)
{ … }
static PyObject *
dict_repr_lock_held(PyObject *self)
{ … }
static PyObject *
dict_repr(PyObject *self)
{ … }
static Py_ssize_t
dict_length(PyObject *self)
{ … }
static PyObject *
dict_subscript(PyObject *self, PyObject *key)
{ … }
static int
dict_ass_sub(PyObject *mp, PyObject *v, PyObject *w)
{ … }
static PyMappingMethods dict_as_mapping = …;
static PyObject *
keys_lock_held(PyObject *dict)
{ … }
PyObject *
PyDict_Keys(PyObject *dict)
{ … }
static PyObject *
values_lock_held(PyObject *dict)
{ … }
PyObject *
PyDict_Values(PyObject *dict)
{ … }
static PyObject *
items_lock_held(PyObject *dict)
{ … }
PyObject *
PyDict_Items(PyObject *dict)
{ … }
static PyObject *
dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value)
{ … }
static int
dict_update_arg(PyObject *self, PyObject *arg)
{ … }
static int
dict_update_common(PyObject *self, PyObject *args, PyObject *kwds,
const char *methname)
{ … }
static PyObject *
dict_update(PyObject *self, PyObject *args, PyObject *kwds)
{ … }
static int
merge_from_seq2_lock_held(PyObject *d, PyObject *seq2, int override)
{ … }
int
PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override)
{ … }
static int
dict_dict_merge(PyInterpreterState *interp, PyDictObject *mp, PyDictObject *other, int override)
{ … }
static int
dict_merge(PyInterpreterState *interp, PyObject *a, PyObject *b, int override)
{ … }
int
PyDict_Update(PyObject *a, PyObject *b)
{ … }
int
PyDict_Merge(PyObject *a, PyObject *b, int override)
{ … }
int
_PyDict_MergeEx(PyObject *a, PyObject *b, int override)
{ … }
static PyObject *
dict_copy_impl(PyDictObject *self)
{ … }
static PyDictValues *
copy_values(PyDictValues *values)
{ … }
static PyObject *
copy_lock_held(PyObject *o)
{ … }
PyObject *
PyDict_Copy(PyObject *o)
{ … }
Py_ssize_t
PyDict_Size(PyObject *mp)
{ … }
static int
dict_equal_lock_held(PyDictObject *a, PyDictObject *b)
{ … }
static int
dict_equal(PyDictObject *a, PyDictObject *b)
{ … }
static PyObject *
dict_richcompare(PyObject *v, PyObject *w, int op)
{ … }
static PyObject *
dict___contains__(PyDictObject *self, PyObject *key)
{ … }
static PyObject *
dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
{ … }
static int
dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_value,
PyObject **result, int incref_result)
{ … }
int
PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value,
PyObject **result)
{ … }
PyObject *
PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
{ … }
static PyObject *
dict_setdefault_impl(PyDictObject *self, PyObject *key,
PyObject *default_value)
{ … }
static PyObject *
dict_clear_impl(PyDictObject *self)
{ … }
static PyObject *
dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
{ … }
static PyObject *
dict_popitem_impl(PyDictObject *self)
{ … }
static int
dict_traverse(PyObject *op, visitproc visit, void *arg)
{ … }
static int
dict_tp_clear(PyObject *op)
{ … }
static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
static Py_ssize_t
sizeof_lock_held(PyDictObject *mp)
{ … }
Py_ssize_t
_PyDict_SizeOf(PyDictObject *mp)
{ … }
size_t
_PyDict_KeysSize(PyDictKeysObject *keys)
{ … }
static PyObject *
dict___sizeof___impl(PyDictObject *self)
{ … }
static PyObject *
dict_or(PyObject *self, PyObject *other)
{ … }
static PyObject *
dict_ior(PyObject *self, PyObject *other)
{ … }
PyDoc_STRVAR(getitem__doc__,
"__getitem__($self, key, /)\n--\n\nReturn self[key].");
PyDoc_STRVAR(update__doc__,
"D.update([E, ]**F) -> None. Update D from mapping/iterable E and F.\n\
If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k]\n\
If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v\n\
In either case, this is followed by: for k in F: D[k] = F[k]");
static PyMethodDef mapp_methods[] = …;
int
PyDict_Contains(PyObject *op, PyObject *key)
{ … }
int
PyDict_ContainsString(PyObject *op, const char *key)
{ … }
int
_PyDict_Contains_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
{ … }
int
_PyDict_ContainsId(PyObject *op, _Py_Identifier *key)
{ … }
static PySequenceMethods dict_as_sequence = …;
static PyNumberMethods dict_as_number = …;
static PyObject *
dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ … }
static int
dict_init(PyObject *self, PyObject *args, PyObject *kwds)
{ … }
static PyObject *
dict_vectorcall(PyObject *type, PyObject * const*args,
size_t nargsf, PyObject *kwnames)
{ … }
static PyObject *
dict_iter(PyObject *self)
{ … }
PyDoc_STRVAR(dictionary_doc,
"dict() -> new empty dictionary\n"
"dict(mapping) -> new dictionary initialized from a mapping object's\n"
" (key, value) pairs\n"
"dict(iterable) -> new dictionary initialized as if via:\n"
" d = {}\n"
" for k, v in iterable:\n"
" d[k] = v\n"
"dict(**kwargs) -> new dictionary initialized with the name=value pairs\n"
" in the keyword argument list. For example: dict(one=1, two=2)");
PyTypeObject PyDict_Type = …;
PyObject *
PyDict_GetItemString(PyObject *v, const char *key)
{ … }
int
PyDict_GetItemStringRef(PyObject *v, const char *key, PyObject **result)
{ … }
int
_PyDict_SetItemId(PyObject *v, _Py_Identifier *key, PyObject *item)
{ … }
int
PyDict_SetItemString(PyObject *v, const char *key, PyObject *item)
{ … }
int
_PyDict_DelItemId(PyObject *v, _Py_Identifier *key)
{ … }
int
PyDict_DelItemString(PyObject *v, const char *key)
{ … }
dictiterobject;
static PyObject *
dictiter_new(PyDictObject *dict, PyTypeObject *itertype)
{ … }
static void
dictiter_dealloc(PyObject *self)
{ … }
static int
dictiter_traverse(PyObject *self, visitproc visit, void *arg)
{ … }
static PyObject *
dictiter_len(PyObject *self, PyObject *Py_UNUSED(ignored))
{ … }
PyDoc_STRVAR(length_hint_doc,
"Private method returning an estimate of len(list(it)).");
static PyObject *
dictiter_reduce(PyObject *di, PyObject *Py_UNUSED(ignored));
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
static PyMethodDef dictiter_methods[] = …;
#ifdef Py_GIL_DISABLED
static int
dictiter_iternext_threadsafe(PyDictObject *d, PyObject *self,
PyObject **out_key, PyObject **out_value);
#else
static PyObject*
dictiter_iternextkey_lock_held(PyDictObject *d, PyObject *self)
{ … }
#endif
static PyObject*
dictiter_iternextkey(PyObject *self)
{ … }
PyTypeObject PyDictIterKey_Type = …;
#ifndef Py_GIL_DISABLED
static PyObject *
dictiter_iternextvalue_lock_held(PyDictObject *d, PyObject *self)
{ … }
#endif
static PyObject *
dictiter_iternextvalue(PyObject *self)
{ … }
PyTypeObject PyDictIterValue_Type = …;
static int
dictiter_iternextitem_lock_held(PyDictObject *d, PyObject *self,
PyObject **out_key, PyObject **out_value)
{ … }
#ifdef Py_GIL_DISABLED
static int
acquire_key_value(PyObject **key_loc, PyObject *value, PyObject **value_loc,
PyObject **out_key, PyObject **out_value)
{
if (out_key) {
*out_key = _Py_TryXGetRef(key_loc);
if (*out_key == NULL) {
return -1;
}
}
if (out_value) {
if (!_Py_TryIncrefCompare(value_loc, value)) {
if (out_key) {
Py_DECREF(*out_key);
}
return -1;
}
*out_value = value;
}
return 0;
}
static int
dictiter_iternext_threadsafe(PyDictObject *d, PyObject *self,
PyObject **out_key, PyObject **out_value)
{
int res;
dictiterobject *di = (dictiterobject *)self;
Py_ssize_t i;
PyDictKeysObject *k;
assert (PyDict_Check(d));
if (di->di_used != _Py_atomic_load_ssize_relaxed(&d->ma_used)) {
PyErr_SetString(PyExc_RuntimeError,
"dictionary changed size during iteration");
di->di_used = -1;
return -1;
}
ensure_shared_on_read(d);
i = _Py_atomic_load_ssize_relaxed(&di->di_pos);
k = _Py_atomic_load_ptr_relaxed(&d->ma_keys);
assert(i >= 0);
if (_PyDict_HasSplitTable(d)) {
PyDictValues *values = _Py_atomic_load_ptr_relaxed(&d->ma_values);
if (values == NULL) {
goto concurrent_modification;
}
Py_ssize_t used = (Py_ssize_t)_Py_atomic_load_uint8(&values->size);
if (i >= used) {
goto fail;
}
int index = get_index_from_order(d, i);
PyObject *value = _Py_atomic_load_ptr(&values->values[index]);
if (acquire_key_value(&DK_UNICODE_ENTRIES(k)[index].me_key, value,
&values->values[index], out_key, out_value) < 0) {
goto try_locked;
}
}
else {
Py_ssize_t n = _Py_atomic_load_ssize_relaxed(&k->dk_nentries);
if (DK_IS_UNICODE(k)) {
PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
PyObject *value;
while (i < n &&
(value = _Py_atomic_load_ptr(&entry_ptr->me_value)) == NULL) {
entry_ptr++;
i++;
}
if (i >= n)
goto fail;
if (acquire_key_value(&entry_ptr->me_key, value,
&entry_ptr->me_value, out_key, out_value) < 0) {
goto try_locked;
}
}
else {
PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
PyObject *value;
while (i < n &&
(value = _Py_atomic_load_ptr(&entry_ptr->me_value)) == NULL) {
entry_ptr++;
i++;
}
if (i >= n)
goto fail;
if (acquire_key_value(&entry_ptr->me_key, value,
&entry_ptr->me_value, out_key, out_value) < 0) {
goto try_locked;
}
}
}
Py_ssize_t len;
if ((len = _Py_atomic_load_ssize_relaxed(&di->len)) == 0) {
goto concurrent_modification;
}
_Py_atomic_store_ssize_relaxed(&di->di_pos, i + 1);
_Py_atomic_store_ssize_relaxed(&di->len, len - 1);
return 0;
concurrent_modification:
PyErr_SetString(PyExc_RuntimeError,
"dictionary keys changed during iteration");
fail:
di->di_dict = NULL;
Py_DECREF(d);
return -1;
try_locked:
Py_BEGIN_CRITICAL_SECTION(d);
res = dictiter_iternextitem_lock_held(d, self, out_key, out_value);
Py_END_CRITICAL_SECTION();
return res;
}
#endif
static bool
has_unique_reference(PyObject *op)
{ … }
static bool
acquire_iter_result(PyObject *result)
{ … }
static PyObject *
dictiter_iternextitem(PyObject *self)
{ … }
PyTypeObject PyDictIterItem_Type = …;
static PyObject *
dictreviter_iter_lock_held(PyDictObject *d, PyObject *self)
{ … }
static PyObject *
dictreviter_iternext(PyObject *self)
{ … }
PyTypeObject PyDictRevIterKey_Type = …;
static PyObject *
dict___reversed___impl(PyDictObject *self)
{ … }
static PyObject *
dictiter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
{ … }
PyTypeObject PyDictRevIterItem_Type = …;
PyTypeObject PyDictRevIterValue_Type = …;
static void
dictview_dealloc(PyObject *self)
{ … }
static int
dictview_traverse(PyObject *self, visitproc visit, void *arg)
{ … }
static Py_ssize_t
dictview_len(PyObject *self)
{ … }
PyObject *
_PyDictView_New(PyObject *dict, PyTypeObject *type)
{ … }
static PyObject *
dictview_mapping(PyObject *view, void *Py_UNUSED(ignored)) { … }
static PyGetSetDef dictview_getset[] = …;
static int
all_contained_in(PyObject *self, PyObject *other)
{ … }
static PyObject *
dictview_richcompare(PyObject *self, PyObject *other, int op)
{ … }
static PyObject *
dictview_repr(PyObject *self)
{ … }
static PyObject *
dictkeys_iter(PyObject *self)
{ … }
static int
dictkeys_contains(PyObject *self, PyObject *obj)
{ … }
static PySequenceMethods dictkeys_as_sequence = …;
static PyObject*
dictviews_to_set(PyObject *self)
{ … }
static PyObject*
dictviews_sub(PyObject *self, PyObject *other)
{ … }
static int
dictitems_contains(PyObject *dv, PyObject *obj);
PyObject *
_PyDictView_Intersect(PyObject* self, PyObject *other)
{ … }
static PyObject*
dictviews_or(PyObject* self, PyObject *other)
{ … }
static PyObject *
dictitems_xor_lock_held(PyObject *d1, PyObject *d2)
{ … }
static PyObject *
dictitems_xor(PyObject *self, PyObject *other)
{ … }
static PyObject*
dictviews_xor(PyObject* self, PyObject *other)
{ … }
static PyNumberMethods dictviews_as_number = …;
static PyObject*
dictviews_isdisjoint(PyObject *self, PyObject *other)
{ … }
PyDoc_STRVAR(isdisjoint_doc,
"Return True if the view and the given iterable have a null intersection.");
static PyObject* dictkeys_reversed(PyObject *dv, PyObject *Py_UNUSED(ignored));
PyDoc_STRVAR(reversed_keys_doc,
"Return a reverse iterator over the dict keys.");
static PyMethodDef dictkeys_methods[] = …;
PyTypeObject PyDictKeys_Type = …;
static PyObject *
dict_keys_impl(PyDictObject *self)
{ … }
static PyObject *
dictkeys_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
{ … }
static PyObject *
dictitems_iter(PyObject *self)
{ … }
static int
dictitems_contains(PyObject *self, PyObject *obj)
{ … }
static PySequenceMethods dictitems_as_sequence = …;
static PyObject* dictitems_reversed(PyObject *dv, PyObject *Py_UNUSED(ignored));
PyDoc_STRVAR(reversed_items_doc,
"Return a reverse iterator over the dict items.");
static PyMethodDef dictitems_methods[] = …;
PyTypeObject PyDictItems_Type = …;
static PyObject *
dict_items_impl(PyDictObject *self)
{ … }
static PyObject *
dictitems_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
{ … }
static PyObject *
dictvalues_iter(PyObject *self)
{ … }
static PySequenceMethods dictvalues_as_sequence = …;
static PyObject* dictvalues_reversed(PyObject *dv, PyObject *Py_UNUSED(ignored));
PyDoc_STRVAR(reversed_values_doc,
"Return a reverse iterator over the dict values.");
static PyMethodDef dictvalues_methods[] = …;
PyTypeObject PyDictValues_Type = …;
static PyObject *
dict_values_impl(PyDictObject *self)
{ … }
static PyObject *
dictvalues_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
{ … }
PyDictKeysObject *
_PyDict_NewKeysForClass(PyHeapTypeObject *cls)
{ … }
void
_PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp)
{ … }
static PyDictObject *
make_dict_from_instance_attributes(PyInterpreterState *interp,
PyDictKeysObject *keys, PyDictValues *values)
{ … }
PyDictObject *
_PyObject_MaterializeManagedDict_LockHeld(PyObject *obj)
{ … }
PyDictObject *
_PyObject_MaterializeManagedDict(PyObject *obj)
{ … }
int
_PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value)
{ … }
static int
store_instance_attr_lock_held(PyObject *obj, PyDictValues *values,
PyObject *name, PyObject *value)
{ … }
static inline int
store_instance_attr_dict(PyObject *obj, PyDictObject *dict, PyObject *name, PyObject *value)
{ … }
int
_PyObject_StoreInstanceAttribute(PyObject *obj, PyObject *name, PyObject *value)
{ … }
#if 0
#define CHECK …
int
_PyObject_ManagedDictValidityCheck(PyObject *obj)
{
PyTypeObject *tp = Py_TYPE(obj);
CHECK(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyManagedDictPointer *managed_dict = _PyObject_ManagedDictPointer(obj);
if (_PyManagedDictPointer_IsValues(*managed_dict)) {
PyDictValues *values = _PyManagedDictPointer_GetValues(*managed_dict);
int size = ((uint8_t *)values)[-2];
int count = 0;
PyDictKeysObject *keys = CACHED_KEYS(tp);
for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
if (values->values[i] != NULL) {
count++;
}
}
CHECK(size == count);
}
else {
if (managed_dict->dict != NULL) {
CHECK(PyDict_Check(managed_dict->dict));
}
}
return 1;
}
#endif
bool
_PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr)
{ … }
int
_PyObject_IsInstanceDictEmpty(PyObject *obj)
{ … }
int
PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
{ … }
static void
set_dict_inline_values(PyObject *obj, PyDictObject *new_dict)
{ … }
#ifdef Py_GIL_DISABLED
static bool
try_set_dict_inline_only_or_other_dict(PyObject *obj, PyObject *new_dict, PyDictObject **cur_dict)
{
bool replaced = false;
Py_BEGIN_CRITICAL_SECTION(obj);
PyDictObject *dict = *cur_dict = _PyObject_GetManagedDict(obj);
if (dict == NULL) {
set_dict_inline_values(obj, (PyDictObject *)new_dict);
replaced = true;
goto exit_lock;
}
if (FT_ATOMIC_LOAD_PTR_RELAXED(dict->ma_values) != _PyObject_InlineValues(obj)) {
FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict,
(PyDictObject *)Py_XNewRef(new_dict));
replaced = true;
goto exit_lock;
}
else {
Py_INCREF(dict);
}
exit_lock:
Py_END_CRITICAL_SECTION();
return replaced;
}
static int
replace_dict_probably_inline_materialized(PyObject *obj, PyDictObject *inline_dict,
PyDictObject *cur_dict, PyObject *new_dict)
{
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(obj);
if (cur_dict == inline_dict) {
assert(FT_ATOMIC_LOAD_PTR_RELAXED(inline_dict->ma_values) == _PyObject_InlineValues(obj));
int err = _PyDict_DetachFromObject(inline_dict, obj);
if (err != 0) {
assert(new_dict == NULL);
return err;
}
}
FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict,
(PyDictObject *)Py_XNewRef(new_dict));
return 0;
}
#endif
static void
decref_maybe_delay(PyObject *obj, bool delay)
{ … }
static int
set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
{ … }
int
_PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
{ … }
void
PyObject_ClearManagedDict(PyObject *obj)
{ … }
int
_PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
{ … }
static inline PyObject *
ensure_managed_dict(PyObject *obj)
{ … }
static inline PyObject *
ensure_nonmanaged_dict(PyObject *obj, PyObject **dictptr)
{ … }
PyObject *
PyObject_GenericGetDict(PyObject *obj, void *context)
{ … }
int
_PyObjectDict_SetItem(PyTypeObject *tp, PyObject *obj, PyObject **dictptr,
PyObject *key, PyObject *value)
{ … }
void
_PyDictKeys_DecRef(PyDictKeysObject *keys)
{ … }
static inline uint32_t
get_next_dict_keys_version(PyInterpreterState *interp)
{ … }
uint32_t
_PyDictKeys_GetVersionForCurrentState(PyInterpreterState *interp,
PyDictKeysObject *dictkeys)
{ … }
uint32_t
_PyDict_GetKeysVersionForCurrentState(PyInterpreterState *interp,
PyDictObject *dict)
{ … }
static inline int
validate_watcher_id(PyInterpreterState *interp, int watcher_id)
{ … }
int
PyDict_Watch(int watcher_id, PyObject* dict)
{ … }
int
PyDict_Unwatch(int watcher_id, PyObject* dict)
{ … }
int
PyDict_AddWatcher(PyDict_WatchCallback callback)
{ … }
int
PyDict_ClearWatcher(int watcher_id)
{ … }
static const char *
dict_event_name(PyDict_WatchEvent event) { … }
void
_PyDict_SendEvent(int watcher_bits,
PyDict_WatchEvent event,
PyDictObject *mp,
PyObject *key,
PyObject *value)
{ … }
#ifndef NDEBUG
static int
_PyObject_InlineValuesConsistencyCheck(PyObject *obj)
{
if ((Py_TYPE(obj)->tp_flags & Py_TPFLAGS_INLINE_VALUES) == 0) {
return 1;
}
assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictObject *dict = _PyObject_GetManagedDict(obj);
if (dict == NULL) {
return 1;
}
if (dict->ma_values == _PyObject_InlineValues(obj) ||
_PyObject_InlineValues(obj)->valid == 0) {
return 1;
}
assert(0);
return 0;
}
#endif