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 {
PyObject_HEAD
type *value;
PyObject *dict;
PyObject *weakrefs;
bool owned : 1;
bool constructed : 1;

View File

@ -574,24 +574,24 @@ public:
NAMESPACE_BEGIN(detail)
extern "C" inline PyObject *get_dict(PyObject *op, void *) {
auto *self = (instance<void> *) op;
if (!self->dict) {
self->dict = PyDict_New();
PyObject *&dict = *_PyObject_GetDictPtr(op);
if (!dict) {
dict = PyDict_New();
}
Py_XINCREF(self->dict);
return self->dict;
Py_XINCREF(dict);
return dict;
}
extern "C" inline int set_dict(PyObject *op, PyObject *dict, void *) {
if (!PyDict_Check(dict)) {
extern "C" inline int set_dict(PyObject *op, PyObject *new_dict, void *) {
if (!PyDict_Check(new_dict)) {
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;
}
auto *self = (instance<void> *) op;
Py_INCREF(dict);
Py_CLEAR(self->dict);
self->dict = dict;
PyObject *&dict = *_PyObject_GetDictPtr(op);
Py_INCREF(new_dict);
Py_CLEAR(dict);
dict = new_dict;
return 0;
}
@ -714,7 +714,8 @@ protected:
/* Support dynamic attributes */
if (rec->dynamic_attr) {
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_traverse = traverse;
type->ht_type.tp_clear = clear;
@ -822,20 +823,23 @@ protected:
if (self->weakrefs)
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);
}
static int traverse(PyObject *op, visitproc visit, void *arg) {
auto *self = (instance<void> *) op;
Py_VISIT(self->dict);
PyObject *&dict = *_PyObject_GetDictPtr(op);
Py_VISIT(dict);
return 0;
}
static int clear(PyObject *op) {
auto *self = (instance<void> *) op;
Py_CLEAR(self->dict);
PyObject *&dict = *_PyObject_GetDictPtr(op);
Py_CLEAR(dict);
return 0;
}