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

Commit b9e886b

Browse files
authored
Stackless issue #270: Remove duplicated code
Eliminate duplicated code in ceval.c to improve maintainability. Update changelog.txt.
1 parent 31671f7 commit b9e886b

File tree

2 files changed

+79
-132
lines changed

2 files changed

+79
-132
lines changed

Python/ceval.c

Lines changed: 75 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -671,10 +671,11 @@ do { \
671671

672672
#endif
673673

674-
PyObject* _Py_HOT_FUNCTION
675674
#ifdef STACKLESS
676-
slp_eval_frame_value(PyFrameObject *f, int throwflag, PyObject *retval)
675+
static PyObject* _Py_HOT_FUNCTION
676+
slp_eval_frame_value(PyFrameObject *f, int throwflag, PyObject *retval_arg)
677677
#else
678+
PyObject* _Py_HOT_FUNCTION
678679
_PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
679680
#endif
680681
{
@@ -686,9 +687,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
686687
int opcode; /* Current opcode */
687688
int oparg; /* Current opcode argument, if any */
688689
PyObject **fastlocals, **freevars;
689-
#ifndef STACKLESS
690690
PyObject *retval = NULL; /* Return value */
691-
#endif
692691
PyThreadState *tstate = _PyThreadState_GET();
693692
PyCodeObject *co;
694693

@@ -968,10 +967,8 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
968967
Py_XDECREF(traceback); \
969968
} while(0)
970969

971-
/* Stackless specific defines start here.. */
970+
/* Stackless specific macros and code start here. */
972971
#ifdef STACKLESS
973-
int executing = f->f_executing;
974-
975972
#define SLP_CHECK_INTERRUPT() \
976973
if (tstate->st.interrupt && !tstate->curexc_type) { \
977974
if (tstate->st.tick_counter > tstate->st.tick_watermark) { \
@@ -989,6 +986,19 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
989986
} \
990987
tstate->st.tick_counter++;
991988

989+
int executing = f->f_executing;
990+
assert(executing != SLP_FRAME_EXECUTING_INVALID);
991+
if (executing != SLP_FRAME_EXECUTING_NO) {
992+
goto slp_setup_completed;
993+
}
994+
995+
/* push frame */
996+
if (Py_EnterRecursiveCall("")) {
997+
Py_XDECREF(retval_arg);
998+
SLP_STORE_NEXT_FRAME(tstate, f->f_back);
999+
return NULL;
1000+
}
1001+
9921002
#else
9931003
#define SLP_CHECK_INTERRUPT() ;
9941004

@@ -997,11 +1007,8 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
9971007
/* push frame */
9981008
if (Py_EnterRecursiveCall(""))
9991009
return NULL;
1010+
#endif
10001011

1001-
/* STACKLESS:
1002-
* the code starting from here on until the end-marker
1003-
* is duplicated below. Keep the two copies in sync!
1004-
*/
10051012
tstate->frame = f;
10061013

10071014
if (tstate->use_tracing) {
@@ -1037,10 +1044,10 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
10371044
}
10381045
}
10391046
}
1040-
/* STACKLESS: end of duplicated code
1041-
*/
1042-
1043-
#endif /* #ifdef STACKLESS */
1047+
#ifdef STACKLESS
1048+
executing = SLP_FRAME_EXECUTING_NOVAL;
1049+
slp_setup_completed:
1050+
#endif
10441051

10451052
if (PyDTrace_FUNCTION_ENTRY_ENABLED())
10461053
dtrace_function_entry(f);
@@ -1086,14 +1093,14 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
10861093
lltrace = _PyDict_GetItemId(f->f_globals, &PyId___ltrace__) != NULL;
10871094
#endif
10881095

1089-
if (throwflag) { /* support for generator.throw() */
1090-
assert(retval == NULL); /* to prevent reference leaks */
1096+
if (throwflag) /* support for generator.throw() */
10911097
goto error;
1092-
}
1093-
10941098

