Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit a4e657f

Browse files
Anselm KruisAnselm Kruis
Anselm Kruis
authored and
Anselm Kruis
committed
Stackless issue #254: bpo-36974: separate vectorcall functions for each calling convention
Adapt Stackless to upstream commit bf8e82f.
1 parent edfb267 commit a4e657f

File tree

4 files changed

+103
-29
lines changed

4 files changed

+103
-29
lines changed

Include/internal/pycore_stackless.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,7 @@ slp_cstack_set_base_and_goodgap(PyThreadState *tstate, const void * pstackvar, P
837837
#define SLP_PEEK_NEXT_FRAME(tstate) \
838838
((tstate)->frame)
839839

840+
#define _PyStackless_TRY_STACKLESS 0
840841
#define STACKLESS_PROMOTE_WRAPPER(descr) assert(1)
841842

842843
#define STACKLESS_PROPOSE(tstate, func) assert(1)

Objects/descrobject.c

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,18 @@ method_check_args(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObj
271271
return 0;
272272
}
273273

274+
#ifdef STACKLESS
275+
static int
276+
get_stackless(PyObject *func) {
277+
assert(PyObject_TypeCheck(func, &PyMethodDescr_Type));
278+
return ((PyMethodDescrObject *)func)->d_method->ml_flags & METH_STACKLESS;
279+
}
280+
#endif
281+
274282
static inline funcptr
275-
method_enter_call(PyObject *func)
283+
method_enter_call(PyObject *func, int stackless)
276284
{
277-
if (Py_EnterRecursiveCall(" while calling a Python object")) {
285+
if (!stackless && Py_EnterRecursiveCall(" while calling a Python object")) {
278286
return NULL;
279287
}
280288
return (funcptr)((PyMethodDescrObject *)func)->d_method->ml_meth;
@@ -285,6 +293,7 @@ static PyObject *
285293
method_vectorcall_VARARGS(
286294
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
287295
{
296+
STACKLESS_VECTORCALL_GETARG(method_vectorcall_VARARGS);
288297
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
289298
if (method_check_args(func, args, nargs, kwnames)) {
290299
return NULL;
@@ -293,21 +302,27 @@ method_vectorcall_VARARGS(
293302
if (argstuple == NULL) {
294303
return NULL;
295304
}
296-
PyCFunction meth = (PyCFunction)method_enter_call(func);
305+
STACKLESS_PROMOTE_FLAG(get_stackless(func));
306+
stackless = !!_PyStackless_TRY_STACKLESS; /* reuse variable stackless */
307+
PyCFunction meth = (PyCFunction)method_enter_call(func, stackless);
297308
if (meth == NULL) {
309+
STACKLESS_RETRACT();
298310
Py_DECREF(argstuple);
299311
return NULL;
300312
}
301313
PyObject *result = meth(args[0], argstuple);
314+
STACKLESS_ASSERT();
302315
Py_DECREF(argstuple);
303-
Py_LeaveRecursiveCall();
316+
if (!stackless)
317+
Py_LeaveRecursiveCall();
304318
return result;
305319
}
306320

307321
static PyObject *
308322
method_vectorcall_VARARGS_KEYWORDS(
309323
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
310324
{
325+
STACKLESS_VECTORCALL_GETARG(method_vectorcall_VARARGS_KEYWORDS);
311326
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
312327
if (method_check_args(func, args, nargs, NULL)) {
313328
return NULL;
@@ -325,13 +340,18 @@ method_vectorcall_VARARGS_KEYWORDS(
325340
goto exit;
326341
}
327342
}
343+
STACKLESS_PROMOTE_FLAG(get_stackless(func));
344+
stackless = !!_PyStackless_TRY_STACKLESS; /* reuse variable stackless */
328345
PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords)
329-
method_enter_call(func);
346+
method_enter_call(func, stackless);
330347
if (meth == NULL) {
348+
STACKLESS_RETRACT();
331349
goto exit;
332350
}
333351
result = meth(args[0], argstuple, kwdict);
334-
Py_LeaveRecursiveCall();
352+
STACKLESS_ASSERT();
353+
if(!stackless)
354+
Py_LeaveRecursiveCall();
335355
exit:
336356
Py_DECREF(argstuple);
337357
Py_XDECREF(kwdict);
@@ -342,42 +362,55 @@ static PyObject *
342362
method_vectorcall_FASTCALL(
343363
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
344364
{
365+
STACKLESS_VECTORCALL_GETARG(method_vectorcall_FASTCALL);
345366
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
346367
if (method_check_args(func, args, nargs, kwnames)) {
347368
return NULL;
348369
}
370+
STACKLESS_PROMOTE_FLAG(get_stackless(func));
371+
stackless = !!_PyStackless_TRY_STACKLESS; /* reuse variable stackless */
349372
_PyCFunctionFast meth = (_PyCFunctionFast)
350-
method_enter_call(func);
373+
method_enter_call(func, stackless);
351374
if (meth == NULL) {
375+
STACKLESS_RETRACT();
352376
return NULL;
353377
}
354378
PyObject *result = meth(args[0], args+1, nargs-1);
355-
Py_LeaveRecursiveCall();
379+
STACKLESS_ASSERT();
380+
if(!stackless)
381+
Py_LeaveRecursiveCall();
356382
return result;
357383
}
358384

359385
static PyObject *
360386
method_vectorcall_FASTCALL_KEYWORDS(
361387
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
362388
{
389+
STACKLESS_VECTORCALL_GETARG(method_vectorcall_FASTCALL_KEYWORDS);
363390
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
364391
if (method_check_args(func, args, nargs, NULL)) {
365392
return NULL;
366393
}
394+
STACKLESS_PROMOTE_FLAG(get_stackless(func));
395+
stackless = !!_PyStackless_TRY_STACKLESS; /* reuse variable stackless */
367396
_PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)
368-
method_enter_call(func);
397+
method_enter_call(func, stackless);
369398
if (meth == NULL) {
399+
STACKLESS_RETRACT();
370400
return NULL;
371401
}
372402
PyObject *result = meth(args[0], args+1, nargs-1, kwnames);
373-
Py_LeaveRecursiveCall();
403+
STACKLESS_ASSERT();
404+
if(!stackless)
405+
Py_LeaveRecursiveCall();
374406
return result;
375407
}
376408

377409
static PyObject *
378410
method_vectorcall_NOARGS(
379411
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
380412
{
413+
STACKLESS_VECTORCALL_GETARG(method_vectorcall_NOARGS);
381414
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
382415
if (method_check_args(func, args, nargs, kwnames)) {
383416
return NULL;
@@ -387,19 +420,25 @@ method_vectorcall_NOARGS(
387420
"%.200s() takes no arguments (%zd given)", get_name(func), nargs-1);
388421
return NULL;
389422
}
390-
PyCFunction meth = (PyCFunction)method_enter_call(func);
423+
STACKLESS_PROMOTE_FLAG(get_stackless(func));
424+
stackless = !!_PyStackless_TRY_STACKLESS; /* reuse variable stackless */
425+
PyCFunction meth = (PyCFunction)method_enter_call(func, stackless);
391426
if (meth == NULL) {
427+
STACKLESS_RETRACT();
392428
return NULL;
393429
}
394430
PyObject *result = meth(args[0], NULL);
395-
Py_LeaveRecursiveCall();
431+
STACKLESS_ASSERT();
432+
if(!stackless)
433+
Py_LeaveRecursiveCall();
396434
return result;
397435
}
398436

399437
static PyObject *
400438
method_vectorcall_O(
401439
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
402440
{
441+
STACKLESS_VECTORCALL_GETARG(method_vectorcall_O);
403442
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
404443
if (method_check_args(func, args, nargs, kwnames)) {
405444
return NULL;
@@ -410,12 +449,17 @@ method_vectorcall_O(
410449
get_name(func), nargs-1);
411450
return NULL;
412451
}
413-
PyCFunction meth = (PyCFunction)method_enter_call(func);
452+
STACKLESS_PROMOTE_FLAG(get_stackless(func));
453+
stackless = !!_PyStackless_TRY_STACKLESS; /* reuse variable stackless */
454+
PyCFunction meth = (PyCFunction)method_enter_call(func, stackless);
414455
if (meth == NULL) {
456+
STACKLESS_RETRACT();
415457
return NULL;
416458
}
417459
PyObject *result = meth(args[0], args[1]);
418-
Py_LeaveRecursiveCall();
460+
STACKLESS_ASSERT();
461+
if(!stackless)
462+
Py_LeaveRecursiveCall();
419463
return result;
420464
}
421465

Objects/methodobject.c

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -403,10 +403,18 @@ cfunction_check_kwargs(PyObject *func, PyObject *kwnames)
403403
return 0;
404404
}
405405

406+
#ifdef STACKLESS
407+
static int
408+
cfunction_get_stackless(PyObject *func) {
409+
assert(PyCFunction_Check(func));
410+
return ((PyCFunctionObject *)func)->m_ml->ml_flags & METH_STACKLESS;
411+
}
412+
#endif
413+
406414
static inline funcptr
407-
cfunction_enter_call(PyObject *func)
415+
cfunction_enter_call(PyObject *func, int stackless)
408416
{
409-
if (Py_EnterRecursiveCall(" while calling a Python object")) {
417+
if (!stackless && Py_EnterRecursiveCall(" while calling a Python object")) {
410418
return NULL;
411419
}
412420
return (funcptr)PyCFunction_GET_FUNCTION(func);
@@ -417,39 +425,52 @@ static PyObject *
417425
cfunction_vectorcall_FASTCALL(
418426
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
419427
{
428+
STACKLESS_VECTORCALL_GETARG(cfunction_vectorcall_FASTCALL);
420429
if (cfunction_check_kwargs(func, kwnames)) {
421430
return NULL;
422431
}
423432
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
433+
STACKLESS_PROMOTE_FLAG(cfunction_get_stackless(func));
434+
stackless = !!_PyStackless_TRY_STACKLESS; /* reuse variable stackless */
424435
_PyCFunctionFast meth = (_PyCFunctionFast)
425-
cfunction_enter_call(func);
436+
cfunction_enter_call(func, stackless);
426437
if (meth == NULL) {
438+
STACKLESS_RETRACT();
427439
return NULL;
428440
}
429441
PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs);
430-
Py_LeaveRecursiveCall();
442+
STACKLESS_ASSERT();
443+
if (!stackless)
444+
Py_LeaveRecursiveCall();
431445
return result;
432446
}
433447

434448
static PyObject *
435449
cfunction_vectorcall_FASTCALL_KEYWORDS(
436450
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
437451
{
452+
STACKLESS_VECTORCALL_GETARG(cfunction_vectorcall_FASTCALL_KEYWORDS);
438453
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
454+
STACKLESS_PROMOTE_FLAG(cfunction_get_stackless(func));
455+
stackless = !!_PyStackless_TRY_STACKLESS; /* reuse variable stackless */
439456
_PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)
440-
cfunction_enter_call(func);
457+
cfunction_enter_call(func, stackless);
441458
if (meth == NULL) {
459+
STACKLESS_RETRACT();
442460
return NULL;
443461
}
444462
PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs, kwnames);
445-
Py_LeaveRecursiveCall();
463+
STACKLESS_ASSERT();
464+
if (!stackless)
465+
Py_LeaveRecursiveCall();
446466
return result;
447467
}
448468

449469
static PyObject *
450470
cfunction_vectorcall_NOARGS(
451471
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
452472
{
473+
STACKLESS_VECTORCALL_GETARG(cfunction_vectorcall_NOARGS);
453474
if (cfunction_check_kwargs(func, kwnames)) {
454475
return NULL;
455476
}
@@ -459,19 +480,25 @@ cfunction_vectorcall_NOARGS(
459480
"%.200s() takes no arguments (%zd given)", get_name(func), nargs);
460481
return NULL;
461482
}
462-
PyCFunction meth = (PyCFunction)cfunction_enter_call(func);
483+
STACKLESS_PROMOTE_FLAG(cfunction_get_stackless(func));
484+
stackless = !!_PyStackless_TRY_STACKLESS; /* reuse variable stackless */
485+
PyCFunction meth = (PyCFunction)cfunction_enter_call(func, stackless);
463486
if (meth == NULL) {
487+
STACKLESS_RETRACT();
464488
return NULL;
465489
}
466490
PyObject *result = meth(PyCFunction_GET_SELF(func), NULL);
467-
Py_LeaveRecursiveCall();
491+
STACKLESS_ASSERT();
492+
if (!stackless)
493+
Py_LeaveRecursiveCall();
468494
return result;
469495
}
470496

471497
static PyObject *
472498
cfunction_vectorcall_O(
473499
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
474500
{
501+
STACKLESS_VECTORCALL_GETARG(cfunction_vectorcall_O);
475502
if (cfunction_check_kwargs(func, kwnames)) {
476503
return NULL;
477504
}
@@ -482,11 +509,16 @@ cfunction_vectorcall_O(
482509
get_name(func), nargs);
483510
return NULL;
484511
}
485-
PyCFunction meth = (PyCFunction)cfunction_enter_call(func);
512+
STACKLESS_PROMOTE_FLAG(cfunction_get_stackless(func));
513+
stackless = !!_PyStackless_TRY_STACKLESS; /* reuse variable stackless */
514+
PyCFunction meth = (PyCFunction)cfunction_enter_call(func, stackless);
486515
if (meth == NULL) {
516+
STACKLESS_RETRACT();
487517
return NULL;
488518
}
489519
PyObject *result = meth(PyCFunction_GET_SELF(func), args[0]);
490-
Py_LeaveRecursiveCall();
520+
STACKLESS_ASSERT();
521+
if (!stackless)
522+
Py_LeaveRecursiveCall();
491523
return result;
492524
}

Python/ceval.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5479,10 +5479,7 @@ trace_call_function(PyThreadState *tstate,
54795479
{
54805480
PyObject *x;
54815481
if (PyCFunction_Check(func)) {
5482-
STACKLESS_GETARG();
5483-
STACKLESS_VECTORCALL_BEFORE(_PyCFunction_Vectorcall);
54845482
C_TRACE(x, _PyObject_Vectorcall(func, args, nargs, kwnames));
5485-
STACKLESS_VECTORCALL_AFTER(_PyCFunction_Vectorcall);
54865483
return x;
54875484
}
54885485
else if (Py_TYPE(func) == &PyMethodDescr_Type && nargs > 0) {
@@ -5499,11 +5496,11 @@ trace_call_function(PyThreadState *tstate,
54995496
if (func == NULL) {
55005497
return NULL;
55015498
}
5502-
STACKLESS_VECTORCALL_BEFORE(_PyCFunction_Vectorcall);
5499+
STACKLESS_PROMOTE_ALL();
55035500
C_TRACE(x, _PyObject_Vectorcall(func,
55045501
args+1, nargs-1,
55055502
kwnames));
5506-
STACKLESS_VECTORCALL_AFTER(_PyCFunction_Vectorcall);
5503+
STACKLESS_ASSERT();
55075504
Py_DECREF(func);
55085505
return x;
55095506
}

0 commit comments

Comments
 (0)