Only allocate dict pointer when needed for dynamic attributes

This commit is contained in:
Dean Moldovan 2016-10-12 23:20:32 +02:00
parent 6fccf69360
commit 22726c9d22
2 changed files with 22 additions and 19 deletions

View File

@ -297,7 +297,6 @@ inline std::string error_string();
template <typename type> struct instance_essentials { template <typename type> struct instance_essentials {
PyObject_HEAD PyObject_HEAD
type *value; type *value;
PyObject *dict;
PyObject *weakrefs; PyObject *weakrefs;
bool owned : 1; bool owned : 1;
bool constructed : 1; bool constructed : 1;

View File

@ -574,24 +574,24 @@ public:
NAMESPACE_BEGIN(detail) NAMESPACE_BEGIN(detail)
extern "C" inline PyObject *get_dict(PyObject *op, void *) { extern "C" inline PyObject *get_dict(PyObject *op, void *) {
auto *self = (instance<void> *) op; PyObject *&dict = *_PyObject_GetDictPtr(op);
if (!self->dict) { if (!dict) {
self->dict = PyDict_New(); dict = PyDict_New();
} }
Py_XINCREF(self->dict); Py_XINCREF(dict);
return self->dict; return dict;
} }
extern "C" inline int set_dict(PyObject *op, PyObject *dict, void *) { extern "C" inline int set_dict(PyObject *op, PyObject *new_dict, void *) {
if (!PyDict_Check(dict)) { if (!PyDict_Check(new_dict)) {
PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'", PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'",
Py_TYPE(dict)->tp_name); Py_TYPE(new_dict)->tp_name);
return -1; return -1;
} }
auto *self = (instance<void> *) op; PyObject *&dict = *_PyObject_GetDictPtr(op);
Py_INCREF(dict); Py_INCREF(new_dict);
Py_CLEAR(self->dict); Py_CLEAR(dict);
self->dict = dict; dict = new_dict;
return 0; return 0;
} }
@ -714,7 +714,8 @@ protected:
/* Support dynamic attributes */ /* Support dynamic attributes */
if (rec->dynamic_attr) { if (rec->dynamic_attr) {
type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_GC; type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_GC;
type->ht_type.tp_dictoffset = offsetof(instance_essentials<void>, dict); type->ht_type.tp_dictoffset = type->ht_type.tp_basicsize; // place the dict at the end
type->ht_type.tp_basicsize += sizeof(PyObject *); // and allocate enough space for it
type->ht_type.tp_getset = generic_getset; type->ht_type.tp_getset = generic_getset;
type->ht_type.tp_traverse = traverse; type->ht_type.tp_traverse = traverse;
type->ht_type.tp_clear = clear; type->ht_type.tp_clear = clear;
@ -822,20 +823,23 @@ protected:
if (self->weakrefs) if (self->weakrefs)
PyObject_ClearWeakRefs((PyObject *) self); PyObject_ClearWeakRefs((PyObject *) self);
Py_CLEAR(self->dict); PyObject **dict_ptr = _PyObject_GetDictPtr((PyObject *) self);
if (dict_ptr) {
Py_CLEAR(*dict_ptr);
}
} }
Py_TYPE(self)->tp_free((PyObject*) self); Py_TYPE(self)->tp_free((PyObject*) self);
} }
static int traverse(PyObject *op, visitproc visit, void *arg) { static int traverse(PyObject *op, visitproc visit, void *arg) {
auto *self = (instance<void> *) op; PyObject *&dict = *_PyObject_GetDictPtr(op);
Py_VISIT(self->dict); Py_VISIT(dict);
return 0; return 0;
} }
static int clear(PyObject *op) { static int clear(PyObject *op) {
auto *self = (instance<void> *) op; PyObject *&dict = *_PyObject_GetDictPtr(op);
Py_CLEAR(self->dict); Py_CLEAR(dict);
return 0; return 0;
} }