gh-103092: Convert some `_ctypes` metatypes to heap types (GH-113620)

Co-authored-by: Erlend E. Aasland <erlend@python.org>
This commit is contained in:
AN Long 2024-01-18 23:30:27 +08:00 committed by GitHub
parent a571a2fd3f
commit 8e31cdc945
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 141 additions and 281 deletions

View File

@ -876,20 +876,6 @@ CDataType_repeat(PyObject *self, Py_ssize_t length)
return PyCArrayType_from_ctype(self, length);
}
static PySequenceMethods CDataType_as_sequence = {
0, /* inquiry sq_length; */
0, /* binaryfunc sq_concat; */
CDataType_repeat, /* intargfunc sq_repeat; */
0, /* intargfunc sq_item; */
0, /* intintargfunc sq_slice; */
0, /* intobjargproc sq_ass_item; */
0, /* intintobjargproc sq_ass_slice; */
0, /* objobjproc sq_contains; */
0, /* binaryfunc sq_inplace_concat; */
0, /* intargfunc sq_inplace_repeat; */
};
static int
CDataType_clear(PyTypeObject *self)
{
@ -903,8 +889,10 @@ static int
CDataType_traverse(PyTypeObject *self, visitproc visit, void *arg)
{
StgDictObject *dict = PyType_stgdict((PyObject *)self);
if (dict)
if (dict) {
Py_VISIT(dict->proto);
}
Py_VISIT(Py_TYPE(self));
return PyType_Type.tp_traverse((PyObject *)self, visit, arg);
}
@ -935,91 +923,45 @@ UnionType_setattro(PyObject *self, PyObject *key, PyObject *value)
return 0;
}
static PyType_Slot pycstruct_type_slots[] = {
{Py_tp_setattro, PyCStructType_setattro},
{Py_tp_doc, PyDoc_STR("metatype for the CData Objects")},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
{Py_tp_methods, CDataType_methods},
{Py_tp_new, PyCStructType_new},
PyTypeObject PyCStructType_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_ctypes.PyCStructType", /* tp_name */
0, /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
&CDataType_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyCStructType_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
PyDoc_STR("metatype for the CData Objects"), /* tp_doc */
(traverseproc)CDataType_traverse, /* tp_traverse */
(inquiry)CDataType_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
CDataType_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
PyCStructType_new, /* tp_new */
0, /* tp_free */
// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};
static PyTypeObject UnionType_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_ctypes.UnionType", /* tp_name */
0, /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
&CDataType_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
UnionType_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
PyDoc_STR("metatype for the CData Objects"), /* tp_doc */
(traverseproc)CDataType_traverse, /* tp_traverse */
(inquiry)CDataType_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
CDataType_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
UnionType_new, /* tp_new */
0, /* tp_free */
PyType_Spec pycstruct_type_spec = {
.name = "_ctypes.PyCStructType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = pycstruct_type_slots,
};
static PyType_Slot union_type_slots[] = {
{Py_tp_setattro, UnionType_setattro},
{Py_tp_doc, PyDoc_STR("metatype for the Union Objects")},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
{Py_tp_methods, CDataType_methods},
{Py_tp_new, UnionType_new},
// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};
static PyType_Spec union_type_spec = {
.name = "_ctypes.UnionType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = union_type_slots,
};
/******************************************************************/
@ -1234,46 +1176,23 @@ static PyMethodDef PyCPointerType_methods[] = {
{ NULL, NULL },
};
PyTypeObject PyCPointerType_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_ctypes.PyCPointerType", /* tp_name */
0, /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
&CDataType_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
PyDoc_STR("metatype for the Pointer Objects"), /* tp_doc */
(traverseproc)CDataType_traverse, /* tp_traverse */
(inquiry)CDataType_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PyCPointerType_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
PyCPointerType_new, /* tp_new */
0, /* tp_free */
static PyType_Slot pycpointer_type_slots[] = {
{Py_tp_doc, PyDoc_STR("metatype for the Pointer Objects")},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
{Py_tp_methods, PyCPointerType_methods},
{Py_tp_new, PyCPointerType_new},
// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};
static PyType_Spec pycpointer_type_spec = {
.name = "_ctypes.PyCPointerType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = pycpointer_type_slots,
};
@ -1606,48 +1525,24 @@ error:
return NULL;
}
PyTypeObject PyCArrayType_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_ctypes.PyCArrayType", /* tp_name */
0, /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
&CDataType_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
PyDoc_STR("metatype for the Array Objects"), /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
CDataType_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
PyCArrayType_new, /* tp_new */
0, /* tp_free */
static PyType_Slot pycarray_type_slots[] = {
{Py_tp_doc, PyDoc_STR("metatype for the Array Objects")},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_methods, CDataType_methods},
{Py_tp_new, PyCArrayType_new},
{Py_tp_clear, CDataType_clear},
// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};
static PyType_Spec pycarray_type_spec = {
.name = "_ctypes.PyCArrayType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = pycarray_type_slots,
};
/******************************************************************/
/*
@ -2175,7 +2070,11 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
}
if (type == &PyCSimpleType_Type && fmt->setfunc_swapped && fmt->getfunc_swapped) {
ctypes_state *st = GLOBAL_STATE();
if (type == st->PyCSimpleType_Type
&& fmt->setfunc_swapped
&& fmt->getfunc_swapped)
{
PyObject *swapped = CreateSwappedType(type, args, kwds,
proto, fmt);
StgDictObject *sw_dict;
@ -2292,46 +2191,23 @@ static PyMethodDef PyCSimpleType_methods[] = {
{ NULL, NULL },
};
PyTypeObject PyCSimpleType_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_ctypes.PyCSimpleType", /* tp_name */
0, /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
&CDataType_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
PyDoc_STR("metatype for the PyCSimpleType Objects"), /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PyCSimpleType_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
PyCSimpleType_new, /* tp_new */
0, /* tp_free */
static PyType_Slot pycsimple_type_slots[] = {
{Py_tp_doc, PyDoc_STR("metatype for the PyCSimpleType Objects")},
{Py_tp_methods, PyCSimpleType_methods},
{Py_tp_new, PyCSimpleType_new},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};
PyType_Spec pycsimple_type_spec = {
.name = "_ctypes.PyCSimpleType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = pycsimple_type_slots,
};
/******************************************************************/
@ -2575,46 +2451,23 @@ PyCFuncPtrType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return (PyObject *)result;
}
PyTypeObject PyCFuncPtrType_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_ctypes.PyCFuncPtrType", /* tp_name */
0, /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
&CDataType_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
PyDoc_STR("metatype for C function pointers"), /* tp_doc */
(traverseproc)CDataType_traverse, /* tp_traverse */
(inquiry)CDataType_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
CDataType_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
PyCFuncPtrType_new, /* tp_new */
0, /* tp_free */
static PyType_Slot pycfuncptr_type_slots[] = {
{Py_tp_doc, PyDoc_STR("metatype for C function pointers")},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
{Py_tp_methods, CDataType_methods},
{Py_tp_new, PyCFuncPtrType_new},
// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};
static PyType_Spec pycfuncptr_type_spec = {
.name = "_ctypes.PyCFuncPtrType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = pycfuncptr_type_slots,
};
@ -4881,7 +4734,8 @@ PyCArrayType_from_ctype(PyObject *itemtype, Py_ssize_t length)
((PyTypeObject *)itemtype)->tp_name, (long)length);
#endif
result = PyObject_CallFunction((PyObject *)&PyCArrayType_Type,
ctypes_state *st = GLOBAL_STATE();
result = PyObject_CallFunction((PyObject *)st->PyCArrayType_Type,
"s(O){s:n,s:O}",
name,
&PyCArray_Type,
@ -5690,24 +5544,29 @@ _ctypes_add_types(PyObject *mod)
*
* Metaclasses
*/
TYPE_READY_BASE(&PyCStructType_Type, &PyType_Type);
TYPE_READY_BASE(&UnionType_Type, &PyType_Type);
TYPE_READY_BASE(&PyCPointerType_Type, &PyType_Type);
TYPE_READY_BASE(&PyCArrayType_Type, &PyType_Type);
TYPE_READY_BASE(&PyCSimpleType_Type, &PyType_Type);
TYPE_READY_BASE(&PyCFuncPtrType_Type, &PyType_Type);
CREATE_TYPE(mod, st->PyCStructType_Type, &pycstruct_type_spec,
&PyType_Type);
CREATE_TYPE(mod, st->UnionType_Type, &union_type_spec, &PyType_Type);
CREATE_TYPE(mod, st->PyCPointerType_Type, &pycpointer_type_spec,
&PyType_Type);
CREATE_TYPE(mod, st->PyCArrayType_Type, &pycarray_type_spec,
&PyType_Type);
CREATE_TYPE(mod, st->PyCSimpleType_Type, &pycsimple_type_spec,
&PyType_Type);
CREATE_TYPE(mod, st->PyCFuncPtrType_Type, &pycfuncptr_type_spec,
&PyType_Type);
/*************************************************
*
* Classes using a custom metaclass
*/
MOD_ADD_TYPE(&Struct_Type, &PyCStructType_Type, &PyCData_Type);
MOD_ADD_TYPE(&Union_Type, &UnionType_Type, &PyCData_Type);
MOD_ADD_TYPE(&PyCPointer_Type, &PyCPointerType_Type, &PyCData_Type);
MOD_ADD_TYPE(&PyCArray_Type, &PyCArrayType_Type, &PyCData_Type);
MOD_ADD_TYPE(&Simple_Type, &PyCSimpleType_Type, &PyCData_Type);
MOD_ADD_TYPE(&PyCFuncPtr_Type, &PyCFuncPtrType_Type, &PyCData_Type);
MOD_ADD_TYPE(&Struct_Type, st->PyCStructType_Type, &PyCData_Type);
MOD_ADD_TYPE(&Union_Type, st->UnionType_Type, &PyCData_Type);
MOD_ADD_TYPE(&PyCPointer_Type, st->PyCPointerType_Type, &PyCData_Type);
MOD_ADD_TYPE(&PyCArray_Type, st->PyCArrayType_Type, &PyCData_Type);
MOD_ADD_TYPE(&Simple_Type, st->PyCSimpleType_Type, &PyCData_Type);
MOD_ADD_TYPE(&PyCFuncPtr_Type, st->PyCFuncPtrType_Type, &PyCData_Type);
/*************************************************
*

View File

@ -41,6 +41,12 @@ typedef struct {
PyTypeObject *PyComError_Type;
#endif
PyTypeObject *StructParam_Type;
PyTypeObject *PyCStructType_Type;
PyTypeObject *UnionType_Type;
PyTypeObject *PyCPointerType_Type;
PyTypeObject *PyCArrayType_Type;
PyTypeObject *PyCSimpleType_Type;
PyTypeObject *PyCFuncPtrType_Type;
} ctypes_state;
extern ctypes_state global_state;
@ -118,7 +124,7 @@ typedef struct {
Py_ssize_t b_size; /* size of memory block in bytes */
Py_ssize_t b_length; /* number of references we need */
Py_ssize_t b_index; /* index of this object into base's
b_object list */
b_object list */
PyObject *b_objects; /* list of references we need to keep */
union value b_value;
/* end of tagCDataObject, additional fields follow */
@ -155,9 +161,8 @@ extern PyTypeObject PyCData_Type;
#define CDataObject_Check(v) PyObject_TypeCheck(v, &PyCData_Type)
#define _CDataObject_HasExternalBuffer(v) ((v)->b_ptr != (char *)&(v)->b_value)
extern PyTypeObject PyCSimpleType_Type;
#define PyCSimpleTypeObject_CheckExact(v) Py_IS_TYPE(v, &PyCSimpleType_Type)
#define PyCSimpleTypeObject_Check(v) PyObject_TypeCheck(v, &PyCSimpleType_Type)
#define PyCSimpleTypeObject_CheckExact(v) Py_IS_TYPE(v, GLOBAL_STATE()->PyCSimpleType_Type)
#define PyCSimpleTypeObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCSimpleType_Type)
extern struct fielddesc *_ctypes_get_fielddesc(const char *fmt);
@ -171,21 +176,17 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
extern PyObject *PyCData_AtAddress(PyObject *type, void *buf);
extern PyObject *PyCData_FromBytes(PyObject *type, char *data, Py_ssize_t length);
extern PyTypeObject PyCArrayType_Type;
extern PyTypeObject PyCArray_Type;
extern PyTypeObject PyCPointerType_Type;
extern PyTypeObject PyCPointer_Type;
extern PyTypeObject PyCFuncPtr_Type;
extern PyTypeObject PyCFuncPtrType_Type;
extern PyTypeObject PyCStructType_Type;
#define PyCArrayTypeObject_Check(v) PyObject_TypeCheck(v, &PyCArrayType_Type)
#define PyCArrayTypeObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCArrayType_Type)
#define ArrayObject_Check(v) PyObject_TypeCheck(v, &PyCArray_Type)
#define PointerObject_Check(v) PyObject_TypeCheck(v, &PyCPointer_Type)
#define PyCPointerTypeObject_Check(v) PyObject_TypeCheck(v, &PyCPointerType_Type)
#define PyCPointerTypeObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCPointerType_Type)
#define PyCFuncPtrObject_Check(v) PyObject_TypeCheck(v, &PyCFuncPtr_Type)
#define PyCFuncPtrTypeObject_Check(v) PyObject_TypeCheck(v, &PyCFuncPtrType_Type)
#define PyCStructTypeObject_Check(v) PyObject_TypeCheck(v, &PyCStructType_Type)
#define PyCFuncPtrTypeObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCFuncPtrType_Type)
#define PyCStructTypeObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCStructType_Type)
extern PyObject *
PyCArrayType_from_ctype(PyObject *itemtype, Py_ssize_t length);