Skip to content

Commit f93588a

Browse files
_PyObject_TryGetInstanceAttributeStackRef
1 parent be5fa22 commit f93588a

File tree

4 files changed

+98
-8
lines changed

4 files changed

+98
-8
lines changed

Include/internal/pycore_dict.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ extern int _PyDict_GetItemRef_KnownHash(PyDictObject *op, PyObject *key, Py_hash
120120
extern int _PyDict_GetItemRef_Unicode_LockHeld(PyDictObject *op, PyObject *key, PyObject **result);
121121
extern int _PyDict_GetItem_KnownHash_StackRef(PyDictObject *op, PyObject *key, Py_hash_t hash, _PyStackRef *result);
122122
extern int _PyObjectDict_SetItem(PyTypeObject *tp, PyObject *obj, PyObject **dictptr, PyObject *name, PyObject *value);
123+
extern int _PyDict_GetItemStackRef(PyObject *op, PyObject *key, _PyStackRef *result);
123124

124125
extern int _PyDict_Pop_KnownHash(
125126
PyDictObject *dict,

Include/internal/pycore_object.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,8 @@ extern int _PyObject_StoreInstanceAttribute(PyObject *obj,
790790
PyObject *name, PyObject *value);
791791
extern bool _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name,
792792
PyObject **attr);
793-
793+
extern bool _PyObject_TryGetInstanceAttributeStackRef(PyObject *obj, PyObject *name,
794+
_PyStackRef *attr);
794795
#ifdef Py_GIL_DISABLED
795796
# define MANAGED_DICT_OFFSET (((Py_ssize_t)sizeof(PyObject *))*-1)
796797
# define MANAGED_WEAKREF_OFFSET (((Py_ssize_t)sizeof(PyObject *))*-2)

Objects/dictobject.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2363,6 +2363,24 @@ PyDict_GetItemRef(PyObject *op, PyObject *key, PyObject **result)
23632363
return _PyDict_GetItemRef_KnownHash((PyDictObject *)op, key, hash, result);
23642364
}
23652365

2366+
int
2367+
_PyDict_GetItemStackRef(PyObject *op, PyObject *key, _PyStackRef *result)
2368+
{
2369+
if (!PyDict_Check(op)) {
2370+
PyErr_BadInternalCall();
2371+
*result = PyStackRef_NULL;
2372+
return -1;
2373+
}
2374+
2375+
Py_hash_t hash = _PyObject_HashFast(key);
2376+
if (hash == -1) {
2377+
*result = PyStackRef_NULL;
2378+
return -1;
2379+
}
2380+
2381+
return _PyDict_GetItem_KnownHash_StackRef((PyDictObject *)op, key, hash, result);
2382+
}
2383+
23662384
int
23672385
_PyDict_GetItemRef_Unicode_LockHeld(PyDictObject *op, PyObject *key, PyObject **result)
23682386
{
@@ -7075,6 +7093,79 @@ _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr
70757093
#endif
70767094
}
70777095

7096+
bool
7097+
_PyObject_TryGetInstanceAttributeStackRef(PyObject *obj, PyObject *name, _PyStackRef *attr)
7098+
{
7099+
assert(PyUnicode_CheckExact(name));
7100+
PyDictValues *values = _PyObject_InlineValues(obj);
7101+
if (!FT_ATOMIC_LOAD_UINT8(values->valid)) {
7102+
return false;
7103+
}
7104+
7105+
PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
7106+
assert(keys != NULL);
7107+
Py_ssize_t ix = _PyDictKeys_StringLookup(keys, name);
7108+
if (ix == DKIX_EMPTY) {
7109+
*attr = PyStackRef_NULL;
7110+
return true;
7111+
}
7112+
7113+
#ifdef Py_GIL_DISABLED
7114+
PyObject *value = _Py_atomic_load_ptr_acquire(&values->values[ix]);
7115+
*attr = PyStackRef_FromPyObjectNew(value);
7116+
if (value == _Py_atomic_load_ptr_acquire(&values->values[ix])) {
7117+
return true;
7118+
}
7119+
7120+
PyDictObject *dict = _PyObject_GetManagedDict(obj);
7121+
if (dict == NULL) {
7122+
// No dict, lock the object to prevent one from being
7123+
// materialized...
7124+
bool success = false;
7125+
Py_BEGIN_CRITICAL_SECTION(obj);
7126+
7127+
dict = _PyObject_GetManagedDict(obj);
7128+
if (dict == NULL) {
7129+
// Still no dict, we can read from the values
7130+
assert(values->valid);
7131+
value = values->values[ix];
7132+
*attr = PyStackRef_FromPyObjectNew(value);
7133+
success = true;
7134+
}
7135+
7136+
Py_END_CRITICAL_SECTION();
7137+
7138+
if (success) {
7139+
return true;
7140+
}
7141+
}
7142+
7143+
// We have a dictionary, we'll need to lock it to prevent
7144+
// the values from being resized.
7145+
assert(dict != NULL);
7146+
7147+
bool success;
7148+
Py_BEGIN_CRITICAL_SECTION(dict);
7149+
7150+
if (dict->ma_values == values && FT_ATOMIC_LOAD_UINT8(values->valid)) {
7151+
value = _Py_atomic_load_ptr_relaxed(&values->values[ix]);
7152+
*attr = PyStackRef_FromPyObjectNew(value);
7153+
success = true;
7154+
} else {
7155+
// Caller needs to lookup from the dictionary
7156+
success = false;
7157+
}
7158+
7159+
Py_END_CRITICAL_SECTION();
7160+
7161+
return success;
7162+
#else
7163+
PyObject *value = values->values[ix];
7164+
*attr = PyStackRef_FromPyObjectNew(value);
7165+
return true;
7166+
#endif
7167+
}
7168+
70787169
int
70797170
_PyObject_IsInstanceDictEmpty(PyObject *obj)
70807171
{

Objects/object.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,11 +1620,10 @@ _PyObject_GetMethodStackRef(PyObject *obj, PyObject *name, _PyStackRef *method)
16201620
}
16211621
}
16221622
}
1623-
PyObject *dict, *attr;
1623+
PyObject *dict;
16241624
if ((tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) &&
1625-
_PyObject_TryGetInstanceAttribute(obj, name, &attr)) {
1626-
if (attr != NULL) {
1627-
*method = PyStackRef_FromPyObjectSteal(attr);
1625+
_PyObject_TryGetInstanceAttributeStackRef(obj, name, method)) {
1626+
if (!PyStackRef_IsNull(*method)) {
16281627
PyStackRef_XCLOSE(descr_st);
16291628
return 0;
16301629
}
@@ -1644,9 +1643,7 @@ _PyObject_GetMethodStackRef(PyObject *obj, PyObject *name, _PyStackRef *method)
16441643
}
16451644
if (dict != NULL) {
16461645
Py_INCREF(dict);
1647-
PyObject *item;
1648-
if (PyDict_GetItemRef(dict, name, &item) != 0) {
1649-
*method = PyStackRef_FromPyObjectSteal(item);
1646+
if (_PyDict_GetItemStackRef(dict, name, method) != 0) {
16501647
// found or error
16511648
Py_DECREF(dict);
16521649
PyStackRef_CLOSE(descr_st);

0 commit comments

Comments
 (0)