10951099
#ifdef STACKLESS
10961100
assert(f->f_executing == SLP_FRAME_EXECUTING_VALUE);
1101+
assert(retval == NULL);
1102+
retval = retval_arg;
1103+
retval_arg = NULL;
10971104
switch(executing){
10981105
case SLP_FRAME_EXECUTING_NOVAL:
10991106
/* don't push it, frame ignores value */
@@ -2026,12 +2033,14 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
20262033
STACKLESS_ASSERT();
20272034
} else {
20282035
_Py_IDENTIFIER(send);
2029-
if (v == Py_None) {
2036+
if (v == Py_None)
2037+
{
20302038
STACKLESS_PROPOSE_METHOD(tstate, receiver, tp_iternext);
20312039
retval = Py_TYPE(receiver)->tp_iternext(receiver);
20322040
STACKLESS_ASSERT();
20332041
}
2034-
else {
2042+
else
2043+
{
20352044
STACKLESS_PROPOSE_ALL(tstate);
20362045
retval = _PyObject_CallMethodIdObjArgs(receiver, &PyId_send, v, NULL);
20372046
STACKLESS_ASSERT();
@@ -2043,7 +2052,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
20432052
HANDLE_UNWINDING(SLP_FRAME_EXECUTING_YIELD_FROM, 0, retval);
20442053
}
20452054
if (0) {
2046-
slp_continue_slp_eval_frame_yield_from:
2055+
slp_continue_slp_eval_frame_yield_from:
20472056
/* Initialize variables */
20482057
receiver = TOP();
20492058
}
@@ -3132,7 +3141,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
31323141
HANDLE_UNWINDING(SLP_FRAME_EXECUTING_ITER, 1, next);
31333142
}
31343143
if (0) {
3135-
slp_continue_slp_eval_frame_iter:
3144+
slp_continue_slp_eval_frame_iter:
31363145
SLP_SET_OPCODE_AND_OPARG();
31373146
assert(opcode == FOR_ITER);
31383147

@@ -3234,7 +3243,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
32343243
HANDLE_UNWINDING(SLP_FRAME_EXECUTING_SETUP_WITH, 1, res);
32353244
}
32363245
if(0) {
3237-
slp_continue_slp_eval_frame_setup_with:
3246+
slp_continue_slp_eval_frame_setup_with:
32383247
SLP_SET_OPCODE_AND_OPARG();
32393248
assert(opcode == SETUP_WITH);
32403249
/* Initialize variables */
@@ -3323,7 +3332,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
33233332
HANDLE_UNWINDING(SLP_FRAME_EXECUTING_WITH_CLEANUP, 0, res);
33243333
}
33253334
if (0) {
3326-
slp_continue_slp_eval_frame_with_cleanup:
3335+
slp_continue_slp_eval_frame_with_cleanup:
33273336
/* Initialize variables */
33283337
exc = TOP();
33293338
if (exc == NULL)
@@ -3549,6 +3558,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
35493558
Py_DECREF(func);
35503559
Py_DECREF(callargs);
35513560
Py_XDECREF(kwargs);
3561+
35523562
#ifdef STACKLESS
35533563
if (STACKLESS_UNWINDING(result)) {
35543564
(void) POP(); /* top of stack causes a GC related assertion error */
@@ -3798,29 +3808,24 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
37983808
}
37993809

38003810
/* pop frame */
3801-
/* exit_eval_frame: */
3802-
#ifndef STACKLESS
38033811
exit_eval_frame:
38043812
if (PyDTrace_FUNCTION_RETURN_ENABLED())
38053813
dtrace_function_return(f);
38063814
Py_LeaveRecursiveCall();
38073815
f->f_executing = 0;
3808-
tstate->frame = f->f_back;
3809-
3810-
return _Py_CheckFunctionResult(NULL, retval, "PyEval_EvalFrameEx");
3811-
3812-
#else
3813-
if (PyDTrace_FUNCTION_RETURN_ENABLED())
3814-
dtrace_function_return(f);
3815-
Py_LeaveRecursiveCall();
3816-
f->f_executing = 0;
3816+
#ifdef STACKLESS
38173817
SLP_STORE_NEXT_FRAME(tstate, f->f_back);
3818+
Py_CLEAR(retval_arg);
3819+
#else
3820+
tstate->frame = f->f_back;
3821+
#endif
38183822

38193823
return _Py_CheckFunctionResult(NULL, retval, "PyEval_EvalFrameEx");
38203824

3821-
3825+
#ifdef STACKLESS
38223826
stackless_interrupt_call:
38233827
/* interrupted during unwinding */
3828+
assert(retval_arg == NULL);
38243829
assert(f->f_executing == SLP_FRAME_EXECUTING_VALUE);
38253830
f->f_executing = SLP_FRAME_EXECUTING_NOVAL;
38263831
f->f_stacktop = stack_pointer;
@@ -3888,6 +3893,38 @@ handle_unwinding(int lineno, PyFrameObject *f,
38883893
return 0;
38893894
}
38903895

3896+
PyObject*
3897+
PyEval_EvalFrameEx_slp(PyFrameObject *f, int throwflag, PyObject *retval_arg)
3898+
{
3899+
PyThreadState *tstate = _PyThreadState_GET();
3900+
int executing = f->f_executing;
3901+
if (executing == SLP_FRAME_EXECUTING_INVALID) {
3902+
--tstate->recursion_depth;
3903+
return slp_cannot_execute((PyCFrameObject *)f, "PyEval_EvalFrameEx_slp", retval_arg);
3904+
} else if (executing == SLP_FRAME_EXECUTING_NO) {
3905+
/* Processing of a frame starts here */
3906+
3907+
/* Check, if an extension module has changed tstate->interp->eval_frame.
3908+
* PEP 523 defines this function pointer as an API to customise the frame
3909+
* evaluation. Stackless can not support this API. In order to prevent
3910+
* undefined behavior, we terminate the interpreter.
3911+
*/
3912+
if (tstate->interp->eval_frame != _PyEval_EvalFrameDefault)
3913+
Py_FatalError("An extension module has set a custom frame evaluation function (see PEP 523).\n"
3914+
"Stackless Python does not support the frame evaluation API defined by PEP 523.\n"
3915+
"The programm now terminates to prevent undefined behavior.\n");
3916+
3917+
if (SLP_CSTACK_SAVE_NOW(tstate, f)) {
3918+
/* Setup the C-stack and recursively call PyEval_EvalFrameEx_slp with the same arguments.
3919+
* SLP_CSTACK_SAVE_NOW(tstate, f) will be false then.
3920+
*/
3921+
return slp_eval_frame_newstack(f, throwflag, retval_arg);
3922+
}
3923+
}
3924+
return slp_eval_frame_value(f, throwflag, retval_arg);
3925+
}
3926+
3927+
38913928
static PyObject *
38923929
run_frame_dispatch(PyCFrameObject *cf, int exc, PyObject *retval)
38933930
{
@@ -4000,98 +4037,6 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
40004037
assert(SLP_CURRENT_FRAME_IS_VALID(tstate));
40014038
return retval;
40024039
}
4003-
4004-
PyObject * _Py_HOT_FUNCTION
4005-
PyEval_EvalFrameEx_slp(PyFrameObject *f, int throwflag, PyObject *retval)
4006-
{
4007-
if (f->f_executing == SLP_FRAME_EXECUTING_INVALID) {
4008-
PyThreadState *tstate = _PyThreadState_GET();
4009-
--tstate->recursion_depth;
4010-
return slp_cannot_execute((PyCFrameObject *)f, "PyEval_EvalFrameEx_slp", retval);
4011-
} else if (f->f_executing != SLP_FRAME_EXECUTING_NO) {
4012-
return slp_eval_frame_value(f, throwflag, retval);
4013-
}
4014-
4015-
PyThreadState *tstate = _PyThreadState_GET();
4016-
4017-
/* Check, if an extension module has changed tstate->interp->eval_frame.
4018-
* PEP 523 defines this function pointer as an API to customise the frame
4019-
* evaluation. Stackless can not support this API. In order to prevent
4020-
* undefined behavior, we terminate the interpreter.
4021-
*/
4022-
if (tstate->interp->eval_frame != _PyEval_EvalFrameDefault)
4023-
Py_FatalError("An extension module has set a custom frame evaluation function (see PEP 523).\n"
4024-
"Stackless Python does not support the frame evaluation API defined by PEP 523.\n"
4025-
"The programm now terminates to prevent undefined behavior.\n");
4026-
4027-
/* Start of code, similar to non stackless
4028-
* PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
4029-
*/
4030-
4031-
if (SLP_CSTACK_SAVE_NOW(tstate, f))
4032-
return slp_eval_frame_newstack(f, throwflag, retval);
4033-
4034-
/* push frame */
4035-
if (Py_EnterRecursiveCall("")) {
4036-
Py_XDECREF(retval);
4037-
SLP_STORE_NEXT_FRAME(tstate, f->f_back);
4038-
return NULL;
4039-
}
4040-
4041-
/* STACKLESS:
4042-
* the code starting from here on until the end-marker
4043-
* is a copy of code above. Keep the two copies in sync!
4044-
*/
4045-
tstate->frame = f;
4046-
4047-
if (tstate->use_tracing) {
4048-
if (tstate->c_tracefunc != NULL) {
4049-
/* tstate->c_tracefunc, if defined, is a
4050-
function that will be called on *every* entry
4051-
to a code block. Its return value, if not
4052-
None, is a function that will be called at
4053-
the start of each executed line of code.
4054-
(Actually, the function must return itself
4055-
in order to continue tracing.) The trace
4056-
functions are called with three arguments:
4057-
a pointer to the current frame, a string
4058-
indicating why the function is called, and
4059-
an argument which depends on the situation.
4060-
The global trace function is also called
4061-
whenever an exception is detected. */
4062-
if (call_trace_protected(tstate->c_tracefunc,
4063-
tstate->c_traceobj,
4064-
tstate, f, PyTrace_CALL, Py_None)) {
4065-
/* Trace function raised an error */
4066-
goto exit_eval_frame;
4067-
}
4068-
}
4069-
if (tstate->c_profilefunc != NULL) {
4070-
/* Similar for c_profilefunc, except it needn't
4071-
return itself and isn't called for "line" events */
4072-
if (call_trace_protected(tstate->c_profilefunc,
4073-
tstate->c_profileobj,
4074-
tstate, f, PyTrace_CALL, Py_None)) {
4075-
/* Profile function raised an error */
4076-
goto exit_eval_frame;
4077-
}
4078-
}
4079-
}
4080-
/* STACKLESS: end of duplicated code
4081-
*/
4082-
4083-
4084-
f->f_executing = SLP_FRAME_EXECUTING_NOVAL;
4085-
return slp_eval_frame_value(f, throwflag, retval);
4086-
exit_eval_frame:
4087-
Py_XDECREF(retval);
4088-
if (PyDTrace_FUNCTION_RETURN_ENABLED())
4089-
dtrace_function_return(f);
4090-
Py_LeaveRecursiveCall();
4091-
f->f_executing = SLP_FRAME_EXECUTING_NO;
4092-
SLP_STORE_NEXT_FRAME(tstate, f->f_back);
4093-
return NULL;
4094-
}
40954040
#endif /* #ifdef STACKLESS */
40964041

40974042

@@ -4288,7 +4233,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
42884233
if (f == NULL) {
42894234
return NULL;
42904235
}
4291-
42924236
fastlocals = f->f_localsplus;
42934237
freevars = f->f_localsplus + co->co_nlocals;
42944238

@@ -5076,7 +5020,7 @@ PyObject *
50765020
PyEval_GetGlobals(void)
50775021
{
50785022
PyFrameObject *current_frame = PyEval_GetFrame();
5079-
#if 1 && defined STACKLESS
5023+
#ifdef STACKLESS
50805024
if (current_frame == NULL) {
50815025
PyThreadState *ts = _PyThreadState_GET();
50825026

Stackless/changelog.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ What's New in Stackless 3.X.X?
1010
*Release date: 20XX-XX-XX*
1111

1212
- https://github.com/stackless-dev/stackless/issues/270
13-
Stackless now uses an unmodified PyFrameObject structure.
13+
Stackless now uses an unmodified PyFrameObject structure. Stackless now
14+
stores more state information in the field f->f_executing than C-Python.
15+
If an extension module modifies f->f_executing, undefined behavior can occur.
16+
Reading the field as boolean still works.
1417

1518
- https://github.com/stackless-dev/stackless/issues/269
1619
A failure to unpickle a frame could cause a NULL pointer access when

0 commit comments

Comments
 (0)