From e5c691abe3946ddbaa00730b92f3b96f96903f7d Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 7 Mar 2003 15:13:17 +0000 Subject: - The extended type structure used for heap types (new-style classes defined by Python code using a class statement) is now exported from object.h as PyHeapTypeObject. (SF patch #696193.) --- Include/object.h | 22 ++++++++++++++ Misc/NEWS | 4 ++- Objects/typeobject.c | 83 +++++++++++++++++++++------------------------------- 3 files changed, 59 insertions(+), 50 deletions(-) diff --git a/Include/object.h b/Include/object.h index 5e509b4..7b93230 100644 --- a/Include/object.h +++ b/Include/object.h @@ -327,6 +327,28 @@ typedef struct _typeobject { } PyTypeObject; +/* The *real* layout of a type object when allocated on the heap */ +typedef struct _heaptypeobject { + /* Note: there's a dependency on the order of these members + in slotptr() in typeobject.c . */ + PyTypeObject type; + PyNumberMethods as_number; + PyMappingMethods as_mapping; + PySequenceMethods as_sequence; /* as_sequence comes after as_mapping, + so that the mapping wins when both + the mapping and the sequence define + a given operator (e.g. __getitem__). + see add_operators() in typeobject.c . */ + PyBufferProcs as_buffer; + PyObject *name, *slots; + /* here are optional user slots, followed by the members. */ +} PyHeapTypeObject; + +/* access macro to the members which are floating "behind" the object */ +#define PyHeapType_GET_MEMBERS(etype) \ + ((PyMemberDef *)(((char *)etype) + (etype)->type.ob_type->tp_basicsize)) + + /* Generic type check */ PyAPI_FUNC(int) PyType_IsSubtype(PyTypeObject *, PyTypeObject *); #define PyObject_TypeCheck(ob, tp) \ diff --git a/Misc/NEWS b/Misc/NEWS index 0a446df..a83e282 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -80,7 +80,9 @@ Build C API ----- -TBD +- The extended type structure used for heap types (new-style + classes defined by Python code using a class statement) is now + exported from object.h as PyHeapTypeObject. (SF patch #696193.) New platforms ------------- diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e61eae8..a067cd5 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5,24 +5,6 @@ #include -/* The *real* layout of a type object when allocated on the heap */ -/* XXX Should we publish this in a header file? */ -typedef struct { - /* Note: there's a dependency on the order of these members - in slotptr() below. */ - PyTypeObject type; - PyNumberMethods as_number; - PyMappingMethods as_mapping; - PySequenceMethods as_sequence; /* as_sequence comes after as_mapping, - so that the mapping wins when both - the mapping and the sequence define - a given operator (e.g. __getitem__). - see add_operators() below. */ - PyBufferProcs as_buffer; - PyObject *name, *slots; - PyMemberDef members[1]; -} etype; - static PyMemberDef type_members[] = { {"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY}, {"__itemsize__", T_INT, offsetof(PyTypeObject, tp_itemsize), READONLY}, @@ -42,7 +24,7 @@ type_name(PyTypeObject *type, void *context) char *s; if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { - etype* et = (etype*)type; + PyHeapTypeObject* et = (PyHeapTypeObject*)type; Py_INCREF(et->name); return et->name; @@ -60,7 +42,7 @@ type_name(PyTypeObject *type, void *context) static int type_set_name(PyTypeObject *type, PyObject *value, void *context) { - etype* et; + PyHeapTypeObject* et; if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { PyErr_Format(PyExc_TypeError, @@ -85,7 +67,7 @@ type_set_name(PyTypeObject *type, PyObject *value, void *context) return -1; } - et = (etype*)type; + et = (PyHeapTypeObject*)type; Py_INCREF(value); @@ -449,7 +431,8 @@ PyObject * PyType_GenericAlloc(PyTypeObject *type, int nitems) { PyObject *obj; - const size_t size = _PyObject_VAR_SIZE(type, nitems); + const size_t size = _PyObject_VAR_SIZE(type, nitems+1); + /* note that we need to add one, for the sentinel */ if (PyType_IS_GC(type)) obj = _PyObject_GC_Malloc(size); @@ -489,7 +472,7 @@ traverse_slots(PyTypeObject *type, PyObject *self, visitproc visit, void *arg) PyMemberDef *mp; n = type->ob_size; - mp = ((etype *)type)->members; + mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type); for (i = 0; i < n; i++, mp++) { if (mp->type == T_OBJECT_EX) { char *addr = (char *)self + mp->offset; @@ -554,7 +537,7 @@ clear_slots(PyTypeObject *type, PyObject *self) PyMemberDef *mp; n = type->ob_size; - mp = ((etype *)type)->members; + mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type); for (i = 0; i < n; i++, mp++) { if (mp->type == T_OBJECT_EX && !(mp->flags & READONLY)) { char *addr = (char *)self + mp->offset; @@ -1534,7 +1517,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) static char *kwlist[] = {"name", "bases", "dict", 0}; PyObject *slots, *tmp, *newslots; PyTypeObject *type, *base, *tmptype, *winner; - etype *et; + PyHeapTypeObject *et; PyMemberDef *mp; int i, nbases, nslots, slotoffset, add_dict, add_weak; int j, may_add_dict, may_add_weak; @@ -1649,7 +1632,8 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) /* Are slots allowed? */ nslots = PyTuple_GET_SIZE(slots); - if (nslots > 0 && base->tp_itemsize != 0) { + if (nslots > 0 && base->tp_itemsize != 0 && !PyType_Check(base)) { + /* for the special case of meta types, allow slots */ PyErr_Format(PyExc_TypeError, "nonempty __slots__ " "not supported for subtype of '%s'", @@ -1770,7 +1754,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) } /* Keep name and slots alive in the extended type object */ - et = (etype *)type; + et = (PyHeapTypeObject *)type; Py_INCREF(name); et->name = name; et->slots = slots; @@ -1850,7 +1834,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) } /* Add descriptors for custom slots from __slots__, or for __dict__ */ - mp = et->members; + mp = PyHeapType_GET_MEMBERS(et); slotoffset = base->tp_basicsize; if (slots != NULL) { for (i = 0; i < nslots; i++, mp++) { @@ -1882,7 +1866,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) } type->tp_basicsize = slotoffset; type->tp_itemsize = base->tp_itemsize; - type->tp_members = et->members; + type->tp_members = PyHeapType_GET_MEMBERS(et); if (type->tp_weaklistoffset && type->tp_dictoffset) type->tp_getset = subtype_getsets_full; @@ -2052,13 +2036,13 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) static void type_dealloc(PyTypeObject *type) { - etype *et; + PyHeapTypeObject *et; /* Assert this is a heap-allocated type object */ assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); _PyObject_GC_UNTRACK(type); PyObject_ClearWeakRefs((PyObject *)type); - et = (etype *)type; + et = (PyHeapTypeObject *)type; Py_XDECREF(type->tp_base); Py_XDECREF(type->tp_dict); Py_XDECREF(type->tp_bases); @@ -2134,7 +2118,7 @@ type_traverse(PyTypeObject *type, visitproc visit, void *arg) VISIT(type->tp_base); /* There's no need to visit type->tp_subclasses or - ((etype *)type)->slots, because they can't be involved + ((PyHeapTypeObject *)type)->slots, because they can't be involved in cycles; tp_subclasses is a list of weak references, and slots is a tuple of strings. */ @@ -2180,7 +2164,7 @@ type_clear(PyTypeObject *type) A list of weak references can't be part of a cycle; and lists have their own tp_clear. - slots (in etype): + slots (in PyHeapTypeObject): A tuple of strings can't be part of a cycle. */ @@ -2201,7 +2185,7 @@ PyTypeObject PyType_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, /* ob_size */ "type", /* tp_name */ - sizeof(etype), /* tp_basicsize */ + sizeof(PyHeapTypeObject), /* tp_basicsize */ sizeof(PyMemberDef), /* tp_itemsize */ (destructor)type_dealloc, /* tp_dealloc */ 0, /* tp_print */ @@ -4686,9 +4670,10 @@ slot_tp_del(PyObject *self) /* Table mapping __foo__ names to tp_foo offsets and slot_tp_foo wrapper - functions. The offsets here are relative to the 'etype' structure, which - incorporates the additional structures used for numbers, sequences and - mappings. Note that multiple names may map to the same slot (e.g. __eq__, + functions. The offsets here are relative to the 'PyHeapTypeObject' + structure, which incorporates the additional structures used for numbers, + sequences and mappings. + Note that multiple names may map to the same slot (e.g. __eq__, __ne__ etc. all map to tp_richcompare) and one name may map to multiple slots (e.g. __str__ affects tp_str as well as tp_repr). The table is terminated with an all-zero entry. (This table is further initialized and @@ -4714,7 +4699,7 @@ typedef struct wrapperbase slotdef; {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ PyDoc_STR(DOC), FLAGS} #define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - {NAME, offsetof(etype, SLOT), (void *)(FUNCTION), WRAPPER, \ + {NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ PyDoc_STR(DOC)} #define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ ETSLOT(NAME, as_sequence.SLOT, FUNCTION, WRAPPER, DOC) @@ -4928,20 +4913,20 @@ slotptr(PyTypeObject *type, int offset) { char *ptr; - /* Note: this depends on the order of the members of etype! */ + /* Note: this depends on the order of the members of PyHeapTypeObject! */ assert(offset >= 0); - assert(offset < offsetof(etype, as_buffer)); - if (offset >= offsetof(etype, as_sequence)) { + assert(offset < offsetof(PyHeapTypeObject, as_buffer)); + if (offset >= offsetof(PyHeapTypeObject, as_sequence)) { ptr = (void *)type->tp_as_sequence; - offset -= offsetof(etype, as_sequence); + offset -= offsetof(PyHeapTypeObject, as_sequence); } - else if (offset >= offsetof(etype, as_mapping)) { + else if (offset >= offsetof(PyHeapTypeObject, as_mapping)) { ptr = (void *)type->tp_as_mapping; - offset -= offsetof(etype, as_mapping); + offset -= offsetof(PyHeapTypeObject, as_mapping); } - else if (offset >= offsetof(etype, as_number)) { + else if (offset >= offsetof(PyHeapTypeObject, as_number)) { ptr = (void *)type->tp_as_number; - offset -= offsetof(etype, as_number); + offset -= offsetof(PyHeapTypeObject, as_number); } else { ptr = (void *)type; @@ -5216,9 +5201,9 @@ update_all_slots(PyTypeObject* type) mp_subscript generate a __getitem__ descriptor). In the latter case, the first slotdef entry encoutered wins. Since - slotdef entries are sorted by the offset of the slot in the etype - struct, this gives us some control over disambiguating between - competing slots: the members of struct etype are listed from most + slotdef entries are sorted by the offset of the slot in the + PyHeapTypeObject, this gives us some control over disambiguating + between competing slots: the members of PyHeapTypeObject are listed from most general to least general, so the most general slot is preferred. In particular, because as_mapping comes before as_sequence, for a type that defines both mp_subscript and sq_item, mp_subscript wins. -- cgit v0.12