Branch data Line data Source code
1 : : #include "parts.h"
2 : : #include <stddef.h> // offsetof
3 : :
4 : :
5 : : /* Test PEP 590 - Vectorcall */
6 : :
7 : : static int
8 : 368 : fastcall_args(PyObject *args, PyObject ***stack, Py_ssize_t *nargs)
9 : : {
10 [ + + ]: 368 : if (args == Py_None) {
11 : 84 : *stack = NULL;
12 : 84 : *nargs = 0;
13 : : }
14 [ + - ]: 284 : else if (PyTuple_Check(args)) {
15 : 284 : *stack = ((PyTupleObject *)args)->ob_item;
16 : 284 : *nargs = PyTuple_GET_SIZE(args);
17 : : }
18 : : else {
19 : 0 : PyErr_SetString(PyExc_TypeError, "args must be None or a tuple");
20 : 0 : return -1;
21 : : }
22 : 368 : return 0;
23 : : }
24 : :
25 : :
26 : : static PyObject *
27 : 69 : test_pyobject_fastcall(PyObject *self, PyObject *args)
28 : : {
29 : : PyObject *func, *func_args;
30 : : PyObject **stack;
31 : : Py_ssize_t nargs;
32 : :
33 [ - + ]: 69 : if (!PyArg_ParseTuple(args, "OO", &func, &func_args)) {
34 : 0 : return NULL;
35 : : }
36 : :
37 [ - + ]: 69 : if (fastcall_args(func_args, &stack, &nargs) < 0) {
38 : 0 : return NULL;
39 : : }
40 : 69 : return _PyObject_FastCall(func, stack, nargs);
41 : : }
42 : :
43 : : static PyObject *
44 : 103 : test_pyobject_fastcalldict(PyObject *self, PyObject *args)
45 : : {
46 : : PyObject *func, *func_args, *kwargs;
47 : : PyObject **stack;
48 : : Py_ssize_t nargs;
49 : :
50 [ - + ]: 103 : if (!PyArg_ParseTuple(args, "OOO", &func, &func_args, &kwargs)) {
51 : 0 : return NULL;
52 : : }
53 : :
54 [ - + ]: 103 : if (fastcall_args(func_args, &stack, &nargs) < 0) {
55 : 0 : return NULL;
56 : : }
57 : :
58 [ + + ]: 103 : if (kwargs == Py_None) {
59 : 69 : kwargs = NULL;
60 : : }
61 [ - + ]: 34 : else if (!PyDict_Check(kwargs)) {
62 : 0 : PyErr_SetString(PyExc_TypeError, "kwnames must be None or a dict");
63 : 0 : return NULL;
64 : : }
65 : :
66 : 103 : return PyObject_VectorcallDict(func, stack, nargs, kwargs);
67 : : }
68 : :
69 : : static PyObject *
70 : 196 : test_pyobject_vectorcall(PyObject *self, PyObject *args)
71 : : {
72 : 196 : PyObject *func, *func_args, *kwnames = NULL;
73 : : PyObject **stack;
74 : : Py_ssize_t nargs, nkw;
75 : :
76 [ - + ]: 196 : if (!PyArg_ParseTuple(args, "OOO", &func, &func_args, &kwnames)) {
77 : 0 : return NULL;
78 : : }
79 : :
80 [ - + ]: 196 : if (fastcall_args(func_args, &stack, &nargs) < 0) {
81 : 0 : return NULL;
82 : : }
83 : :
84 [ + + ]: 196 : if (kwnames == Py_None) {
85 : 79 : kwnames = NULL;
86 : : }
87 [ + - ]: 117 : else if (PyTuple_Check(kwnames)) {
88 : 117 : nkw = PyTuple_GET_SIZE(kwnames);
89 [ - + ]: 117 : if (nargs < nkw) {
90 : 0 : PyErr_SetString(PyExc_ValueError, "kwnames longer than args");
91 : 0 : return NULL;
92 : : }
93 : 117 : nargs -= nkw;
94 : : }
95 : : else {
96 : 0 : PyErr_SetString(PyExc_TypeError, "kwnames must be None or a tuple");
97 : 0 : return NULL;
98 : : }
99 : 196 : return PyObject_Vectorcall(func, stack, nargs, kwnames);
100 : : }
101 : :
102 : : static PyObject *
103 : 16 : test_pyvectorcall_call(PyObject *self, PyObject *args)
104 : : {
105 : : PyObject *func;
106 : : PyObject *argstuple;
107 : 16 : PyObject *kwargs = NULL;
108 : :
109 [ - + ]: 16 : if (!PyArg_ParseTuple(args, "OO|O", &func, &argstuple, &kwargs)) {
110 : 0 : return NULL;
111 : : }
112 : :
113 [ - + ]: 16 : if (!PyTuple_Check(argstuple)) {
114 : 0 : PyErr_SetString(PyExc_TypeError, "args must be a tuple");
115 : 0 : return NULL;
116 : : }
117 [ + + - + ]: 16 : if (kwargs != NULL && !PyDict_Check(kwargs)) {
118 : 0 : PyErr_SetString(PyExc_TypeError, "kwargs must be a dict");
119 : 0 : return NULL;
120 : : }
121 : :
122 : 16 : return PyVectorcall_Call(func, argstuple, kwargs);
123 : : }
124 : :
125 : : static PyMethodDef TestMethods[] = {
126 : : {"pyobject_fastcall", test_pyobject_fastcall, METH_VARARGS},
127 : : {"pyobject_fastcalldict", test_pyobject_fastcalldict, METH_VARARGS},
128 : : {"pyobject_vectorcall", test_pyobject_vectorcall, METH_VARARGS},
129 : : {"pyvectorcall_call", test_pyvectorcall_call, METH_VARARGS},
130 : : {NULL},
131 : : };
132 : :
133 : :
134 : : typedef struct {
135 : : PyObject_HEAD
136 : : vectorcallfunc vectorcall;
137 : : } MethodDescriptorObject;
138 : :
139 : : static PyObject *
140 : 46 : MethodDescriptor_vectorcall(PyObject *callable, PyObject *const *args,
141 : : size_t nargsf, PyObject *kwnames)
142 : : {
143 : : /* True if using the vectorcall function in MethodDescriptorObject
144 : : * but False for MethodDescriptor2Object */
145 : 46 : MethodDescriptorObject *md = (MethodDescriptorObject *)callable;
146 : 46 : return PyBool_FromLong(md->vectorcall != NULL);
147 : : }
148 : :
149 : : static PyObject *
150 : 6 : MethodDescriptor_new(PyTypeObject* type, PyObject* args, PyObject *kw)
151 : : {
152 : 6 : MethodDescriptorObject *op = (MethodDescriptorObject *)type->tp_alloc(type, 0);
153 : 6 : op->vectorcall = MethodDescriptor_vectorcall;
154 : 6 : return (PyObject *)op;
155 : : }
156 : :
157 : : static PyObject *
158 : 0 : func_descr_get(PyObject *func, PyObject *obj, PyObject *type)
159 : : {
160 [ # # # # ]: 0 : if (obj == Py_None || obj == NULL) {
161 : 0 : Py_INCREF(func);
162 : 0 : return func;
163 : : }
164 : 0 : return PyMethod_New(func, obj);
165 : : }
166 : :
167 : : static PyObject *
168 : 0 : nop_descr_get(PyObject *func, PyObject *obj, PyObject *type)
169 : : {
170 : 0 : Py_INCREF(func);
171 : 0 : return func;
172 : : }
173 : :
174 : : static PyObject *
175 : 1 : call_return_args(PyObject *self, PyObject *args, PyObject *kwargs)
176 : : {
177 : 1 : Py_INCREF(args);
178 : 1 : return args;
179 : : }
180 : :
181 : : static PyTypeObject MethodDescriptorBase_Type = {
182 : : PyVarObject_HEAD_INIT(NULL, 0)
183 : : "MethodDescriptorBase",
184 : : sizeof(MethodDescriptorObject),
185 : : .tp_new = MethodDescriptor_new,
186 : : .tp_call = PyVectorcall_Call,
187 : : .tp_vectorcall_offset = offsetof(MethodDescriptorObject, vectorcall),
188 : : .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
189 : : Py_TPFLAGS_METHOD_DESCRIPTOR | Py_TPFLAGS_HAVE_VECTORCALL,
190 : : .tp_descr_get = func_descr_get,
191 : : };
192 : :
193 : : static PyTypeObject MethodDescriptorDerived_Type = {
194 : : PyVarObject_HEAD_INIT(NULL, 0)
195 : : "MethodDescriptorDerived",
196 : : .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
197 : : };
198 : :
199 : : static PyTypeObject MethodDescriptorNopGet_Type = {
200 : : PyVarObject_HEAD_INIT(NULL, 0)
201 : : "MethodDescriptorNopGet",
202 : : .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
203 : : .tp_call = call_return_args,
204 : : .tp_descr_get = nop_descr_get,
205 : : };
206 : :
207 : : typedef struct {
208 : : MethodDescriptorObject base;
209 : : vectorcallfunc vectorcall;
210 : : } MethodDescriptor2Object;
211 : :
212 : : static PyObject *
213 : 1 : MethodDescriptor2_new(PyTypeObject* type, PyObject* args, PyObject *kw)
214 : : {
215 : 1 : MethodDescriptor2Object *op = PyObject_New(MethodDescriptor2Object, type);
216 : 1 : op->base.vectorcall = NULL;
217 : 1 : op->vectorcall = MethodDescriptor_vectorcall;
218 : 1 : return (PyObject *)op;
219 : : }
220 : :
221 : : static PyTypeObject MethodDescriptor2_Type = {
222 : : PyVarObject_HEAD_INIT(NULL, 0)
223 : : "MethodDescriptor2",
224 : : sizeof(MethodDescriptor2Object),
225 : : .tp_new = MethodDescriptor2_new,
226 : : .tp_call = PyVectorcall_Call,
227 : : .tp_vectorcall_offset = offsetof(MethodDescriptor2Object, vectorcall),
228 : : .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL,
229 : : };
230 : :
231 : :
232 : : int
233 : 1170 : _PyTestCapi_Init_Vectorcall(PyObject *m) {
234 [ - + ]: 1170 : if (PyModule_AddFunctions(m, TestMethods) < 0) {
235 : 0 : return -1;
236 : : }
237 : :
238 [ - + ]: 1170 : if (PyType_Ready(&MethodDescriptorBase_Type) < 0) {
239 : 0 : return -1;
240 : : }
241 [ - + ]: 1170 : if (PyModule_AddType(m, &MethodDescriptorBase_Type) < 0) {
242 : 0 : return -1;
243 : : }
244 : :
245 : 1170 : MethodDescriptorDerived_Type.tp_base = &MethodDescriptorBase_Type;
246 [ - + ]: 1170 : if (PyType_Ready(&MethodDescriptorDerived_Type) < 0) {
247 : 0 : return -1;
248 : : }
249 [ - + ]: 1170 : if (PyModule_AddType(m, &MethodDescriptorDerived_Type) < 0) {
250 : 0 : return -1;
251 : : }
252 : :
253 : 1170 : MethodDescriptorNopGet_Type.tp_base = &MethodDescriptorBase_Type;
254 [ - + ]: 1170 : if (PyType_Ready(&MethodDescriptorNopGet_Type) < 0) {
255 : 0 : return -1;
256 : : }
257 [ - + ]: 1170 : if (PyModule_AddType(m, &MethodDescriptorNopGet_Type) < 0) {
258 : 0 : return -1;
259 : : }
260 : :
261 : 1170 : MethodDescriptor2_Type.tp_base = &MethodDescriptorBase_Type;
262 [ - + ]: 1170 : if (PyType_Ready(&MethodDescriptor2_Type) < 0) {
263 : 0 : return -1;
264 : : }
265 [ - + ]: 1170 : if (PyModule_AddType(m, &MethodDescriptor2_Type) < 0) {
266 : 0 : return -1;
267 : : }
268 : :
269 : 1170 : return 0;
270 : : }
|