Kaydet (Commit) 9676b22c authored tarafından Guido van Rossum's avatar Guido van Rossum

Weak reference support, closing SF bug #451773.

Classes that don't use __slots__ have a __weakref__ member added in
the same way as __dict__ is added (i.e. only if the base didn't
already have one).  Classes using __slots__ can enable weak
referenceability by adding '__weakref__' to the __slots__ list.

Renamed the __weaklistoffset__ class member to __weakrefoffset__ --
it's not always a list, it seems.  (Is tp_weaklistoffset a historical
misnomer, or do I misunderstand this?)
üst dbfe5e85
...@@ -9,7 +9,7 @@ static struct memberlist type_members[] = { ...@@ -9,7 +9,7 @@ static struct memberlist type_members[] = {
{"__itemsize__", T_INT, offsetof(PyTypeObject, tp_itemsize), READONLY}, {"__itemsize__", T_INT, offsetof(PyTypeObject, tp_itemsize), READONLY},
{"__flags__", T_LONG, offsetof(PyTypeObject, tp_flags), READONLY}, {"__flags__", T_LONG, offsetof(PyTypeObject, tp_flags), READONLY},
{"__doc__", T_STRING, offsetof(PyTypeObject, tp_doc), READONLY}, {"__doc__", T_STRING, offsetof(PyTypeObject, tp_doc), READONLY},
{"__weaklistoffset__", T_LONG, {"__weakrefoffset__", T_LONG,
offsetof(PyTypeObject, tp_weaklistoffset), READONLY}, offsetof(PyTypeObject, tp_weaklistoffset), READONLY},
{"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY}, {"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY},
{"__dictoffset__", T_LONG, {"__dictoffset__", T_LONG,
...@@ -201,6 +201,7 @@ static void ...@@ -201,6 +201,7 @@ static void
subtype_dealloc(PyObject *self) subtype_dealloc(PyObject *self)
{ {
int dictoffset = self->ob_type->tp_dictoffset; int dictoffset = self->ob_type->tp_dictoffset;
int weaklistoffset = self->ob_type->tp_weaklistoffset;
PyTypeObject *type, *base; PyTypeObject *type, *base;
destructor f; destructor f;
...@@ -224,6 +225,10 @@ subtype_dealloc(PyObject *self) ...@@ -224,6 +225,10 @@ subtype_dealloc(PyObject *self)
} }
} }
/* If we added weaklist, we clear it */
if (weaklistoffset && !base->tp_weaklistoffset)
PyObject_ClearWeakRefs(self);
/* Finalize GC if the base doesn't do GC and we do */ /* Finalize GC if the base doesn't do GC and we do */
if (PyType_IS_GC(type) && !PyType_IS_GC(base)) if (PyType_IS_GC(type) && !PyType_IS_GC(base))
PyObject_GC_Fini(self); PyObject_GC_Fini(self);
...@@ -455,22 +460,23 @@ best_base(PyObject *bases) ...@@ -455,22 +460,23 @@ best_base(PyObject *bases)
static int static int
extra_ivars(PyTypeObject *type, PyTypeObject *base) extra_ivars(PyTypeObject *type, PyTypeObject *base)
{ {
int t_size = PyType_BASICSIZE(type); size_t t_size = PyType_BASICSIZE(type);
int b_size = PyType_BASICSIZE(base); size_t b_size = PyType_BASICSIZE(base);
assert(t_size >= b_size); /* type smaller than base! */ assert(t_size >= b_size); /* Else type smaller than base! */
if (type->tp_itemsize || base->tp_itemsize) { if (type->tp_itemsize || base->tp_itemsize) {
/* If itemsize is involved, stricter rules */ /* If itemsize is involved, stricter rules */
return t_size != b_size || return t_size != b_size ||
type->tp_itemsize != base->tp_itemsize; type->tp_itemsize != base->tp_itemsize;
} }
if (t_size == b_size) if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 &&
return 0; type->tp_weaklistoffset + sizeof(PyObject *) == t_size)
if (type->tp_dictoffset != 0 && base->tp_dictoffset == 0 && t_size -= sizeof(PyObject *);
type->tp_dictoffset == b_size && if (type->tp_dictoffset && base->tp_dictoffset == 0 &&
(size_t)t_size == b_size + sizeof(PyObject *)) type->tp_dictoffset + sizeof(PyObject *) == t_size)
return 0; /* "Forgive" adding a __dict__ only */ t_size -= sizeof(PyObject *);
return 1;
return t_size != b_size;
} }
static PyTypeObject * static PyTypeObject *
...@@ -500,7 +506,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) ...@@ -500,7 +506,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
PyTypeObject *type, *base, *tmptype, *winner; PyTypeObject *type, *base, *tmptype, *winner;
etype *et; etype *et;
struct memberlist *mp; struct memberlist *mp;
int i, nbases, nslots, slotoffset, dynamic; int i, nbases, nslots, slotoffset, dynamic, add_dict, add_weak;
/* Special case: type(x) should return x->ob_type */ /* Special case: type(x) should return x->ob_type */
if (metatype == &PyType_Type && if (metatype == &PyType_Type &&
...@@ -613,6 +619,8 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) ...@@ -613,6 +619,8 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
/* Check for a __slots__ sequence variable in dict, and count it */ /* Check for a __slots__ sequence variable in dict, and count it */
slots = PyDict_GetItemString(dict, "__slots__"); slots = PyDict_GetItemString(dict, "__slots__");
nslots = 0; nslots = 0;
add_dict = 0;
add_weak = 0;
if (slots != NULL) { if (slots != NULL) {
/* Make it into a tuple */ /* Make it into a tuple */
if (PyString_Check(slots)) if (PyString_Check(slots))
...@@ -629,12 +637,19 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) ...@@ -629,12 +637,19 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
Py_DECREF(slots); Py_DECREF(slots);
return NULL; return NULL;
} }
/* XXX Check against null bytes in name */
} }
} }
if (slots == NULL && base->tp_dictoffset == 0 && if (slots == NULL && base->tp_dictoffset == 0 &&
(base->tp_setattro == PyObject_GenericSetAttr || (base->tp_setattro == PyObject_GenericSetAttr ||
base->tp_setattro == NULL)) base->tp_setattro == NULL)) {
nslots = 1; nslots++;
add_dict++;
}
if (slots == NULL && base->tp_weaklistoffset == 0) {
nslots++;
add_weak++;
}
/* XXX From here until type is safely allocated, /* XXX From here until type is safely allocated,
"return NULL" may leak slots! */ "return NULL" may leak slots! */
...@@ -716,16 +731,31 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) ...@@ -716,16 +731,31 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
PyTuple_GET_ITEM(slots, i)); PyTuple_GET_ITEM(slots, i));
mp->type = T_OBJECT; mp->type = T_OBJECT;
mp->offset = slotoffset; mp->offset = slotoffset;
if (base->tp_weaklistoffset == 0 &&
strcmp(mp->name, "__weakref__") == 0)
type->tp_weaklistoffset = slotoffset;
slotoffset += sizeof(PyObject *); slotoffset += sizeof(PyObject *);
} }
} }
else if (nslots) { else {
type->tp_dictoffset = slotoffset; if (add_dict) {
mp->name = "__dict__"; type->tp_dictoffset = slotoffset;
mp->type = T_OBJECT; mp->name = "__dict__";
mp->offset = slotoffset; mp->type = T_OBJECT;
mp->readonly = 1; mp->offset = slotoffset;
slotoffset += sizeof(PyObject *); mp->readonly = 1;
mp++;
slotoffset += sizeof(PyObject *);
}
if (add_weak) {
type->tp_weaklistoffset = slotoffset;
mp->name = "__weakref__";
mp->type = T_OBJECT;
mp->offset = slotoffset;
mp->readonly = 1;
mp++;
slotoffset += sizeof(PyObject *);
}
} }
type->tp_basicsize = slotoffset; type->tp_basicsize = slotoffset;
type->tp_members = et->members; type->tp_members = et->members;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment