Skip to content

Commit 6c39835

Browse files
committed
Don't make METH_METHOD functions a separate Python type
Instead, PyCFunction_Type is made variable, so it can hold PyCMethodObject (or any future extensions) directly. (This is similar to how PyType_Type handles the need for extra storage.)
1 parent 36a0a9f commit 6c39835

File tree

4 files changed

+9
-28
lines changed

4 files changed

+9
-28
lines changed

Include/cpython/methodobject.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
# error "this header file must not be included directly"
33
#endif
44

5-
PyAPI_DATA(PyTypeObject) PyCMethod_Type;
6-
75
/* Macros for direct access to these values. Type checks are *not*
86
done, so use with care. */
97
#define PyCFunction_GET_FUNCTION(func) \
@@ -18,7 +16,7 @@ PyAPI_DATA(PyTypeObject) PyCMethod_Type;
1816
((PyCMethodObject *)func) -> mm_class : NULL)
1917

2018
typedef struct {
21-
PyObject_HEAD
19+
PyObject_VAR_HEAD
2220
PyMethodDef *m_ml; /* Description of the C function to call */
2321
PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */
2422
PyObject *m_module; /* The __module__ attribute, can be anything */

Include/methodobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ extern "C" {
1313

1414
PyAPI_DATA(PyTypeObject) PyCFunction_Type;
1515

16-
#define PyCFunction_Check(op) (Py_IS_TYPE(op, &PyCFunction_Type) || (PyType_IsSubtype(Py_TYPE(op), &PyCFunction_Type)))
16+
#define PyCFunction_Check(op) Py_IS_TYPE(op, &PyCFunction_Type)
1717

1818
typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
1919
typedef PyObject *(*_PyCFunctionFast) (PyObject *, PyObject *const *, Py_ssize_t);

Lib/test/test_sys.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1117,7 +1117,7 @@ def test_objecttypes(self):
11171117
# buffer
11181118
# XXX
11191119
# builtin_function_or_method
1120-
check(len, size('5P'))
1120+
check(len, vsize('5P'))
11211121
# bytearray
11221122
samples = [b'', b'u'*100000]
11231123
for sample in samples:

Objects/methodobject.c

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,10 @@ PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *c
8484
"flag but no class");
8585
return NULL;
8686
}
87-
PyCMethodObject *om = PyObject_GC_New(PyCMethodObject, &PyCMethod_Type);
87+
PyCMethodObject *om = PyObject_GC_NewVar(
88+
PyCMethodObject,
89+
&PyCFunction_Type,
90+
sizeof(PyCMethodObject) - sizeof(PyCFunctionObject));
8891
if (om == NULL) {
8992
return NULL;
9093
}
@@ -99,7 +102,7 @@ PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *c
99102
return NULL;
100103
}
101104
else {
102-
op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type);
105+
op = PyObject_GC_NewVar(PyCFunctionObject, &PyCFunction_Type, 0);
103106
if (op == NULL)
104107
return NULL;
105108
}
@@ -334,7 +337,7 @@ PyTypeObject PyCFunction_Type = {
334337
PyVarObject_HEAD_INIT(&PyType_Type, 0)
335338
"builtin_function_or_method",
336339
sizeof(PyCFunctionObject),
337-
0,
340+
1,
338341
(destructor)meth_dealloc, /* tp_dealloc */
339342
offsetof(PyCFunctionObject, vectorcall), /* tp_vectorcall_offset */
340343
0, /* tp_getattr */
@@ -366,26 +369,6 @@ PyTypeObject PyCFunction_Type = {
366369
0, /* tp_dict */
367370
};
368371

369-
PyTypeObject PyCMethod_Type = {
370-
PyVarObject_HEAD_INIT(&PyType_Type, 0)
371-
.tp_name = "builtin_c_method",
372-
.tp_basicsize = sizeof(PyCMethodObject),
373-
.tp_dealloc = (destructor)meth_dealloc,
374-
.tp_repr = (reprfunc)meth_repr,
375-
.tp_hash = (hashfunc)meth_hash,
376-
.tp_call = cfunction_call,
377-
.tp_getattro = PyObject_GenericGetAttr,
378-
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
379-
.tp_traverse = (traverseproc)meth_traverse,
380-
.tp_richcompare = meth_richcompare,
381-
.tp_weaklistoffset = offsetof(PyCFunctionObject, m_weakreflist),
382-
.tp_methods = meth_methods,
383-
.tp_members = meth_members,
384-
.tp_getset = meth_getsets,
385-
.tp_base = &PyCFunction_Type,
386-
.tp_vectorcall_offset = offsetof(PyCFunctionObject, vectorcall),
387-
};
388-
389372
/* Vectorcall functions for each of the PyCFunction calling conventions,
390373
* except for METH_VARARGS (possibly combined with METH_KEYWORDS) which
391374
* doesn't use vectorcall.

0 commit comments

Comments
 (0)