Fix PyObject_GenericGetDict, PyObject_GenericSetDict, and add test cases · python/cpython@56a79e6 · GitHub
Skip to content

Commit 56a79e6

Browse files
committed
Fix PyObject_GenericGetDict, PyObject_GenericSetDict, and add test cases
1 parent ae6d925 commit 56a79e6

3 files changed

Lines changed: 206 additions & 51 deletions

File tree

Lines changed: 141 additions & 0 deletions

Objects/dictobject.c

Lines changed: 61 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7159,70 +7159,47 @@ _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
71597159
return 0;
71607160
}
71617161

7162-
PyObject *
7163-
PyObject_GenericGetDict(PyObject *obj, void *context)
7162+
static inline PyObject *
7163+
ensure_managed_dict(PyObject *obj)
71647164
{
7165-
PyInterpreterState *interp = _PyInterpreterState_GET();
7166-
PyTypeObject *tp = Py_TYPE(obj);
7167-
PyDictObject *dict;
7168-
if (_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT)) {
7169-
dict = _PyObject_GetManagedDict(obj);
7170-
if (dict == NULL &&
7171-
(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) &&
7165+
PyDictObject *dict = _PyObject_GetManagedDict(obj);
7166+
if (dict == NULL) {
7167+
PyTypeObject *tp = Py_TYPE(obj);
7168+
if ((tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) &&
71727169
FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(obj)->valid)) {
71737170
dict = _PyObject_MaterializeManagedDict(obj);
71747171
}
7175-
else if (dict == NULL) {
7176-
Py_BEGIN_CRITICAL_SECTION(obj);
7177-
7172+
else {
7173+
#ifdef Py_GIL_DISABLED
71787174
// Check again that we're not racing with someone else creating the dict
7175+
Py_BEGIN_CRITICAL_SECTION(obj);
71797176
dict = _PyObject_GetManagedDict(obj);
7180-
if (dict == NULL) {
7181-
OBJECT_STAT_INC(dict_materialized_on_request);
7182-
dictkeys_incref(CACHED_KEYS(tp));
7183-
dict = (PyDictObject *)new_dict_with_shared_keys(interp, CACHED_KEYS(tp));
7184-
FT_ATOMIC_STORE_PTR_RELEASE(_PyObject_ManagedDictPointer(obj)->dict,
7185-
(PyDictObject *)dict);
7177+
if (dict != NULL) {
7178+
goto done;
71867179
}
7180+
#endif
7181+
OBJECT_STAT_INC(dict_materialized_on_request);
7182+
dictkeys_incref(CACHED_KEYS(tp));
7183+
dict = (PyDictObject *)new_dict_with_shared_keys(_PyInterpreterState_GET(),
7184+
CACHED_KEYS(tp));
7185+
FT_ATOMIC_STORE_PTR_RELEASE(_PyObject_ManagedDictPointer(obj)->dict,
7186+
(PyDictObject *)dict);
71877187

7188+
#ifdef Py_GIL_DISABLED
7189+
done:
71887190
Py_END_CRITICAL_SECTION();
7191+
#endif
71897192
}
7190-
return Py_XNewRef((PyObject *)dict);
7191-
}
7192-
else {
7193-
PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
7194-
if (dictptr == NULL) {
7195-
PyErr_SetString(PyExc_AttributeError,
7196-
"This object has no __dict__");
7197-
return NULL;
7198-
}
7199-
PyObject *dict = *dictptr;
7200-
if (dict == NULL) {
7201-
PyTypeObject *tp = Py_TYPE(obj);
7202-
if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) {
7203-
dictkeys_incref(CACHED_KEYS(tp));
7204-
*dictptr = dict = new_dict_with_shared_keys(
7205-
interp, CACHED_KEYS(tp));
7206-
}
7207-
else {
7208-
*dictptr = dict = PyDict_New();
7209-
}
7210-
}
7211-
return Py_XNewRef(dict);
72127193
}
7194+
return (PyObject *)dict;
72137195
}
72147196

7215-
int
7216-
_PyObjectDict_SetItem(PyTypeObject *tp, PyObject *obj, PyObject **dictptr,
7217-
PyObject *key, PyObject *value)
7197+
static inline PyObject *
7198+
ensure_nonmanaged_dict(PyObject *obj, PyObject **dictptr)
72187199
{
7219-
PyObject *dict;
7220-
int res;
72217200
PyDictKeysObject *cached;
7222-
PyInterpreterState *interp = _PyInterpreterState_GET();
72237201

7224-
assert(dictptr != NULL);
7225-
dict = *dictptr;
7202+
PyObject *dict = FT_ATOMIC_LOAD_PTR_RELAXED(*dictptr);
72267203
if (dict == NULL) {
72277204
#ifdef Py_GIL_DISABLED
72287205
Py_BEGIN_CRITICAL_SECTION(obj);
@@ -7231,7 +7208,9 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject *obj, PyObject **dictptr,
72317208
goto done;
72327209
}
72337210
#endif
7211+
PyTypeObject *tp = Py_TYPE(obj);
72347212
if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) && (cached = CACHED_KEYS(tp))) {
7213+
PyInterpreterState *interp = _PyInterpreterState_GET();
72357214
assert(!_PyType_HasFeature(tp, Py_TPFLAGS_INLINE_VALUES));
72367215
dictkeys_incref(cached);
72377216
dict = new_dict_with_shared_keys(interp, cached);
@@ -7242,14 +7221,45 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject *obj, PyObject **dictptr,
72427221
else {
72437222
dict = PyDict_New();
72447223
}
7245-
*dictptr = dict;
7224+
FT_ATOMIC_STORE_PTR_RELAXED(*dictptr, dict);
72467225
#ifdef Py_GIL_DISABLED
72477226
done:
72487227
Py_END_CRITICAL_SECTION();
72497228
#endif
7250-
if (dict == NULL) {
7251-
return -1;
7229+
}
7230+
return dict;
7231+
}
7232+
7233+
PyObject *
7234+
PyObject_GenericGetDict(PyObject *obj, void *context)
7235+
{
7236+
PyTypeObject *tp = Py_TYPE(obj);
7237+
if (_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT)) {
7238+
return Py_XNewRef(ensure_managed_dict(obj));
7239+
}
7240+
else {
7241+
PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
7242+
if (dictptr == NULL) {
7243+
PyErr_SetString(PyExc_AttributeError,
7244+
"This object has no __dict__");
7245+
return NULL;
72527246
}
7247+
7248+
return Py_XNewRef(ensure_nonmanaged_dict(obj, dictptr));
7249+
}
7250+
}
7251+
7252+
int
7253+
_PyObjectDict_SetItem(PyTypeObject *tp, PyObject *obj, PyObject **dictptr,
7254+
PyObject *key, PyObject *value)
7255+
{
7256+
PyObject *dict;
7257+
int res;
7258+
7259+
assert(dictptr != NULL);
7260+
dict = ensure_nonmanaged_dict(obj, dictptr);
7261+
if (dict == NULL) {
7262+
return -1;
72537263
}
72547264

72557265
Py_BEGIN_CRITICAL_SECTION(dict);

Objects/object.c

Lines changed: 4 additions & 0 deletions

0 commit comments

Comments
 (0)