[3.8] bpo-36974: separate vectorcall functions for each calling conve… · python/cpython@bf8e82f (original) (raw)
`@@ -226,80 +226,199 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
`
226
226
`return -1;
`
227
227
`}
`
228
228
``
229
``
`-
static PyObject *
`
230
``
`-
methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
`
231
``
`-
{
`
232
``
`-
Py_ssize_t nargs;
`
233
``
`-
PyObject *self, *result;
`
234
229
``
235
``
`-
/* Make sure that the first argument is acceptable as 'self' */
`
236
``
`-
assert(PyTuple_Check(args));
`
237
``
`-
nargs = PyTuple_GET_SIZE(args);
`
``
230
`+
/* Vectorcall functions for each of the PyMethodDescr calling conventions.
`
``
231
`+
`
``
232
`+
- First, common helpers
`
``
233
`+
*/
`
``
234
`+
static const char *
`
``
235
`+
get_name(PyObject *func) {
`
``
236
`+
assert(PyObject_TypeCheck(func, &PyMethodDescr_Type));
`
``
237
`+
return ((PyMethodDescrObject *)func)->d_method->ml_name;
`
``
238
`+
}
`
``
239
+
``
240
`+
typedef void (*funcptr)(void);
`
``
241
+
``
242
`+
static inline int
`
``
243
`+
method_check_args(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
`
``
244
`+
{
`
``
245
`+
assert(!PyErr_Occurred());
`
``
246
`+
assert(PyObject_TypeCheck(func, &PyMethodDescr_Type));
`
238
247
`if (nargs < 1) {
`
239
248
`PyErr_Format(PyExc_TypeError,
`
240
``
`-
"descriptor '%V' of '%.100s' "
`
``
249
`+
"descriptor '%.200s' of '%.100s' "
`
241
250
`"object needs an argument",
`
242
``
`-
descr_name((PyDescrObject *)descr), "?",
`
243
``
`-
PyDescr_TYPE(descr)->tp_name);
`
244
``
`-
return NULL;
`
``
251
`+
get_name(func), PyDescr_TYPE(func)->tp_name);
`
``
252
`+
return -1;
`
245
253
` }
`
246
``
`-
self = PyTuple_GET_ITEM(args, 0);
`
``
254
`+
PyObject *self = args[0];
`
247
255
`if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
`
248
``
`-
(PyObject *)PyDescr_TYPE(descr))) {
`
``
256
`+
(PyObject *)PyDescr_TYPE(func)))
`
``
257
`+
{
`
249
258
`PyErr_Format(PyExc_TypeError,
`
250
``
`-
"descriptor '%V' for '%.100s' objects "
`
``
259
`+
"descriptor '%.200s' for '%.100s' objects "
`
251
260
`"doesn't apply to a '%.100s' object",
`
252
``
`-
descr_name((PyDescrObject *)descr), "?",
`
253
``
`-
PyDescr_TYPE(descr)->tp_name,
`
254
``
`-
self->ob_type->tp_name);
`
``
261
`+
get_name(func), PyDescr_TYPE(func)->tp_name,
`
``
262
`+
Py_TYPE(self)->tp_name);
`
``
263
`+
return -1;
`
``
264
`+
}
`
``
265
`+
if (kwnames && PyTuple_GET_SIZE(kwnames)) {
`
``
266
`+
PyErr_Format(PyExc_TypeError,
`
``
267
`+
"%.200s() takes no keyword arguments", get_name(func));
`
``
268
`+
return -1;
`
``
269
`+
}
`
``
270
`+
return 0;
`
``
271
`+
}
`
``
272
+
``
273
`+
static inline funcptr
`
``
274
`+
method_enter_call(PyObject *func)
`
``
275
`+
{
`
``
276
`+
if (Py_EnterRecursiveCall(" while calling a Python object")) {
`
255
277
`return NULL;
`
256
278
` }
`
``
279
`+
return (funcptr)((PyMethodDescrObject *)func)->d_method->ml_meth;
`
``
280
`+
}
`
257
281
``
258
``
`-
result = _PyMethodDef_RawFastCallDict(descr->d_method, self,
`
259
``
`-
&_PyTuple_ITEMS(args)[1], nargs - 1,
`
260
``
`-
kwargs);
`
261
``
`-
result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
`
``
282
`+
/* Now the actual vectorcall functions */
`
``
283
`+
static PyObject *
`
``
284
`+
method_vectorcall_VARARGS(
`
``
285
`+
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
`
``
286
`+
{
`
``
287
`+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
`
``
288
`+
if (method_check_args(func, args, nargs, kwnames)) {
`
``
289
`+
return NULL;
`
``
290
`+
}
`
``
291
`+
PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1);
`
``
292
`+
if (argstuple == NULL) {
`
``
293
`+
return NULL;
`
``
294
`+
}
`
``
295
`+
PyCFunction meth = (PyCFunction)method_enter_call(func);
`
``
296
`+
if (meth == NULL) {
`
``
297
`+
Py_DECREF(argstuple);
`
``
298
`+
return NULL;
`
``
299
`+
}
`
``
300
`+
PyObject *result = meth(args[0], argstuple);
`
``
301
`+
Py_DECREF(argstuple);
`
``
302
`+
Py_LeaveRecursiveCall();
`
262
303
`return result;
`
263
304
`}
`
264
305
``
265
``
`-
// same to methoddescr_call(), but use FASTCALL convention.
`
266
``
`-
PyObject *
`
267
``
`-
_PyMethodDescr_Vectorcall(PyObject *descrobj,
`
268
``
`-
PyObject *const *args, size_t nargsf,
`
269
``
`-
PyObject *kwnames)
`
``
306
`+
static PyObject *
`
``
307
`+
method_vectorcall_VARARGS_KEYWORDS(
`
``
308
`+
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
`
270
309
`{
`
271
``
`-
assert(Py_TYPE(descrobj) == &PyMethodDescr_Type);
`
272
``
`-
PyMethodDescrObject *descr = (PyMethodDescrObject *)descrobj;
`
273
``
`-
PyObject *self, *result;
`
``
310
`+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
`
``
311
`+
if (method_check_args(func, args, nargs, NULL)) {
`
``
312
`+
return NULL;
`
``
313
`+
}
`
``
314
`+
PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1);
`
``
315
`+
if (argstuple == NULL) {
`
``
316
`+
return NULL;
`
``
317
`+
}
`
``
318
`+
PyObject *result = NULL;
`
``
319
`+
/* Create a temporary dict for keyword arguments */
`
``
320
`+
PyObject *kwdict = NULL;
`
``
321
`+
if (kwnames != NULL && PyTuple_GET_SIZE(kwnames) > 0) {
`
``
322
`+
kwdict = _PyStack_AsDict(args + nargs, kwnames);
`
``
323
`+
if (kwdict == NULL) {
`
``
324
`+
goto exit;
`
``
325
`+
}
`
``
326
`+
}
`
``
327
`+
PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords)
`
``
328
`+
method_enter_call(func);
`
``
329
`+
if (meth == NULL) {
`
``
330
`+
goto exit;
`
``
331
`+
}
`
``
332
`+
result = meth(args[0], argstuple, kwdict);
`
``
333
`+
Py_LeaveRecursiveCall();
`
``
334
`+
exit:
`
``
335
`+
Py_DECREF(argstuple);
`
``
336
`+
Py_XDECREF(kwdict);
`
``
337
`+
return result;
`
``
338
`+
}
`
274
339
``
``
340
`+
static PyObject *
`
``
341
`+
method_vectorcall_FASTCALL(
`
``
342
`+
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
`
``
343
`+
{
`
275
344
`Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
`
276
``
`-
/* Make sure that the first argument is acceptable as 'self' */
`
277
``
`-
if (nargs < 1) {
`
278
``
`-
PyErr_Format(PyExc_TypeError,
`
279
``
`-
"descriptor '%V' of '%.100s' "
`
280
``
`-
"object needs an argument",
`
281
``
`-
descr_name((PyDescrObject *)descr), "?",
`
282
``
`-
PyDescr_TYPE(descr)->tp_name);
`
``
345
`+
if (method_check_args(func, args, nargs, kwnames)) {
`
283
346
`return NULL;
`
284
347
` }
`
285
``
`-
self = args[0];
`
286
``
`-
if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
`
287
``
`-
(PyObject *)PyDescr_TYPE(descr))) {
`
``
348
`+
_PyCFunctionFast meth = (_PyCFunctionFast)
`
``
349
`+
method_enter_call(func);
`
``
350
`+
if (meth == NULL) {
`
``
351
`+
return NULL;
`
``
352
`+
}
`
``
353
`+
PyObject *result = meth(args[0], args+1, nargs-1);
`
``
354
`+
Py_LeaveRecursiveCall();
`
``
355
`+
return result;
`
``
356
`+
}
`
``
357
+
``
358
`+
static PyObject *
`
``
359
`+
method_vectorcall_FASTCALL_KEYWORDS(
`
``
360
`+
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
`
``
361
`+
{
`
``
362
`+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
`
``
363
`+
if (method_check_args(func, args, nargs, NULL)) {
`
``
364
`+
return NULL;
`
``
365
`+
}
`
``
366
`+
_PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)
`
``
367
`+
method_enter_call(func);
`
``
368
`+
if (meth == NULL) {
`
``
369
`+
return NULL;
`
``
370
`+
}
`
``
371
`+
PyObject *result = meth(args[0], args+1, nargs-1, kwnames);
`
``
372
`+
Py_LeaveRecursiveCall();
`
``
373
`+
return result;
`
``
374
`+
}
`
``
375
+
``
376
`+
static PyObject *
`
``
377
`+
method_vectorcall_NOARGS(
`
``
378
`+
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
`
``
379
`+
{
`
``
380
`+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
`
``
381
`+
if (method_check_args(func, args, nargs, kwnames)) {
`
``
382
`+
return NULL;
`
``
383
`+
}
`
``
384
`+
if (nargs != 1) {
`
288
385
`PyErr_Format(PyExc_TypeError,
`
289
``
`-
"descriptor '%V' for '%.100s' objects "
`
290
``
`-
"doesn't apply to a '%.100s' object",
`
291
``
`-
descr_name((PyDescrObject *)descr), "?",
`
292
``
`-
PyDescr_TYPE(descr)->tp_name,
`
293
``
`-
self->ob_type->tp_name);
`
``
386
`+
"%.200s() takes no arguments (%zd given)", get_name(func), nargs-1);
`
294
387
`return NULL;
`
295
388
` }
`
``
389
`+
PyCFunction meth = (PyCFunction)method_enter_call(func);
`
``
390
`+
if (meth == NULL) {
`
``
391
`+
return NULL;
`
``
392
`+
}
`
``
393
`+
PyObject *result = meth(args[0], NULL);
`
``
394
`+
Py_LeaveRecursiveCall();
`
``
395
`+
return result;
`
``
396
`+
}
`
296
397
``
297
``
`-
result = _PyMethodDef_RawFastCallKeywords(descr->d_method, self,
`
298
``
`-
args+1, nargs-1, kwnames);
`
299
``
`-
result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
`
``
398
`+
static PyObject *
`
``
399
`+
method_vectorcall_O(
`
``
400
`+
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
`
``
401
`+
{
`
``
402
`+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
`
``
403
`+
if (method_check_args(func, args, nargs, kwnames)) {
`
``
404
`+
return NULL;
`
``
405
`+
}
`
``
406
`+
if (nargs != 2) {
`
``
407
`+
PyErr_Format(PyExc_TypeError,
`
``
408
`+
"%.200s() takes exactly one argument (%zd given)",
`
``
409
`+
get_name(func), nargs-1);
`
``
410
`+
return NULL;
`
``
411
`+
}
`
``
412
`+
PyCFunction meth = (PyCFunction)method_enter_call(func);
`
``
413
`+
if (meth == NULL) {
`
``
414
`+
return NULL;
`
``
415
`+
}
`
``
416
`+
PyObject *result = meth(args[0], args[1]);
`
``
417
`+
Py_LeaveRecursiveCall();
`
300
418
`return result;
`
301
419
`}
`
302
420
``
``
421
+
303
422
`static PyObject *
`
304
423
`classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
`
305
424
`PyObject *kwds)
`
`@@ -552,7 +671,7 @@ PyTypeObject PyMethodDescr_Type = {
`
552
671
`0, /* tp_as_sequence */
`
553
672
`0, /* tp_as_mapping */
`
554
673
`0, /* tp_hash */
`
555
``
`-
(ternaryfunc)methoddescr_call, /* tp_call */
`
``
674
`+
PyVectorcall_Call, /* tp_call */
`
556
675
`0, /* tp_str */
`
557
676
`PyObject_GenericGetAttr, /* tp_getattro */
`
558
677
`0, /* tp_setattro */
`
`@@ -750,13 +869,40 @@ descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)
`
750
869
`PyObject *
`
751
870
`PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
`
752
871
`{
`
``
872
`+
/* Figure out correct vectorcall function to use */
`
``
873
`+
vectorcallfunc vectorcall;
`
``
874
`+
switch (method->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS))
`
``
875
`+
{
`
``
876
`+
case METH_VARARGS:
`
``
877
`+
vectorcall = method_vectorcall_VARARGS;
`
``
878
`+
break;
`
``
879
`+
case METH_VARARGS | METH_KEYWORDS:
`
``
880
`+
vectorcall = method_vectorcall_VARARGS_KEYWORDS;
`
``
881
`+
break;
`
``
882
`+
case METH_FASTCALL:
`
``
883
`+
vectorcall = method_vectorcall_FASTCALL;
`
``
884
`+
break;
`
``
885
`+
case METH_FASTCALL | METH_KEYWORDS:
`
``
886
`+
vectorcall = method_vectorcall_FASTCALL_KEYWORDS;
`
``
887
`+
break;
`
``
888
`+
case METH_NOARGS:
`
``
889
`+
vectorcall = method_vectorcall_NOARGS;
`
``
890
`+
break;
`
``
891
`+
case METH_O:
`
``
892
`+
vectorcall = method_vectorcall_O;
`
``
893
`+
break;
`
``
894
`+
default:
`
``
895
`+
PyErr_SetString(PyExc_SystemError, "bad call flags");
`
``
896
`+
return NULL;
`
``
897
`+
}
`
``
898
+
753
899
`PyMethodDescrObject *descr;
`
754
900
``
755
901
`descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
`
756
902
`type, method->ml_name);
`
757
903
`if (descr != NULL) {
`
758
904
`descr->d_method = method;
`
759
``
`-
descr->vectorcall = _PyMethodDescr_Vectorcall;
`
``
905
`+
descr->vectorcall = vectorcall;
`
760
906
` }
`
761
907
`return (PyObject *)descr;
`
762
908
`}
`