|
| 1 | +#include"parts.h" |
| 2 | +#include<stddef.h>// offsetof |
| 3 | + |
| 4 | + |
| 5 | +/* Test PEP 590 - Vectorcall */ |
| 6 | + |
| 7 | +staticint |
| 8 | +fastcall_args(PyObject*args,PyObject***stack,Py_ssize_t*nargs) |
| 9 | +{ |
| 10 | +if (args==Py_None) { |
| 11 | +*stack=NULL; |
| 12 | +*nargs=0; |
| 13 | + } |
| 14 | +elseif (PyTuple_Check(args)) { |
| 15 | +*stack= ((PyTupleObject*)args)->ob_item; |
| 16 | +*nargs=PyTuple_GET_SIZE(args); |
| 17 | + } |
| 18 | +else { |
| 19 | +PyErr_SetString(PyExc_TypeError,"args must be None or a tuple"); |
| 20 | +return-1; |
| 21 | + } |
| 22 | +return0; |
| 23 | +} |
| 24 | + |
| 25 | + |
| 26 | +staticPyObject* |
| 27 | +test_pyobject_fastcall(PyObject*self,PyObject*args) |
| 28 | +{ |
| 29 | +PyObject*func,*func_args; |
| 30 | +PyObject**stack; |
| 31 | +Py_ssize_tnargs; |
| 32 | + |
| 33 | +if (!PyArg_ParseTuple(args,"OO",&func,&func_args)) { |
| 34 | +returnNULL; |
| 35 | + } |
| 36 | + |
| 37 | +if (fastcall_args(func_args,&stack,&nargs)<0) { |
| 38 | +returnNULL; |
| 39 | + } |
| 40 | +return_PyObject_FastCall(func,stack,nargs); |
| 41 | +} |
| 42 | + |
| 43 | +staticPyObject* |
| 44 | +test_pyobject_fastcalldict(PyObject*self,PyObject*args) |
| 45 | +{ |
| 46 | +PyObject*func,*func_args,*kwargs; |
| 47 | +PyObject**stack; |
| 48 | +Py_ssize_tnargs; |
| 49 | + |
| 50 | +if (!PyArg_ParseTuple(args,"OOO",&func,&func_args,&kwargs)) { |
| 51 | +returnNULL; |
| 52 | + } |
| 53 | + |
| 54 | +if (fastcall_args(func_args,&stack,&nargs)<0) { |
| 55 | +returnNULL; |
| 56 | + } |
| 57 | + |
| 58 | +if (kwargs==Py_None) { |
| 59 | +kwargs=NULL; |
| 60 | + } |
| 61 | +elseif (!PyDict_Check(kwargs)) { |
| 62 | +PyErr_SetString(PyExc_TypeError,"kwnames must be None or a dict"); |
| 63 | +returnNULL; |
| 64 | + } |
| 65 | + |
| 66 | +returnPyObject_VectorcallDict(func,stack,nargs,kwargs); |
| 67 | +} |
| 68 | + |
| 69 | +staticPyObject* |
| 70 | +test_pyobject_vectorcall(PyObject*self,PyObject*args) |
| 71 | +{ |
| 72 | +PyObject*func,*func_args,*kwnames=NULL; |
| 73 | +PyObject**stack; |
| 74 | +Py_ssize_tnargs,nkw; |
| 75 | + |
| 76 | +if (!PyArg_ParseTuple(args,"OOO",&func,&func_args,&kwnames)) { |
| 77 | +returnNULL; |
| 78 | + } |
| 79 | + |
| 80 | +if (fastcall_args(func_args,&stack,&nargs)<0) { |
| 81 | +returnNULL; |
| 82 | + } |
| 83 | + |
| 84 | +if (kwnames==Py_None) { |
| 85 | +kwnames=NULL; |
| 86 | + } |
| 87 | +elseif (PyTuple_Check(kwnames)) { |
| 88 | +nkw=PyTuple_GET_SIZE(kwnames); |
| 89 | +if (nargs<nkw) { |
| 90 | +PyErr_SetString(PyExc_ValueError,"kwnames longer than args"); |
| 91 | +returnNULL; |
| 92 | + } |
| 93 | +nargs-=nkw; |
| 94 | + } |
| 95 | +else { |
| 96 | +PyErr_SetString(PyExc_TypeError,"kwnames must be None or a tuple"); |
| 97 | +returnNULL; |
| 98 | + } |
| 99 | +returnPyObject_Vectorcall(func,stack,nargs,kwnames); |
| 100 | +} |
| 101 | + |
| 102 | +staticPyObject* |
| 103 | +test_pyvectorcall_call(PyObject*self,PyObject*args) |
| 104 | +{ |
| 105 | +PyObject*func; |
| 106 | +PyObject*argstuple; |
| 107 | +PyObject*kwargs=NULL; |
| 108 | + |
| 109 | +if (!PyArg_ParseTuple(args,"OO|O",&func,&argstuple,&kwargs)) { |
| 110 | +returnNULL; |
| 111 | + } |
| 112 | + |
| 113 | +if (!PyTuple_Check(argstuple)) { |
| 114 | +PyErr_SetString(PyExc_TypeError,"args must be a tuple"); |
| 115 | +returnNULL; |
| 116 | + } |
| 117 | +if (kwargs!=NULL&& !PyDict_Check(kwargs)) { |
| 118 | +PyErr_SetString(PyExc_TypeError,"kwargs must be a dict"); |
| 119 | +returnNULL; |
| 120 | + } |
| 121 | + |
| 122 | +returnPyVectorcall_Call(func,argstuple,kwargs); |
| 123 | +} |
| 124 | + |
| 125 | +staticPyMethodDefTestMethods[]= { |
| 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 | +typedefstruct { |
| 135 | +PyObject_HEAD |
| 136 | +vectorcallfuncvectorcall; |
| 137 | +}MethodDescriptorObject; |
| 138 | + |
| 139 | +staticPyObject* |
| 140 | +MethodDescriptor_vectorcall(PyObject*callable,PyObject*const*args, |
| 141 | +size_tnargsf,PyObject*kwnames) |
| 142 | +{ |
| 143 | +/* True if using the vectorcall function in MethodDescriptorObject |
| 144 | + * but False for MethodDescriptor2Object */ |
| 145 | +MethodDescriptorObject*md= (MethodDescriptorObject*)callable; |
| 146 | +returnPyBool_FromLong(md->vectorcall!=NULL); |
| 147 | +} |
| 148 | + |
| 149 | +staticPyObject* |
| 150 | +MethodDescriptor_new(PyTypeObject*type,PyObject*args,PyObject*kw) |
| 151 | +{ |
| 152 | +MethodDescriptorObject*op= (MethodDescriptorObject*)type->tp_alloc(type,0); |
| 153 | +op->vectorcall=MethodDescriptor_vectorcall; |
| 154 | +return (PyObject*)op; |
| 155 | +} |
| 156 | + |
| 157 | +staticPyObject* |
| 158 | +func_descr_get(PyObject*func,PyObject*obj,PyObject*type) |
| 159 | +{ |
| 160 | +if (obj==Py_None||obj==NULL) { |
| 161 | +Py_INCREF(func); |
| 162 | +returnfunc; |
| 163 | + } |
| 164 | +returnPyMethod_New(func,obj); |
| 165 | +} |
| 166 | + |
| 167 | +staticPyObject* |
| 168 | +nop_descr_get(PyObject*func,PyObject*obj,PyObject*type) |
| 169 | +{ |
| 170 | +Py_INCREF(func); |
| 171 | +returnfunc; |
| 172 | +} |
| 173 | + |
| 174 | +staticPyObject* |
| 175 | +call_return_args(PyObject*self,PyObject*args,PyObject*kwargs) |
| 176 | +{ |
| 177 | +Py_INCREF(args); |
| 178 | +returnargs; |
| 179 | +} |
| 180 | + |
| 181 | +staticPyTypeObjectMethodDescriptorBase_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 | +staticPyTypeObjectMethodDescriptorDerived_Type= { |
| 194 | +PyVarObject_HEAD_INIT(NULL,0) |
| 195 | +"MethodDescriptorDerived", |
| 196 | + .tp_flags=Py_TPFLAGS_DEFAULT |Py_TPFLAGS_BASETYPE, |
| 197 | +}; |
| 198 | + |
| 199 | +staticPyTypeObjectMethodDescriptorNopGet_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 | +typedefstruct { |
| 208 | +MethodDescriptorObjectbase; |
| 209 | +vectorcallfuncvectorcall; |
| 210 | +}MethodDescriptor2Object; |
| 211 | + |
| 212 | +staticPyObject* |
| 213 | +MethodDescriptor2_new(PyTypeObject*type,PyObject*args,PyObject*kw) |
| 214 | +{ |
| 215 | +MethodDescriptor2Object*op=PyObject_New(MethodDescriptor2Object,type); |
| 216 | +op->base.vectorcall=NULL; |
| 217 | +op->vectorcall=MethodDescriptor_vectorcall; |
| 218 | +return (PyObject*)op; |
| 219 | +} |
| 220 | + |
| 221 | +staticPyTypeObjectMethodDescriptor2_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 | +_PyTestCapi_Init_Vectorcall(PyObject*m) { |
| 234 | +if (PyModule_AddFunctions(m,TestMethods)<0) { |
| 235 | +return-1; |
| 236 | + } |
| 237 | + |
| 238 | +if (PyType_Ready(&MethodDescriptorBase_Type)<0) { |
| 239 | +return-1; |
| 240 | + } |
| 241 | +if (PyModule_AddType(m,&MethodDescriptorBase_Type)<0) { |
| 242 | +return-1; |
| 243 | + } |
| 244 | + |
| 245 | +MethodDescriptorDerived_Type.tp_base=&MethodDescriptorBase_Type; |
| 246 | +if (PyType_Ready(&MethodDescriptorDerived_Type)<0) { |
| 247 | +return-1; |
| 248 | + } |
| 249 | +if (PyModule_AddType(m,&MethodDescriptorDerived_Type)<0) { |
| 250 | +return-1; |
| 251 | + } |
| 252 | + |
| 253 | +MethodDescriptorNopGet_Type.tp_base=&MethodDescriptorBase_Type; |
| 254 | +if (PyType_Ready(&MethodDescriptorNopGet_Type)<0) { |
| 255 | +return-1; |
| 256 | + } |
| 257 | +if (PyModule_AddType(m,&MethodDescriptorNopGet_Type)<0) { |
| 258 | +return-1; |
| 259 | + } |
| 260 | + |
| 261 | +MethodDescriptor2_Type.tp_base=&MethodDescriptorBase_Type; |
| 262 | +if (PyType_Ready(&MethodDescriptor2_Type)<0) { |
| 263 | +return-1; |
| 264 | + } |
| 265 | +if (PyModule_AddType(m,&MethodDescriptor2_Type)<0) { |
| 266 | +return-1; |
| 267 | + } |
| 268 | + |
| 269 | +return0; |
| 270 | +} |