summaryrefslogtreecommitdiffstats
path: root/Objects/object.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/object.c')
-rw-r--r--Objects/object.c185
1 files changed, 131 insertions, 54 deletions
diff --git a/Objects/object.c b/Objects/object.c
index 9d48346..14c85c2 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -5,6 +5,7 @@
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_ceval.h" // _Py_EnterRecursiveCall()
#include "pycore_context.h"
+#include "pycore_dict.h"
#include "pycore_initconfig.h" // _PyStatus_EXCEPTION()
#include "pycore_object.h" // _PyType_CheckConsistency()
#include "pycore_pyerrors.h" // _PyErr_Occurred()
@@ -1065,10 +1066,8 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
return -1;
}
-/* Helper to get a pointer to an object's __dict__ slot, if any */
-
PyObject **
-_PyObject_GetDictPtr(PyObject *obj)
+_PyObject_DictPointer(PyObject *obj)
{
Py_ssize_t dictoffset;
PyTypeObject *tp = Py_TYPE(obj);
@@ -1090,6 +1089,35 @@ _PyObject_GetDictPtr(PyObject *obj)
return (PyObject **) ((char *)obj + dictoffset);
}
+/* Helper to get a pointer to an object's __dict__ slot, if any.
+ * Creates the dict from inline attributes if necessary.
+ * Does not set an exception. */
+PyObject **
+_PyObject_GetDictPtr(PyObject *obj)
+{
+ PyObject **dict_ptr = _PyObject_DictPointer(obj);
+ if (dict_ptr == NULL) {
+ return NULL;
+ }
+ if (*dict_ptr != NULL) {
+ return dict_ptr;
+ }
+ PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
+ if (values_ptr == NULL || *values_ptr == NULL) {
+ return dict_ptr;
+ }
+ PyObject *dict = _PyObject_MakeDictFromInstanceAttributes(obj, *values_ptr);
+ if (dict == NULL) {
+ PyErr_Clear();
+ return NULL;
+ }
+ assert(*dict_ptr == NULL);
+ assert(*values_ptr != NULL);
+ *values_ptr = NULL;
+ *dict_ptr = dict;
+ return dict_ptr;
+}
+
PyObject *
PyObject_SelfIter(PyObject *obj)
{
@@ -1136,7 +1164,7 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method)
}
}
- if (tp->tp_getattro != PyObject_GenericGetAttr || !PyUnicode_Check(name)) {
+ if (tp->tp_getattro != PyObject_GenericGetAttr || !PyUnicode_CheckExact(name)) {
*method = PyObject_GetAttr(obj, name);
return 0;
}
@@ -1156,23 +1184,34 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method)
}
}
}
-
- PyObject **dictptr = _PyObject_GetDictPtr(obj);
- PyObject *dict;
- if (dictptr != NULL && (dict = *dictptr) != NULL) {
- Py_INCREF(dict);
- PyObject *attr = PyDict_GetItemWithError(dict, name);
+ PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
+ if (values_ptr && *values_ptr) {
+ assert(*_PyObject_DictPointer(obj) == NULL);
+ PyObject *attr = _PyObject_GetInstanceAttribute(obj, *values_ptr, name);
if (attr != NULL) {
- *method = Py_NewRef(attr);
- Py_DECREF(dict);
+ *method = attr;
Py_XDECREF(descr);
return 0;
}
- Py_DECREF(dict);
+ }
+ else {
+ PyObject **dictptr = _PyObject_DictPointer(obj);
+ PyObject *dict;
+ if (dictptr != NULL && (dict = *dictptr) != NULL) {
+ Py_INCREF(dict);
+ PyObject *attr = PyDict_GetItemWithError(dict, name);
+ if (attr != NULL) {
+ *method = Py_NewRef(attr);
+ Py_DECREF(dict);
+ Py_XDECREF(descr);
+ return 0;
+ }
+ Py_DECREF(dict);
- if (PyErr_Occurred()) {
- Py_XDECREF(descr);
- return 0;
+ if (PyErr_Occurred()) {
+ Py_XDECREF(descr);
+ return 0;
+ }
}
}
@@ -1200,6 +1239,17 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method)
return 0;
}
+PyDictValues **
+_PyObject_ValuesPointer(PyObject *obj)
+{
+ PyTypeObject *tp = Py_TYPE(obj);
+ Py_ssize_t offset = tp->tp_inline_values_offset;
+ if (offset == 0) {
+ return NULL;
+ }
+ return (PyDictValues **) ((char *)obj + offset);
+}
+
/* Generic GetAttr functions - put these in your tp_[gs]etattro slot. */
PyObject *
@@ -1247,25 +1297,46 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
goto done;
}
}
-
if (dict == NULL) {
- /* Inline _PyObject_GetDictPtr */
- dictoffset = tp->tp_dictoffset;
- if (dictoffset != 0) {
- if (dictoffset < 0) {
- Py_ssize_t tsize = Py_SIZE(obj);
- if (tsize < 0) {
- tsize = -tsize;
+ PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
+ if (values_ptr && *values_ptr) {
+ if (PyUnicode_CheckExact(name)) {
+ assert(*_PyObject_DictPointer(obj) == NULL);
+ res = _PyObject_GetInstanceAttribute(obj, *values_ptr, name);
+ if (res != NULL) {
+ goto done;
}
- size_t size = _PyObject_VAR_SIZE(tp, tsize);
- _PyObject_ASSERT(obj, size <= PY_SSIZE_T_MAX);
-
- dictoffset += (Py_ssize_t)size;
- _PyObject_ASSERT(obj, dictoffset > 0);
- _PyObject_ASSERT(obj, dictoffset % SIZEOF_VOID_P == 0);
}
- dictptr = (PyObject **) ((char *)obj + dictoffset);
- dict = *dictptr;
+ else {
+ dictptr = _PyObject_DictPointer(obj);
+ assert(dictptr != NULL && *dictptr == NULL);
+ *dictptr = dict = _PyObject_MakeDictFromInstanceAttributes(obj, *values_ptr);
+ if (dict == NULL) {
+ res = NULL;
+ goto done;
+ }
+ *values_ptr = NULL;
+ }
+ }
+ else {
+ /* Inline _PyObject_DictPointer */
+ dictoffset = tp->tp_dictoffset;
+ if (dictoffset != 0) {
+ if (dictoffset < 0) {
+ Py_ssize_t tsize = Py_SIZE(obj);
+ if (tsize < 0) {
+ tsize = -tsize;
+ }
+ size_t size = _PyObject_VAR_SIZE(tp, tsize);
+ _PyObject_ASSERT(obj, size <= PY_SSIZE_T_MAX);
+
+ dictoffset += (Py_ssize_t)size;
+ _PyObject_ASSERT(obj, dictoffset > 0);
+ _PyObject_ASSERT(obj, dictoffset % SIZEOF_VOID_P == 0);
+ }
+ dictptr = (PyObject **) ((char *)obj + dictoffset);
+ dict = *dictptr;
+ }
}
}
if (dict != NULL) {
@@ -1328,7 +1399,6 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
PyTypeObject *tp = Py_TYPE(obj);
PyObject *descr;
descrsetfunc f;
- PyObject **dictptr;
int res = -1;
if (!PyUnicode_Check(name)){
@@ -1354,30 +1424,30 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
}
}
- /* XXX [Steve Dower] These are really noisy - worth it? */
- /*if (PyType_Check(obj) || PyModule_Check(obj)) {
- if (value && PySys_Audit("object.__setattr__", "OOO", obj, name, value) < 0)
- return -1;
- if (!value && PySys_Audit("object.__delattr__", "OO", obj, name) < 0)
- return -1;
- }*/
-
if (dict == NULL) {
- dictptr = _PyObject_GetDictPtr(obj);
- if (dictptr == NULL) {
- if (descr == NULL) {
- PyErr_Format(PyExc_AttributeError,
- "'%.100s' object has no attribute '%U'",
- tp->tp_name, name);
+ PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
+ if (values_ptr && *values_ptr) {
+ res = _PyObject_StoreInstanceAttribute(obj, *values_ptr, name, value);
+ }
+ else {
+ PyObject **dictptr = _PyObject_DictPointer(obj);
+ if (dictptr == NULL) {
+ if (descr == NULL) {
+ PyErr_Format(PyExc_AttributeError,
+ "'%.100s' object has no attribute '%U'",
+ tp->tp_name, name);
+ }
+ else {
+ PyErr_Format(PyExc_AttributeError,
+ "'%.50s' object attribute '%U' is read-only",
+ tp->tp_name, name);
+ }
+ goto done;
}
else {
- PyErr_Format(PyExc_AttributeError,
- "'%.50s' object attribute '%U' is read-only",
- tp->tp_name, name);
+ res = _PyObjectDict_SetItem(tp, dictptr, name, value);
}
- goto done;
}
- res = _PyObjectDict_SetItem(tp, dictptr, name, value);
}
else {
Py_INCREF(dict);
@@ -1407,8 +1477,15 @@ PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context)
{
PyObject **dictptr = _PyObject_GetDictPtr(obj);
if (dictptr == NULL) {
- PyErr_SetString(PyExc_AttributeError,
- "This object has no __dict__");
+ PyDictValues** values_ptr = _PyObject_ValuesPointer(obj);
+ if (values_ptr != NULL && *values_ptr != NULL) {
+ /* Was unable to convert to dict */
+ PyErr_NoMemory();
+ }
+ else {
+ PyErr_SetString(PyExc_AttributeError,
+ "This object has no __dict__");
+ }
return -1;
}
if (value == NULL) {