From 6bf82f9df88041fce6dee05bb6ae4d9c9f57c084 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Wed, 30 Jun 2021 13:56:28 +0200 Subject: [PATCH 01/11] Stackless issue #281: Refactor tasklet profiling and tracing Per tasklet profiling and tracing state information is no stored in the tasklet itself. This increases the size of tasklet objects a bit, but saves a lot of code. --- Include/cpython/slp_structs.h | 23 +- Include/internal/pycore_stackless.h | 3 - Lib/stackless.py | 2 +- Stackless/changelog.txt | 5 + Stackless/module/scheduling.c | 295 ++++++++--------------- Stackless/module/taskletobject.c | 325 ++++++++------------------ Stackless/pickling/prickelpit.c | 3 - Stackless/unittests/test_exception.py | 4 +- Stackless/unittests/test_tracing.py | 12 - Stackless/unittests/test_tstate.py | 23 +- 10 files changed, 235 insertions(+), 460 deletions(-) diff --git a/Include/cpython/slp_structs.h b/Include/cpython/slp_structs.h index e915565bbd784b..37d02cadc60a87 100644 --- a/Include/cpython/slp_structs.h +++ b/Include/cpython/slp_structs.h @@ -101,16 +101,6 @@ typedef struct _tasklet_flags { unsigned int pending_irq: SLP_TASKLET_FLAGS_BITS_pending_irq; } PyTaskletFlagStruc; -/* a partial copy of PyThreadState. Used to preserve - the state of a hard switched tasklet */ -typedef struct _tasklet_tstate { - int tracing; - Py_tracefunc c_profilefunc; - Py_tracefunc c_tracefunc; - PyObject *c_profileobj; - PyObject *c_traceobj; -} PyTaskletTStateStruc; - typedef struct _tasklet { PyObject_HEAD struct _tasklet *next; @@ -133,9 +123,20 @@ typedef struct _tasklet { int recursion_depth; PyObject *def_globals; PyObject *tsk_weakreflist; - /* If the tasklet is current: NULL. (The context of a current tasklet is always in ts->tasklet.) + /* If the tasklet is current: NULL. (The context of a current tasklet is + * always in ts->context.) * If the tasklet is not current: the context for the tasklet */ PyObject *context; + + /* If the tasklet is current: NULL. (The profile and tracing state of a + * current tasklet is stored in the thread state.) + * If the tasklet is not current: the profile and tracing state for the tasklet. + */ + Py_tracefunc profilefunc; + Py_tracefunc tracefunc; + PyObject *profileobj; + PyObject *traceobj; + int tracing; } PyTaskletObject; diff --git a/Include/internal/pycore_stackless.h b/Include/internal/pycore_stackless.h index 8562d915a2ce83..a9844ada69a392 100644 --- a/Include/internal/pycore_stackless.h +++ b/Include/internal/pycore_stackless.h @@ -380,8 +380,6 @@ PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx_slp(struct _frame *, int, PyObject *); /* eval_frame with stack overflow, triggered there with a macro */ PyObject * slp_eval_frame_newstack(struct _frame *f, int throwflag, PyObject *retval); -/* other eval_frame functions from module/scheduling.c */ -PyObject * slp_restore_tracing(PyCFrameObject *cf, int exc, PyObject *retval); /* other eval_frame functions from Objects/typeobject.c */ PyObject * slp_tp_init_callback(PyCFrameObject *cf, int exc, PyObject *retval); /* functions related to pickling */ @@ -754,7 +752,6 @@ int slp_prepare_slots(PyTypeObject*); Py_tracefunc slp_get_sys_profile_func(void); Py_tracefunc slp_get_sys_trace_func(void); int slp_encode_ctrace_functions(Py_tracefunc c_tracefunc, Py_tracefunc c_profilefunc); -PyTaskletTStateStruc * slp_get_saved_tstate(PyTaskletObject *task); /* * Channel related prototypes diff --git a/Lib/stackless.py b/Lib/stackless.py index 3b38579fa91a0d..d1c345ec1e7b71 100644 --- a/Lib/stackless.py +++ b/Lib/stackless.py @@ -92,7 +92,7 @@ def _tasklet_get_unpicklable_state(tasklet): flags = pickle_flags(PICKLEFLAGS_PICKLE_CONTEXT, PICKLEFLAGS_PICKLE_CONTEXT) try: - return {'context': tasklet.__reduce__()[2][8]} + return {'context': tasklet.__reduce__()[2][12]} finally: pickle_flags(flags, PICKLEFLAGS_PICKLE_CONTEXT) diff --git a/Stackless/changelog.txt b/Stackless/changelog.txt index 237b3595eeccc9..6aaf94820b9923 100644 --- a/Stackless/changelog.txt +++ b/Stackless/changelog.txt @@ -9,6 +9,11 @@ What's New in Stackless 3.X.X? *Release date: 20XX-XX-XX* +- https://github.com/stackless-dev/stackless/issues/281 + Per tasklet profiling and tracing state information is now stored in the + tasklet itself. This increases the size of tasklet objects a bit, but saves a + lot of code. + - https://github.com/stackless-dev/stackless/issues/270 Stackless now uses an unmodified PyFrameObject structure. Stackless now stores more state information in the field f->f_executing than C-Python. diff --git a/Stackless/module/scheduling.c b/Stackless/module/scheduling.c index 4e466872bfa07a..d93045680582da 100644 --- a/Stackless/module/scheduling.c +++ b/Stackless/module/scheduling.c @@ -322,118 +322,6 @@ slp_init_bombtype(void) return PyType_Ready(&PyBomb_Type); } -/******************************************************************* - - Exception handling revised. - - Every tasklet has its own exception state. The thread state - exists only once for the current thread, so we need to simulate - ownership. - - Whenever a tasklet is run for the first time, it should clear - the exception variables and start with a clean state. - - When it dies normally, it should clean up these. - - When a transfer occours from one tasklet to another, - the first tasklet should save its exception in local variables, - and the other one should restore its own. - - When a tasklet dies with an uncaught exception, this will - be passed on to the main tasklet. The main tasklet must - clear its exception state, if any, and take over those of - the tasklet resting in peace. - - 2002-08-08 This was a misconception. This is not the current - exception, but the one which ceval provides for exception - handlers. That means, sharing of this variable is totally - unrelated to the current error, and we always swap the data. - - Added support for trace/profile as well. - - ********************************************************************/ - - -typedef struct { - intptr_t magic1; - PyTaskletTStateStruc s; - intptr_t magic2; -} saved_tstat_with_magic_t; - -/* not a valid ptr and not a common integer */ -#define SAVED_TSTATE_MAGIC1 (((intptr_t)transfer_with_tracing)+1) -#define SAVED_TSTATE_MAGIC2 (-1*((intptr_t)transfer_with_tracing)) - -static int -transfer_with_tracing(PyCStackObject **cstprev, PyCStackObject *cst, PyTaskletObject *prev) -{ - PyThreadState *ts = _PyThreadState_GET(); - int ret; - - saved_tstat_with_magic_t sm; - sm.magic1 = SAVED_TSTATE_MAGIC1; - sm.magic2 = SAVED_TSTATE_MAGIC2; - - /* prevent overly compiler optimisation. - We store the address of sm into a global variable. - This way the optimizer can't change the layout of the structure. */ - SLP_DO_NOT_OPTIMIZE_AWAY(&sm); - - sm.s.tracing = ts->tracing; - sm.s.c_profilefunc = ts->c_profilefunc; - sm.s.c_tracefunc = ts->c_tracefunc; - sm.s.c_profileobj = ts->c_profileobj; - sm.s.c_traceobj = ts->c_traceobj; - Py_XINCREF(sm.s.c_profileobj); - Py_XINCREF(sm.s.c_traceobj); - - PyEval_SetTrace(NULL, NULL); - PyEval_SetProfile(NULL, NULL); - ts->tracing = 0; - - ret = slp_transfer(cstprev, cst, prev); - - ts->tracing = sm.s.tracing; - PyEval_SetTrace(sm.s.c_tracefunc, sm.s.c_traceobj); - PyEval_SetProfile(sm.s.c_profilefunc, sm.s.c_profileobj); - - sm.magic1 = 0; - sm.magic2 = 0; - Py_XDECREF(sm.s.c_profileobj); - Py_XDECREF(sm.s.c_traceobj); - - return ret; -} - -PyTaskletTStateStruc * -slp_get_saved_tstate(PyTaskletObject *task) { - /* typical offset of the structure from cstate->stack - * is about 20. Therefore 100 should be enough */ - static const Py_ssize_t max_search_size = 100; - PyCStackObject *cst = task->cstate; - Py_ssize_t *p, *p_max; - - if (cst->tstate && cst->tstate->st.current == task) - /* task is current */ - return NULL; - if (cst->task != task) - return NULL; - assert(Py_SIZE(cst) >= 0); - if (Py_SIZE(cst) > max_search_size) - p_max = &(cst->stack[max_search_size]); - else - p_max = &(cst->stack[Py_SIZE(cst)]); - for (p=cst->stack; p!=p_max; p++) { - if (SAVED_TSTATE_MAGIC1 == *p) { - saved_tstat_with_magic_t *sm = (saved_tstat_with_magic_t *)p; - assert(sm->magic1 == SAVED_TSTATE_MAGIC1); - if (sm->magic2 == SAVED_TSTATE_MAGIC2) - /* got it */ - return &(sm->s); - } - } - return NULL; -} /* scheduler monitoring */ @@ -556,33 +444,6 @@ kill_wrap_bad_guy(PyTaskletObject *prev, PyTaskletObject *bad_guy) /* non-recursive scheduling */ -PyObject * -slp_restore_tracing(PyCFrameObject *cf, int exc, PyObject *retval) -{ - PyThreadState *ts = _PyThreadState_GET(); - - if (NULL == cf->any1 && NULL == cf->any2) { - /* frame was created by unpickling */ - if (cf->n & 1) { - Py_tracefunc func = slp_get_sys_trace_func(); - if (NULL == func) - return NULL; - cf->any1 = func; - } - if (cf->n & 2) { - Py_tracefunc func = slp_get_sys_profile_func(); - if (NULL == func) - return NULL; - cf->any2 = func; - } - } - ts->tracing = cf->i; - PyEval_SetTrace((Py_tracefunc)cf->any1, cf->ob1); - PyEval_SetProfile((Py_tracefunc)cf->any2, cf->ob2); - SLP_STORE_NEXT_FRAME(ts, cf->f_back); - return STACKLESS_PACK(ts, retval); -} - int slp_encode_ctrace_functions(Py_tracefunc c_tracefunc, Py_tracefunc c_profilefunc) { @@ -771,6 +632,54 @@ Py_LOCAL_INLINE(void) SLP_UPDATE_TSTATE_ON_SWITCH(PyThreadState *tstate, PyTaskl tstate->context = next->context; tstate->context_ver++; next->context = NULL; + /* And now the same for the trace and profile state: + * - save the state form tstate to prev + * - move the state from next to tstate + */ + assert(prev->profilefunc == NULL); + assert(prev->tracefunc == NULL); + assert(prev->profileobj == NULL); + assert(prev->traceobj == NULL); + assert(prev->tracing == 0); + if (tstate->c_profilefunc || next->profilefunc) { + prev->profilefunc = tstate->c_profilefunc; + prev->profileobj = tstate->c_profileobj; + Py_XINCREF(prev->profileobj); + if (prev->profileobj) + assert(Py_REFCNT(prev->profileobj) >= 2); /* won't drop to zero in PyEval_SetProfile */ + PyEval_SetProfile(next->profilefunc, next->profileobj); + next->profilefunc = NULL; + if (next->profileobj) + assert(Py_REFCNT(next->profileobj) >= 2); /* won't drop to zero */ + Py_CLEAR(next->profileobj); + } else { + /* If you use a Python profileobj, profilefunc is sysmodule.c profile_trampoline(). + * Therefore, if profilefunc is NULL, profileobj must be NULL too. + */ + assert(tstate->c_profileobj == NULL); + assert(next->profileobj == NULL); + } + if (tstate->c_tracefunc || next->tracefunc) { + prev->tracefunc = tstate->c_tracefunc; + prev->traceobj = tstate->c_traceobj; + Py_XINCREF(prev->traceobj); + if (prev->traceobj) + assert(Py_REFCNT(prev->traceobj) >= 2); /* won't drop to zero in PyEval_SetTrace */ + prev->tracing = tstate->tracing; + tstate->tracing = next->tracing; + PyEval_SetTrace(next->tracefunc, next->traceobj); + next->tracefunc = NULL; + if (next->traceobj) + assert(Py_REFCNT(next->traceobj) >= 2); /* won't drop to zero */ + Py_CLEAR(next->traceobj); + next->tracing = 0; + } else { + /* If you use a Python traceobj, tracefunc is sysmodule.c trace_trampoline(). + * Therefore, if tracefunc is NULL, traceobj must be NULL too. + */ + assert(tstate->c_traceobj == NULL); + assert(next->traceobj == NULL); + } } #else #define SLP_UPDATE_TSTATE_ON_SWITCH(tstate__, prev_, next_) \ @@ -784,6 +693,51 @@ Py_LOCAL_INLINE(void) SLP_UPDATE_TSTATE_ON_SWITCH(PyThreadState *tstate, PyTaskl ts__->context = next__->context; \ ts__->context_ver++; \ next__->context = NULL; \ + /* And now the same for the trace and profile state: */ \ + /* - save the state form tstate to prev */ \ + /* - move the state from next to tstate */ \ + assert(prev__->profilefunc == NULL); \ + assert(prev__->tracefunc == NULL); \ + assert(prev__->profileobj == NULL); \ + assert(prev__->traceobj == NULL); \ + assert(prev__->tracing == 0); \ + if (ts__->c_profilefunc || next__->profilefunc) { \ + prev__->profilefunc = ts__->c_profilefunc; \ + prev__->profileobj = ts__->c_profileobj; \ + Py_XINCREF(prev__->profileobj); \ + if (prev__->profileobj) \ + assert(Py_REFCNT(prev__->profileobj) >= 2); /* won't drop to zero in PyEval_SetProfile */ \ + PyEval_SetProfile(next__->profilefunc, next__->profileobj); \ + next__->profilefunc = NULL; \ + if (next__->profileobj) \ + assert(Py_REFCNT(next__->profileobj) >= 2); /* won't drop to zero */ \ + Py_CLEAR(next__->profileobj); \ + } else { \ + /* If you use a Python profileobj, profilefunc is sysmodule.c profile_trampoline(). */ \ + /* Therefore, if profilefunc is NULL, profileobj must be NULL too. */ \ + assert(ts__->c_profileobj == NULL); \ + assert(next__->profileobj == NULL); \ + } \ + if (ts__->c_tracefunc || next__->tracefunc) { \ + prev__->tracefunc = ts__->c_tracefunc; \ + prev__->traceobj = ts__->c_traceobj; \ + Py_XINCREF(prev__->traceobj); \ + if (prev__->traceobj) \ + assert(Py_REFCNT(prev__->traceobj) >= 2); /* won't drop to zero in PyEval_SetTrace */ \ + prev__->tracing = ts__->tracing; \ + ts__->tracing = next__->tracing; \ + PyEval_SetTrace(next__->tracefunc, next__->traceobj); \ + next__->tracefunc = NULL; \ + if (next__->traceobj) \ + assert(Py_REFCNT(next__->traceobj) >= 2); /* won't drop to zero */ \ + Py_CLEAR(next__->traceobj); \ + next__->tracing = 0; \ + } else { \ + /* If you use a Python traceobj, tracefunc is sysmodule.c trace_trampoline(). */ \ + /* Therefore, if tracefunc is NULL, traceobj must be NULL too. */ \ + assert(ts__->c_traceobj == NULL); \ + assert(next__->traceobj == NULL); \ + } \ } while(0) #endif @@ -1078,7 +1032,6 @@ slp_schedule_task_prepared(PyThreadState *ts, PyObject **result, PyTaskletObject { PyCStackObject **cstprev; PyObject *retval; - int (*transfer)(PyCStackObject **, PyCStackObject *, PyTaskletObject *); int transfer_result; /* remove the no-soft-irq flag from the runflags */ @@ -1121,31 +1074,6 @@ slp_schedule_task_prepared(PyThreadState *ts, PyObject **result, PyTaskletObject return -1; } - if (ts->use_tracing || ts->tracing) { - /* build a shadow frame if we are returning here */ - if (prev->f.frame != NULL) { - PyCFrameObject *f = slp_cframe_new(slp_restore_tracing, 0); - int c_functions = slp_encode_ctrace_functions(ts->c_tracefunc, ts->c_profilefunc); - if (f == NULL || c_functions == -1) - return -1; - f->any1 = ts->c_tracefunc; - f->any2 = ts->c_profilefunc; - f->i = ts->tracing; - f->n = c_functions; - assert(NULL == f->ob1); - assert(NULL == f->ob2); - f->ob1 = ts->c_traceobj; - f->ob2 = ts->c_profileobj; - Py_XINCREF(f->ob1); - Py_XINCREF(f->ob2); - assert(f->f_back == NULL); - f->f_back = prev->f.frame; /* steal the reference */ - prev->f.frame = (PyFrameObject *) f; - } - PyEval_SetTrace(NULL, NULL); - PyEval_SetProfile(NULL, NULL); - ts->tracing = 0; - } assert(next->cstate != NULL); if (next->cstate->nesting_level != 0) { @@ -1213,14 +1141,10 @@ slp_schedule_task_prepared(PyThreadState *ts, PyObject **result, PyTaskletObject Py_CLEAR(next->f.frame); ++ts->st.nesting_level; - if (ts->use_tracing || ts->tracing) - transfer = transfer_with_tracing; - else - transfer = slp_transfer; SLP_UPDATE_TSTATE_ON_SWITCH(ts, prev, next); - transfer_result = transfer(cstprev, next->cstate, prev); + transfer_result = slp_transfer(cstprev, next->cstate, prev); /* Note: If the transfer was successful from here on "prev" holds the * currently executing tasklet and "next" is the previous tasklet. */ @@ -1237,29 +1161,6 @@ slp_schedule_task_prepared(PyThreadState *ts, PyObject **result, PyTaskletObject *did_switch = 1; *result = retval; - /* Now evaluate any pending (slp_restore_tracing) cframes. - * They were inserted by tasklet_set_trace_function or - * tasklet_set_profile_function. We must process them here, because the - * restored cstack doesn't contain them. - * (For now there is at most a single pending cframe.) - */ - if (prev->cstate->nesting_level > 0 && f && PyCFrame_Check(f) && - ((PyCFrameObject *)f)->f_execute == slp_restore_tracing) { - PyObject *retval; - PyFrameObject *f2; - - /* the next frame must be a real frame */ - assert(f->f_back && PyFrame_Check(f->f_back)); - - retval = CALL_FRAME_FUNCTION(f, 0, Py_None); - STACKLESS_UNPACK(ts, retval); - assert(retval == Py_None); - f2 = SLP_CLAIM_NEXT_FRAME(ts); - assert(f2 == f->f_back); - Py_DECREF(f); - f = f2; - assert(PyFrame_Check(SLP_CURRENT_FRAME(ts))); - } assert(f == NULL || Py_REFCNT(f) >= 2); Py_XDECREF(f); return 0; @@ -1389,8 +1290,14 @@ schedule_task_destruct(PyObject **retval, PyTaskletObject *prev, PyTaskletObject } fail = slp_schedule_task(retval, prev, next, 1, &switched); /* it should either fail or switch */ - if (!fail) + if (!fail) { assert(switched); + /* clear tracing and profiling state for compatibility with Stackless versions < 3.8 */ + prev->profilefunc = prev->tracefunc = NULL; + prev->tracing = 0; + Py_CLEAR(prev->profileobj); + Py_CLEAR(prev->traceobj); + } if (fail) { /* something happened, cancel our decref manipulations. */ if (tempval != NULL) { diff --git a/Stackless/module/taskletobject.c b/Stackless/module/taskletobject.c index 20bf77b54c9443..f24089ea0deeaa 100644 --- a/Stackless/module/taskletobject.c +++ b/Stackless/module/taskletobject.c @@ -172,6 +172,8 @@ tasklet_traverse(PyTaskletObject *t, visitproc visit, void *arg) Py_VISIT(t->exc_state.exc_value); Py_VISIT(t->exc_state.exc_traceback); Py_VISIT(t->context); + Py_VISIT(t->profileobj); + Py_VISIT(t->traceobj); return 0; } @@ -204,6 +206,10 @@ tasklet_clear(PyTaskletObject *t) Py_CLEAR(t->tempval); Py_CLEAR(t->def_globals); Py_CLEAR(t->context); + t->profilefunc = t->tracefunc = NULL; + t->tracing = 0; + Py_CLEAR(t->profileobj); + Py_CLEAR(t->traceobj); /* unlink task from cstate */ if (t->cstate != NULL && t->cstate->task == t) @@ -530,7 +536,7 @@ tasklet_bind(PyObject *self, PyObject *args, PyObject *kwargs) return self; } -#define TASKLET_TUPLEFMT "iOiOOOOO" +#define TASKLET_TUPLEFMT "iOiOOOOOiiOO" static PyObject * tasklet_new(PyTypeObject *type, PyObject *args, PyObject *kwds) @@ -620,6 +626,8 @@ tasklet_reduce(PyTaskletObject * t, PyObject *value) PyThreadState *ts = t->cstate->tstate; PyObject *exc_type, *exc_value, *exc_traceback, *exc_info; PyObject *context = NULL; + int tracing, c_functions; + PyObject *profileobj, *traceobj; if (value && !PyLong_Check(value)) { PyErr_SetString(PyExc_TypeError, "__reduce_ex__ argument should be an integer"); @@ -633,20 +641,14 @@ tasklet_reduce(PyTaskletObject * t, PyObject *value) if (lis == NULL) goto err_exit; f = t->f.frame; while (f != NULL) { - int append_frame = 1; - if (PyCFrame_Check(f) && ((PyCFrameObject *)f)->f_execute == slp_restore_tracing) { - append_frame = ts->st.pickleflags & SLP_PICKLEFLAGS_PRESERVE_TRACING_STATE; - } - if (append_frame) { - int ret; - PyObject * frame_reducer = slp_reduce_frame(f); - if (frame_reducer == NULL) - goto err_exit; - ret = PyList_Append(lis, frame_reducer); - Py_DECREF(frame_reducer); - if (ret) - goto err_exit; - } + int ret; + PyObject * frame_reducer = slp_reduce_frame(f); + if (frame_reducer == NULL) + goto err_exit; + ret = PyList_Append(lis, frame_reducer); + Py_DECREF(frame_reducer); + if (ret) + goto err_exit; f = f->f_back; } if (PyList_Reverse(lis)) goto err_exit; @@ -661,6 +663,24 @@ tasklet_reduce(PyTaskletObject * t, PyObject *value) if (NULL == context) goto err_exit; + if (ts && ts->st.pickleflags & SLP_PICKLEFLAGS_PRESERVE_TRACING_STATE) { + c_functions = slp_encode_ctrace_functions(t->tracefunc, t->profilefunc); + if (-1 == c_functions) + goto err_exit; + tracing = t->tracing; + profileobj = t->profileobj; + if (NULL == profileobj) + profileobj = Py_None; + traceobj = t->traceobj; + if (NULL == traceobj) + traceobj = Py_None; + } else { + c_functions = 0; + tracing = 0; + profileobj = Py_None; + traceobj = Py_None; + } + assert(!ts || t->exc_info != &ts->exc_state); /* Because of the test a few lines above, it is guaranteed that t is not the current tasklet. * Therefore we can simplify the line @@ -700,6 +720,10 @@ tasklet_reduce(PyTaskletObject * t, PyObject *value) exc_value, exc_traceback, exc_info, + tracing, + c_functions, + profileobj, + traceobj, context ); Py_DECREF(exc_info); @@ -730,6 +754,8 @@ tasklet_setstate(PyObject *self, PyObject *args) PyObject *exc_type, *exc_value, *exc_traceback; PyObject *old_type, *old_value, *old_traceback; PyObject *exc_info_obj; + int tracing, c_functions; + PyObject *profileobj, *traceobj; PyObject *context = NULL; PyFrameObject *f; Py_ssize_t i, nframes; @@ -740,7 +766,7 @@ tasklet_setstate(PyObject *self, PyObject *args) if (PyTasklet_Alive(t)) RUNTIME_ERROR("tasklet is alive", NULL); - if (!PyArg_ParseTuple(args, "iOiO!OOOO|O:tasklet", + if (!PyArg_ParseTuple(args, "iOiO!OOOOiiOO|O:tasklet", &flags, &tempval, &nesting_level, @@ -749,6 +775,10 @@ tasklet_setstate(PyObject *self, PyObject *args) &exc_value, &exc_traceback, &exc_info_obj, + &tracing, + &c_functions, + &profileobj, + &traceobj, &context)) return NULL; @@ -808,6 +838,39 @@ tasklet_setstate(PyObject *self, PyObject *args) if(NULL == context && _tasklet_init_context(t)) return NULL; } + + /* profile and tracing */ + if (c_functions & 1) { + Py_tracefunc func = slp_get_sys_trace_func(); + if (NULL == func) + return NULL; + t->tracefunc = func; + } else { + t->tracefunc = NULL; + } + if (c_functions & 2) { + Py_tracefunc func = slp_get_sys_profile_func(); + if (NULL == func) + return NULL; + t->profilefunc = func; + } else { + t->profilefunc = NULL; + } + if (Py_None != profileobj) { + Py_INCREF(profileobj); + Py_XSETREF(t->profileobj, profileobj); + } else { + Py_CLEAR(t->profileobj); + } + if (Py_None != traceobj) { + Py_INCREF(traceobj); + Py_XSETREF(t->traceobj, traceobj); + } else { + Py_CLEAR(t->traceobj); + } + t->tracing = tracing; + + /* context */ if (context) { PyObject *obj = _stackless_tasklet_set_context_impl(t, context); if (NULL == obj) @@ -2050,53 +2113,20 @@ static PyObject * tasklet_get_trace_function(PyTaskletObject *task, void *closure) { PyThreadState *ts = task->cstate->tstate; - PyCFrameObject *f; - PyTaskletTStateStruc *saved_ts; + PyObject *retval; - if (ts && ts->st.current == task) { - /* current tasklet */ - PyObject *temp = ts->c_traceobj; - if (temp == NULL) - temp = Py_None; - Py_INCREF(temp); - return temp; - } - - f = task->f.cframe; - while (NULL != f && PyCFrame_Check(f)) { - if (f->f_execute == slp_restore_tracing) { - /* we found a restore tracing frame */ - PyObject *temp = f->ob1; - if (temp == NULL) - temp = Py_None; - Py_INCREF(temp); - return temp; - } - f = (PyCFrameObject *)(f->f_back); - } - - /* try the saved tstate of a hard switched tasklet */ - saved_ts = slp_get_saved_tstate(task); - if (NULL != saved_ts) { - PyObject *temp; - temp = saved_ts->c_traceobj; - if (NULL == temp) - temp = Py_None; - Py_INCREF(temp); - return temp; - } - - Py_INCREF(Py_None); - return Py_None; + retval = (ts && ts->st.current == task) ? ts->c_traceobj : task->traceobj; + if (retval == NULL) + retval = Py_None; + Py_INCREF(retval); + return retval; } static int tasklet_set_trace_function(PyTaskletObject *task, PyObject *value, void *closure) { PyThreadState *ts = task->cstate->tstate; - PyCFrameObject *f; Py_tracefunc tf = NULL; - PyTaskletTStateStruc *saved_ts; if (Py_None == value) value = NULL; @@ -2113,124 +2143,31 @@ tasklet_set_trace_function(PyTaskletObject *task, PyObject *value, void *closure return 0; } - f = task->f.cframe; - while (NULL != f && PyCFrame_Check(f)) { - if (f->f_execute == slp_restore_tracing) { - /* we found a restore tracing frame */ - PyObject *temp; - int c_functions = slp_encode_ctrace_functions(tf, f->any2); - if (c_functions < 0) - return -1; - temp = f->ob1; - Py_XINCREF(value); - f->ob1 = value; - f->any1 = tf; - f->n = c_functions; - Py_XDECREF(temp); - - return 0; - } - f = (PyCFrameObject *)(f->f_back); - } - - /* try the saved tstate of a hard switched tasklet */ - saved_ts = slp_get_saved_tstate(task); - if (NULL != saved_ts) { - PyObject *temp; - temp = saved_ts->c_traceobj; - Py_XINCREF(value); - saved_ts->c_traceobj = value; - saved_ts->c_tracefunc = tf; - Py_XDECREF(temp); - - return 0; - } - - /* task is neither current nor has a restore_tracing frame. - ==> tracing is currently off */ - if (NULL == value) - /* nothing to do */ - return 0; - - /* here we must add a restore tracing cframe */ - f = task->f.cframe; - if (NULL != f) { - /* Insert a new cframe */ - PyCFrameObject *cf; - int c_functions = slp_encode_ctrace_functions(tf, f->any2); - if (c_functions < 0) - return -1; - cf = slp_cframe_new(slp_restore_tracing, 0); - if (cf == NULL) - return -1; - Py_INCREF(f); - cf->f_back = (PyFrameObject *)f; - Py_INCREF(value); - assert(NULL == cf->ob1); - cf->ob1 = value; - cf->any1 = tf; - cf->n = c_functions; - assert(0 == cf->i); /* ts->tracing */ - assert(NULL == cf->any2); /* ts->c_profilefunc */ - assert(NULL == cf->ob2); /* ts->c_profileobj */ - Py_SETREF(task->f.cframe, cf); - return 0; - } - - RUNTIME_ERROR("tasklet is not alive", -1); + /* tasklet is not current */ + task->tracefunc = tf; + Py_XINCREF(value); + Py_XSETREF(task->traceobj, value); + return 0; } static PyObject * tasklet_get_profile_function(PyTaskletObject *task, void *closure) { PyThreadState *ts = task->cstate->tstate; - PyCFrameObject *f; - PyTaskletTStateStruc *saved_ts; - - if (ts && ts->st.current == task) { - /* current tasklet */ - PyObject *temp = ts->c_profileobj; - if (temp == NULL) - temp = Py_None; - Py_INCREF(temp); - return temp; - } - - f = task->f.cframe; - while (NULL != f && PyCFrame_Check(f)) { - if (f->f_execute == slp_restore_tracing) { - /* we found a restore tracing frame */ - PyObject *temp = f->ob2; - if (temp == NULL) - temp = Py_None; - Py_INCREF(temp); - return temp; - } - f = (PyCFrameObject *)(f->f_back); - } - - /* try the saved tstate of a hard switched tasklet */ - saved_ts = slp_get_saved_tstate(task); - if (NULL != saved_ts) { - PyObject *temp; - temp = saved_ts->c_profileobj; - if (NULL == temp) - temp = Py_None; - Py_INCREF(temp); - return temp; - } + PyObject *retval; - Py_INCREF(Py_None); - return Py_None; + retval = (ts && ts->st.current == task) ? ts->c_profileobj : task->profileobj; + if (retval == NULL) + retval = Py_None; + Py_INCREF(retval); + return retval; } static int tasklet_set_profile_function(PyTaskletObject *task, PyObject *value, void *closure) { PyThreadState *ts = task->cstate->tstate; - PyCFrameObject *f; Py_tracefunc tf = NULL; - PyTaskletTStateStruc *saved_ts; if (Py_None == value) value = NULL; @@ -2247,71 +2184,11 @@ tasklet_set_profile_function(PyTaskletObject *task, PyObject *value, void *closu return 0; } - f = task->f.cframe; - while (NULL != f && PyCFrame_Check(f)) { - if (f->f_execute == slp_restore_tracing) { - PyObject *temp; - int c_functions = slp_encode_ctrace_functions(f->any1, tf); - if (c_functions < 0) - return -1; - /* we found a restore tracing frame */ - temp = f->ob2; - Py_XINCREF(value); - f->ob2 = value; - f->any2 = tf; - f->n = c_functions; - Py_XDECREF(temp); - - return 0; - } - f = (PyCFrameObject *)(f->f_back); - } - - /* try the saved tstate of a hard switched tasklet */ - saved_ts = slp_get_saved_tstate(task); - if (NULL != saved_ts) { - PyObject *temp; - temp = saved_ts->c_profileobj; - Py_XINCREF(value); - saved_ts->c_profileobj = value; - saved_ts->c_profilefunc = tf; - Py_XDECREF(temp); - - return 0; - } - - /* task is neither current nor has a restore_tracing frame. - ==> tracing is currently off */ - if (NULL == value) - /* nothing to do */ - return 0; - - /* here we must add an restore tracing cframe */ - f = task->f.cframe; - if (NULL != f) { - /* Insert a new cframe */ - PyCFrameObject *cf; - int c_functions = slp_encode_ctrace_functions(f->any1, tf); - if (c_functions < 0) - return -1; - cf = slp_cframe_new(slp_restore_tracing, 0); - if (cf == NULL) - return -1; - Py_INCREF(f); - cf->f_back = (PyFrameObject *)f; - Py_INCREF(value); - assert(NULL == cf->ob2); - cf->ob2 = value; - cf->any2 = tf; - cf->n = c_functions; - assert(0 == cf->i); /* ts->tracing */ - assert(NULL == cf->any1); /* ts->c_tracefunc */ - assert(NULL == cf->ob1); /* ts->c_traceobj */ - Py_SETREF(task->f.cframe, cf); - return 0; - } - - RUNTIME_ERROR("tasklet is not alive", -1); + /* tasklet is not current */ + task->profilefunc = tf; + Py_XINCREF(value); + Py_XSETREF(task->profileobj, value); + return 0; } /*[clinic input] diff --git a/Stackless/pickling/prickelpit.c b/Stackless/pickling/prickelpit.c index 3fae868570fb0a..689f793d24842e 100644 --- a/Stackless/pickling/prickelpit.c +++ b/Stackless/pickling/prickelpit.c @@ -828,7 +828,6 @@ static int init_functype(PyObject * mod) #define frametuplefmt "O)(OibOiOOiiOO" SLP_DEF_INVALID_EXEC(slp_channel_seq_callback) -SLP_DEF_INVALID_EXEC(slp_restore_tracing) SLP_DEF_INVALID_EXEC(slp_tp_init_callback) static PyTypeObject wrap_PyFrame_Type; @@ -1164,8 +1163,6 @@ static int init_frametype(PyObject * mod) { return slp_register_execute(&PyCFrame_Type, "channel_seq_callback", slp_channel_seq_callback, SLP_REF_INVALID_EXEC(slp_channel_seq_callback)) - || slp_register_execute(&PyCFrame_Type, "slp_restore_tracing", - slp_restore_tracing, SLP_REF_INVALID_EXEC(slp_restore_tracing)) || slp_register_execute(&PyCFrame_Type, "slp_tp_init_callback", slp_tp_init_callback, SLP_REF_INVALID_EXEC(slp_tp_init_callback)) || init_type(&wrap_PyFrame_Type, initchain, mod); diff --git a/Stackless/unittests/test_exception.py b/Stackless/unittests/test_exception.py index a7e7132d8f4573..cdd4c3a188fb52 100644 --- a/Stackless/unittests/test_exception.py +++ b/Stackless/unittests/test_exception.py @@ -27,8 +27,8 @@ def test_tasklet_reduce_wo_exc(self): self.assertEqual(len(state), 3) state = state[2] self.assertIsInstance(state, tuple) - self.assertEqual(len(state), 8) - self.assertTupleEqual(state[-4:], (None, None, None, None)) + self.assertEqual(len(state), 12) + self.assertTupleEqual(state[4:8], (None, None, None, None)) def test_tasklet_pickle_with_exc(self): self.skipUnlessSoftswitching() diff --git a/Stackless/unittests/test_tracing.py b/Stackless/unittests/test_tracing.py index 5518286887f541..cd75e49e5b1d08 100644 --- a/Stackless/unittests/test_tracing.py +++ b/Stackless/unittests/test_tracing.py @@ -126,18 +126,6 @@ def testSetTraceOnCurrent(self): self.assertIsNone(tasklet.profile_function) self.assertGreater(self.tracecount, 0) - def testSetTraceOnDeadTasklet(self): - t = stackless.tasklet() - self.assertIsNone(t.trace_function) - self.assertRaisesRegex(RuntimeError, "tasklet is not alive", - setattr, t, "trace_function", self.nullTraceFunc) - - def testSetProfileOnDeadTasklet(self): - t = stackless.tasklet() - self.assertIsNone(t.trace_function) - self.assertRaisesRegex(RuntimeError, "tasklet is not alive", - setattr, t, "profile_function", self.nullTraceFunc) - def testSetTraceOnTasklet1(self): # Change trace state of a non-current tasklet # create tasklet, set trace, clear trace, run diff --git a/Stackless/unittests/test_tstate.py b/Stackless/unittests/test_tstate.py index b1bca3f08c998b..483677f4e1decf 100644 --- a/Stackless/unittests/test_tstate.py +++ b/Stackless/unittests/test_tstate.py @@ -332,16 +332,19 @@ def testReduceOfTracingState(self): return # test if the tracing cframe is present / not present - reduce_frame = get_reduce_frame() - self.assertListEqual(reduced_tasklet1[2][3], [reduce_frame(frame)]) - self.assertEqual(len(reduced_tasklet2[2][3]), 2) - self.assertIs(reduced_tasklet2[2][3][0], reduce_frame(frame)) - self.assertIsInstance(reduced_tasklet2[2][3][1], stackless.cframe) - - cf = reduced_tasklet2[2][3][1] - reduced_cframe = cf.__reduce__() - self.assertEqual(reduced_cframe[2][1], 'slp_restore_tracing') - self.assertIs(reduced_cframe[2][2][1].__func__, self.Callback.__func__) + self.assertIsInstance(reduced_tasklet1[2][8], int) + self.assertEqual(reduced_tasklet1[2][8], 0) + self.assertIsInstance(reduced_tasklet1[2][9], int) + self.assertEqual(reduced_tasklet1[2][9], 0) + self.assertIsNone(reduced_tasklet1[2][10]) + self.assertIsNone(reduced_tasklet1[2][11]) + + self.assertIsInstance(reduced_tasklet2[2][8], int) + self.assertEqual(reduced_tasklet2[2][8], 0) + self.assertIsInstance(reduced_tasklet2[2][9], int) + self.assertEqual(reduced_tasklet2[2][9], 1) + self.assertIsNone(reduced_tasklet2[2][10]) + self.assertIs(reduced_tasklet2[2][11].__func__, self.Callback.__func__) if __name__ == '__main__': if not sys.argv[1:]: From 3922fb81ba76da645faac48ce41cc1e86bcb1f83 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Wed, 30 Jun 2021 14:44:46 +0200 Subject: [PATCH 02/11] Stackless issue #281: re-add two test cases They were removed by the previous commit. --- Stackless/unittests/test_tracing.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Stackless/unittests/test_tracing.py b/Stackless/unittests/test_tracing.py index cd75e49e5b1d08..2e7ad9eeae3a0b 100644 --- a/Stackless/unittests/test_tracing.py +++ b/Stackless/unittests/test_tracing.py @@ -126,6 +126,18 @@ def testSetTraceOnCurrent(self): self.assertIsNone(tasklet.profile_function) self.assertGreater(self.tracecount, 0) + def testSetTraceOnDeadTasklet(self): + t = stackless.tasklet() + self.assertIsNone(t.trace_function) + t.trace_function = self.nullTraceFunc + self.assertIs(t.trace_function.__func__, self.nullTraceFunc.__func__) + + def testSetProfileOnDeadTasklet(self): + t = stackless.tasklet() + self.assertIsNone(t.trace_function) + t.profile_function = self.nullTraceFunc + self.assertIs(t.profile_function.__func__, self.nullTraceFunc.__func__) + def testSetTraceOnTasklet1(self): # Change trace state of a non-current tasklet # create tasklet, set trace, clear trace, run From 21c205267ff12637e61010f35ebe503c09ec09e1 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Wed, 30 Jun 2021 22:54:45 +0200 Subject: [PATCH 03/11] Make "pycore_slp_platformselect.h" a very private header. Previously "pycore_slp_platformselect.h" was included by many *.c files and by "pycore_slp_pystate.h". I try to get rid of most platform specific code and concentrate the remaining platform specific code within a single C source "slp_transfer.c". Current state: work in progress --- Include/internal/pycore_slp_platformselect.h | 58 +---------------- Include/internal/pycore_slp_pystate.h | 6 +- Include/internal/pycore_stackless.h | 58 +++++++++++++++++ Modules/_pickle.c | 4 +- Python/ceval.c | 2 +- Stackless/core/slp_transfer.c | 43 +++++++++++++ Stackless/core/stacklesseval.c | 66 ++++++++++---------- Stackless/module/scheduling.c | 2 +- Stackless/module/stacklessmodule.c | 2 +- Stackless/pickling/prickelpit.c | 2 +- Stackless/pickling/safe_pickle.c | 6 +- 11 files changed, 149 insertions(+), 100 deletions(-) diff --git a/Include/internal/pycore_slp_platformselect.h b/Include/internal/pycore_slp_platformselect.h index 8108b493a882d8..1d874b799208e3 100644 --- a/Include/internal/pycore_slp_platformselect.h +++ b/Include/internal/pycore_slp_platformselect.h @@ -35,62 +35,6 @@ /* default definitions if not defined in above files */ -/* - * Call SLP_DO_NOT_OPTIMIZE_AWAY(pointer) to ensure that pointer will be - * computed even post-optimization. Use it for pointers that are computed but - * otherwise are useless. The compiler tends to do a good job at eliminating - * unused variables, and this macro fools it into thinking var is in fact - * needed. - */ - -#ifndef SLP_DO_NOT_OPTIMIZE_AWAY - -/* Code is based on Facebook folly - * https://github.com/facebook/folly/blob/master/folly/Benchmark.h, - * which has an Apache 2 license. - */ -#ifdef _MSC_VER - -#pragma optimize("", off) - -static inline void doNotOptimizeDependencySink(const void* p) {} - -#pragma optimize("", on) - -#define SLP_DO_NOT_OPTIMIZE_AWAY(pointer) doNotOptimizeDependencySink(pointer) -#define SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS /* empty */ - -#elif (defined(__GNUC__) || defined(__clang__)) -/* - * The "r" constraint forces the compiler to make datum available - * in a register to the asm block, which means that it must have - * computed/loaded it. - */ -#define SLP_DO_NOT_OPTIMIZE_AWAY(pointer) \ - do {__asm__ volatile("" ::"r"(pointer));} while(0) -#define SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS /* empty */ -#else -/* - * Unknown compiler - */ -#define SLP_DO_NOT_OPTIMIZE_AWAY(pointer) \ - do { slp_do_not_opimize_away_sink = ((void*)(pointer)); } while(0) -extern uint8_t* volatile slp_do_not_opimize_away_sink; -#define SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS uint8_t* volatile slp_do_not_opimize_away_sink; -#endif -#endif - -/* adjust slots to typical size of a few recursions on your system */ - -#ifndef SLP_CSTACK_SLOTS -#define SLP_CSTACK_SLOTS 1024 -#endif - -/* how many cstacks to cache at all */ - -#ifndef SLP_CSTACK_MAXCACHE -#define SLP_CSTACK_MAXCACHE 100 -#endif /* a good estimate how much the cstack level differs between initialisation and main C-Python(r) code. Not critical, but saves time. @@ -126,7 +70,7 @@ extern uint8_t* volatile slp_do_not_opimize_away_sink; #define SLP_CSTACK_SUBTRACT(a, b) (b) - (a) #endif -#define SLP_CSTACK_SAVE_NOW(tstate, stackvar) \ +#define SLP_CSTACK_SAVE_NOW_to_be_deleted(tstate, stackvar) \ ((tstate)->st.cstack_root != NULL ? \ SLP_CSTACK_SUBTRACT((tstate)->st.cstack_root, \ (intptr_t*)&(stackvar)) > SLP_CSTACK_WATERMARK : 1) diff --git a/Include/internal/pycore_slp_pystate.h b/Include/internal/pycore_slp_pystate.h index 935646a0a891f3..4173d12cdf1dc2 100644 --- a/Include/internal/pycore_slp_pystate.h +++ b/Include/internal/pycore_slp_pystate.h @@ -16,7 +16,11 @@ /* This include file is included from pycore_pystate.h only */ -#include "pycore_slp_platformselect.h" /* for SLP_CSTACK_SLOTS */ + +/* adjust slots to typical size of a few recursions on your system */ +#ifndef SLP_CSTACK_SLOTS +#define SLP_CSTACK_SLOTS 1024 +#endif /* * Stackless runtime state diff --git a/Include/internal/pycore_stackless.h b/Include/internal/pycore_stackless.h index a9844ada69a392..fe25334d117941 100644 --- a/Include/internal/pycore_stackless.h +++ b/Include/internal/pycore_stackless.h @@ -823,6 +823,64 @@ long slp_parse_thread_id(PyObject *thread_id, unsigned long *id); (frame_)->f_executing <= SLP_FRAME_EXECUTING_YIELD_FROM) +/* Stuff originally in pycore_slp_platformselect.h */ + +int +slp_cstack_save_now(const PyThreadState *tstate, const void * pstackvar); +#define SLP_CSTACK_SAVE_NOW(tstate, stackvar) slp_cstack_save_now((tstate), &(stackvar)) +void +slp_cstack_set_root(PyThreadState *tstate, const void * pstackvar); +#define SLP_CSTACK_SET_ROOT(tstate, stackvar) slp_cstack_set_root((tstate), &(stackvar)) +PyObject * +slp_climb_stack_and_eval_frame(PyFrameObject *f); + +/* + * Call SLP_DO_NOT_OPTIMIZE_AWAY(pointer) to ensure that pointer will be + * computed even post-optimization. Use it for pointers that are computed but + * otherwise are useless. The compiler tends to do a good job at eliminating + * unused variables, and this macro fools it into thinking var is in fact + * needed. + */ + +#ifndef SLP_DO_NOT_OPTIMIZE_AWAY + +/* Code is based on Facebook folly + * https://github.com/facebook/folly/blob/master/folly/Benchmark.h, + * which has an Apache 2 license. + */ +#ifdef _MSC_VER + +#pragma optimize("", off) + +static inline void doNotOptimizeDependencySink(const void* p) {} + +#pragma optimize("", on) + +#define SLP_DO_NOT_OPTIMIZE_AWAY(pointer) doNotOptimizeDependencySink(pointer) +#define SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS /* empty */ + +#elif (defined(__GNUC__) || defined(__clang__)) +/* + * The "r" constraint forces the compiler to make datum available + * in a register to the asm block, which means that it must have + * computed/loaded it. + */ +#define SLP_DO_NOT_OPTIMIZE_AWAY(pointer) \ + do {__asm__ volatile("" ::"r"(pointer));} while(0) +#define SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS /* empty */ +#else +/* + * Unknown compiler + */ +#define SLP_DO_NOT_OPTIMIZE_AWAY(pointer) \ + do { slp_do_not_opimize_away_sink = ((void*)(pointer)); } while(0) +extern uint8_t* volatile slp_do_not_opimize_away_sink; +#define SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS uint8_t* volatile slp_do_not_opimize_away_sink; +#endif +#endif /* #ifndef SLP_DO_NOT_OPTIMIZE_AWAY */ + + + #endif /* #ifdef SLP_BUILD_CORE */ #else /* STACKLESS */ diff --git a/Modules/_pickle.c b/Modules/_pickle.c index ac98f0ef39651c..8485db85cdf749 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -12,7 +12,7 @@ #define SLP_BUILD_CORE #include "stackless_api.h" #include "pycore_slp_prickelpit.h" -#include "pycore_slp_platformselect.h" /* for stack saving */ +#include "pycore_stackless.h" #endif PyDoc_STRVAR(pickle_module_doc, @@ -3962,7 +3962,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save) #ifdef STACKLESS /* but we save the stack after a fixed watermark */ { - /* use a variable, because SLP_CSTACK_SAVE_NOW evaluates ts several times. */ + /* use a variable, because SLP_CSTACK_SAVE_NOW may evaluate ts several times. */ PyThreadState *ts = PyThreadState_GET(); if (SLP_CSTACK_SAVE_NOW(ts, self)) { int res; diff --git a/Python/ceval.c b/Python/ceval.c index 7c9ce5a0564dc7..56afb91eab83c4 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -22,7 +22,7 @@ #include "setobject.h" #include "structmember.h" #include "pycore_stackless.h" -#include "pycore_slp_platformselect.h" /* for stack saving */ +// #include "pycore_slp_platformselect.h" /* for stack saving */ #include diff --git a/Stackless/core/slp_transfer.c b/Stackless/core/slp_transfer.c index c9c7a78da25a48..8b2d34ec754166 100644 --- a/Stackless/core/slp_transfer.c +++ b/Stackless/core/slp_transfer.c @@ -117,6 +117,32 @@ climb_stack_and_transfer(PyCStackObject **cstprev, PyCStackObject *cst, return slp_transfer(cstprev, cst, prev); } +PyObject * +slp_climb_stack_and_eval_frame(PyFrameObject *f) +{ + /* + * a similar case to climb_stack_and_transfer, + * but here we need to incorporate a gap in the + * stack into main and keep this gap on the stack. + * This way, initial_stub is always valid to be + * used to return to the main c stack. + */ + PyThreadState *ts = _PyThreadState_GET(); + intptr_t probe; + ptrdiff_t needed = &probe - ts->st.cstack_base; + /* in rare cases, the need might have vanished due to the recursion */ + if (needed > 0) { + register void * stack_ptr_tmp = alloca(needed * sizeof(intptr_t)); + if (stack_ptr_tmp == NULL) + return NULL; + /* hinder the compiler to optimise away + stack_ptr_tmp and the alloca call. + This happens with gcc 4.7.x and -O2 */ + SLP_DO_NOT_OPTIMIZE_AWAY(stack_ptr_tmp); + } + return slp_eval_frame(f); +} + /* This function returns -1 on error, 1 if a switch occurred and 0 * if only a stack save was performed */ @@ -189,6 +215,23 @@ slp_transfer(PyCStackObject **cstprev, PyCStackObject *cst, return result; } +int +slp_cstack_save_now(const PyThreadState *tstate, const void * pstackvar) +{ + assert(tstate); + assert(pstackvar); + if (tstate->st.cstack_root == NULL) + return 1; + return SLP_CSTACK_SUBTRACT(tstate->st.cstack_root, (const intptr_t*)pstackvar) > SLP_CSTACK_WATERMARK; +} + +void +slp_cstack_set_root(PyThreadState *tstate, const void * pstackvar) { + assert(tstate); + assert(pstackvar); + tstate->st.cstack_root = SLP_STACK_REFPLUS + (intptr_t *)pstackvar; +} + #ifdef Py_DEBUG int slp_transfer_return(PyCStackObject *cst) diff --git a/Stackless/core/stacklesseval.c b/Stackless/core/stacklesseval.c index c5f9c11d8d2bb4..db38cf35fcdced 100644 --- a/Stackless/core/stacklesseval.c +++ b/Stackless/core/stacklesseval.c @@ -243,31 +243,31 @@ make_initial_stub(void) return result; } -static PyObject * -climb_stack_and_eval_frame(PyFrameObject *f) -{ - /* - * a similar case to climb_stack_and_transfer, - * but here we need to incorporate a gap in the - * stack into main and keep this gap on the stack. - * This way, initial_stub is always valid to be - * used to return to the main c stack. - */ - PyThreadState *ts = _PyThreadState_GET(); - intptr_t probe; - ptrdiff_t needed = &probe - ts->st.cstack_base; - /* in rare cases, the need might have vanished due to the recursion */ - if (needed > 0) { - register void * stack_ptr_tmp = alloca(needed * sizeof(intptr_t)); - if (stack_ptr_tmp == NULL) - return NULL; - /* hinder the compiler to optimise away - stack_ptr_tmp and the alloca call. - This happens with gcc 4.7.x and -O2 */ - SLP_DO_NOT_OPTIMIZE_AWAY(stack_ptr_tmp); - } - return slp_eval_frame(f); -} +//static PyObject * +//climb_stack_and_eval_frame(PyFrameObject *f) +//{ +// /* +// * a similar case to climb_stack_and_transfer, +// * but here we need to incorporate a gap in the +// * stack into main and keep this gap on the stack. +// * This way, initial_stub is always valid to be +// * used to return to the main c stack. +// */ +// PyThreadState *ts = _PyThreadState_GET(); +// intptr_t probe; +// ptrdiff_t needed = &probe - ts->st.cstack_base; +// /* in rare cases, the need might have vanished due to the recursion */ +// if (needed > 0) { +// register void * stack_ptr_tmp = alloca(needed * sizeof(intptr_t)); +// if (stack_ptr_tmp == NULL) +// return NULL; +// /* hinder the compiler to optimise away +// stack_ptr_tmp and the alloca call. +// This happens with gcc 4.7.x and -O2 */ +// SLP_DO_NOT_OPTIMIZE_AWAY(stack_ptr_tmp); +// } +// return slp_eval_frame(f); +//} static PyObject * slp_frame_dispatch_top(PyObject *retval); @@ -348,11 +348,11 @@ slp_eval_frame(PyFrameObject *f) if (ts->st.cstack_base == NULL) ts->st.cstack_base = stackref - SLP_CSTACK_GOODGAP; if (stackref > ts->st.cstack_base) { - PyCStackObject *initial_stub; - retval = climb_stack_and_eval_frame(f); - initial_stub = ts->st.initial_stub; - /* cst might be NULL in OOM conditions */ - if (ts->interp != _PyRuntime.interpreters.main && initial_stub != NULL) { + PyCStackObject *initial_stub; + retval = slp_climb_stack_and_eval_frame(f); + initial_stub = ts->st.initial_stub; + /* cst might be NULL in OOM conditions */ + if (ts->interp != _PyRuntime.interpreters.main && initial_stub != NULL) { PyCStackObject *cst; register int found = 0; assert(initial_stub->startaddr == ts->st.cstack_base); @@ -865,7 +865,7 @@ eval_frame_callback(PyCFrameObject *cf, int exc, PyObject *retval) * ourselves in an infinite loop of stack spilling. */ saved_base = ts->st.cstack_root; - ts->st.cstack_root = SLP_STACK_REFPLUS + (intptr_t *) &f; + SLP_CSTACK_SET_ROOT(ts, f); /* pull in the right retval and tempval from the arguments */ Py_SETREF(retval, cf->ob1); @@ -928,14 +928,14 @@ slp_eval_frame_newstack(PyFrameObject *f, int exc, PyObject *retval) * magic here will clear that exception. */ intptr_t *old = ts->st.cstack_root; - ts->st.cstack_root = SLP_STACK_REFPLUS + (intptr_t *) &f; + SLP_CSTACK_SET_ROOT(ts, f); retval = PyEval_EvalFrameEx_slp(f, exc, retval); ts->st.cstack_root = old; return retval; } if (ts->st.cstack_root == NULL) { /* this is a toplevel call. Store the root of stack spilling */ - ts->st.cstack_root = SLP_STACK_REFPLUS + (intptr_t *) &f; + SLP_CSTACK_SET_ROOT(ts, f); retval = PyEval_EvalFrameEx_slp(f, exc, retval); /* and reset it. We may reenter stackless at a completely different * depth later diff --git a/Stackless/module/scheduling.c b/Stackless/module/scheduling.c index d93045680582da..6d3b357c28e41f 100644 --- a/Stackless/module/scheduling.c +++ b/Stackless/module/scheduling.c @@ -5,7 +5,7 @@ #ifdef STACKLESS #include "pycore_stackless.h" - +// #include "pycore_slp_platformselect.h" /* for SLP_DO_NOT_OPTIMIZE_AWAY */ /****************************************************** diff --git a/Stackless/module/stacklessmodule.c b/Stackless/module/stacklessmodule.c index 16e6470d8eac9a..8b91410449c759 100644 --- a/Stackless/module/stacklessmodule.c +++ b/Stackless/module/stacklessmodule.c @@ -7,7 +7,7 @@ #include "pycore_stackless.h" #define IMPLEMENT_STACKLESSMODULE -#include "pycore_slp_platformselect.h" +// #include "pycore_slp_platformselect.h" #include "pycore_slp_prickelpit.h" #include /* for offsetof() */ diff --git a/Stackless/pickling/prickelpit.c b/Stackless/pickling/prickelpit.c index 689f793d24842e..c894510dfaaa90 100644 --- a/Stackless/pickling/prickelpit.c +++ b/Stackless/pickling/prickelpit.c @@ -8,7 +8,7 @@ #include "pycore_slp_prickelpit.h" /* platform specific constants */ -#include "pycore_slp_platformselect.h" +// #include "pycore_slp_platformselect.h" /****************************************************** diff --git a/Stackless/pickling/safe_pickle.c b/Stackless/pickling/safe_pickle.c index d8a0ac76a5afd9..42e7020271c061 100644 --- a/Stackless/pickling/safe_pickle.c +++ b/Stackless/pickling/safe_pickle.c @@ -5,7 +5,7 @@ #define SLP_BUILD_CORE #include "pycore_stackless.h" -#include "pycore_slp_platformselect.h" +// #include "pycore_slp_platformselect.h" /* safe pickling */ @@ -31,7 +31,7 @@ pickle_callback(PyCFrameObject *cf, int exc, PyObject *retval) * ourselves in an infinite loop of stack spilling. */ saved_base = ts->st.cstack_root; - ts->st.cstack_root = SLP_STACK_REFPLUS + (intptr_t *) &f; + SLP_CSTACK_SET_ROOT(ts, f); if (retval) { Py_DECREF(retval); cf->i = cPickle_save(cf->ob1, cf->ob2, cf->n); @@ -128,7 +128,7 @@ pickle_M(PyObject *self, PyObject *args, int pers_save) _self = self; _args = args; _pers_save = pers_save; - ts->st.cstack_root = SLP_STACK_REFPLUS + (intptr_t *) &self; + SLP_CSTACK_SET_ROOT(ts, self); ret = slp_int_wrapper(slp_eval_frame((PyFrameObject *)cf)); return ret; } From 7faf7067ddf2a3790d68ce051296fe4e24f5aa62 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Thu, 1 Jul 2021 09:13:27 +0200 Subject: [PATCH 04/11] Stackless issue #282: Refactor slp_eval_frame Decouple the cleanup logic for initial stubs of sub-interpreters from the stack handling. Previously this logic depended on the value of SLP_CSTACK_GOODGAP being positive. --- Stackless/core/stacklesseval.c | 86 +++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/Stackless/core/stacklesseval.c b/Stackless/core/stacklesseval.c index 695c7defcf22a0..93d8daa29dd6c3 100644 --- a/Stackless/core/stacklesseval.c +++ b/Stackless/core/stacklesseval.c @@ -317,6 +317,7 @@ slp_eval_frame(PyFrameObject *f) PyThreadState *ts = _PyThreadState_GET(); PyFrameObject *fprev = f->f_back; intptr_t * stackref; + int set_cstack_base; PyObject *retval; if (fprev == NULL && ts->st.main == NULL) { @@ -345,51 +346,58 @@ slp_eval_frame(PyFrameObject *f) /* mark the stack base */ stackref = SLP_STACK_REFPLUS + (intptr_t *) &f; - if (ts->st.cstack_base == NULL) + set_cstack_base = ts->st.cstack_base == NULL; + if (set_cstack_base) ts->st.cstack_base = stackref - SLP_CSTACK_GOODGAP; if (stackref > ts->st.cstack_base) { - PyCStackObject *initial_stub; - retval = climb_stack_and_eval_frame(f); - initial_stub = ts->st.initial_stub; - /* cst might be NULL in OOM conditions */ - if (ts->interp != _PyRuntime.interpreters.main && initial_stub != NULL) { - PyCStackObject *cst; - register int found = 0; - assert(initial_stub->startaddr == ts->st.cstack_base); - for (cst = initial_stub->next; cst != initial_stub; cst = cst->next) { - if (Py_SIZE(cst) != 0 && cst->task != NULL && - cst->tstate == ts) { - assert(cst->startaddr == ts->st.cstack_base); - found = 1; - break; - } - } - if (!found) { - Py_CLEAR(ts->st.initial_stub); - ts->st.cstack_base = NULL; - ts->st.cstack_root = NULL; - } + retval = climb_stack_and_eval_frame(f); /* recursively calls slp_eval_frame(f) */ + } else { + assert(SLP_CURRENT_FRAME(ts) == NULL); /* else we would change the current frame */ + SLP_STORE_NEXT_FRAME(ts, f); + returning = make_initial_stub(); + if (returning < 0) + return NULL; + /* returning will be 1 if we "switched back" to this stub, and 0 + * if this is the original call that just created the stub. + * If the stub is being reused, the argument, i.e. the frame, + * is in ts->frame + */ + SLP_ASSERT_FRAME_IN_TRANSFER(ts); + if (returning != 1) { + assert(f == SLP_PEEK_NEXT_FRAME(ts)); } - return retval; + assert(ts->interp->st.initial_tstate != NULL); + assert(ts->interp->st.mem_bomb != NULL); + + retval = slp_run_tasklet(); } - assert(SLP_CURRENT_FRAME(ts) == NULL); /* else we would change the current frame */ - SLP_STORE_NEXT_FRAME(ts, f); - returning = make_initial_stub(); - if (returning < 0) - return NULL; - /* returning will be 1 if we "switched back" to this stub, and 0 - * if this is the original call that just created the stub. - * If the stub is being reused, the argument, i.e. the frame, - * is in ts->frame - */ - SLP_ASSERT_FRAME_IN_TRANSFER(ts); - if (returning != 1) { - assert(f == SLP_PEEK_NEXT_FRAME(ts)); + /* Clear the initial stub, except for the main interpreter. + * Without this code, terminating sub-interpreters would leak references. */ + if (set_cstack_base /* only for the outermost call */ + && ts->interp != _PyRuntime.interpreters.main /* not for the main interpreter */ + && ts->st.initial_stub != NULL) /* not yet cleared */ + { + PyCStackObject *initial_stub = ts->st.initial_stub; + PyCStackObject *cst; + register int found = 0; + assert(initial_stub->startaddr == ts->st.cstack_base); + for (cst = initial_stub->next; cst != initial_stub; cst = cst->next) { + if (Py_SIZE(cst) != 0 && cst->task != NULL && + cst->tstate == ts) { + assert(cst->startaddr == ts->st.cstack_base); + found = 1; /* Initial stub is still in use. */ + break; + } + } + if (!found) { + /* This initial stub is no longer in use, free it */ + Py_CLEAR(ts->st.initial_stub); + ts->st.cstack_base = NULL; + ts->st.cstack_root = NULL; + } } - assert(ts->interp->st.initial_tstate != NULL); - assert(ts->interp->st.mem_bomb != NULL); - return slp_run_tasklet(); + return retval; } assert(ts->interp->st.initial_tstate != NULL); assert(ts->interp->st.mem_bomb != NULL); /* see above */ From cc159a355d6309d7e1b158ffe222aa35323e59fd Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Thu, 1 Jul 2021 11:45:54 +0200 Subject: [PATCH 05/11] Stackless issue #283: Concentrate platform code in slp_transfer.c Extract the platform specific stack handling form "slp_eval_frame" into a new function "slp_cstack_set_base_and_goodgap" in slp_transfer.c. --- Include/internal/pycore_stackless.h | 5 ++--- Stackless/core/slp_transfer.c | 18 ++++++++++++++++-- Stackless/core/stacklesseval.c | 11 +++-------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Include/internal/pycore_stackless.h b/Include/internal/pycore_stackless.h index fe25334d117941..a5f9f639bc0ba9 100644 --- a/Include/internal/pycore_stackless.h +++ b/Include/internal/pycore_stackless.h @@ -823,8 +823,7 @@ long slp_parse_thread_id(PyObject *thread_id, unsigned long *id); (frame_)->f_executing <= SLP_FRAME_EXECUTING_YIELD_FROM) -/* Stuff originally in pycore_slp_platformselect.h */ - +/* Defined in slp_transfer.c */ int slp_cstack_save_now(const PyThreadState *tstate, const void * pstackvar); #define SLP_CSTACK_SAVE_NOW(tstate, stackvar) slp_cstack_save_now((tstate), &(stackvar)) @@ -832,7 +831,7 @@ void slp_cstack_set_root(PyThreadState *tstate, const void * pstackvar); #define SLP_CSTACK_SET_ROOT(tstate, stackvar) slp_cstack_set_root((tstate), &(stackvar)) PyObject * -slp_climb_stack_and_eval_frame(PyFrameObject *f); +slp_cstack_set_base_and_goodgap(PyThreadState *tstate, const void * pstackvar, PyFrameObject *f); /* * Call SLP_DO_NOT_OPTIMIZE_AWAY(pointer) to ensure that pointer will be diff --git a/Stackless/core/slp_transfer.c b/Stackless/core/slp_transfer.c index 8b2d34ec754166..a0d28187d7d7b7 100644 --- a/Stackless/core/slp_transfer.c +++ b/Stackless/core/slp_transfer.c @@ -117,8 +117,8 @@ climb_stack_and_transfer(PyCStackObject **cstprev, PyCStackObject *cst, return slp_transfer(cstprev, cst, prev); } -PyObject * -slp_climb_stack_and_eval_frame(PyFrameObject *f) +static PyObject * +climb_stack_and_eval_frame(PyFrameObject *f) { /* * a similar case to climb_stack_and_transfer, @@ -232,6 +232,20 @@ slp_cstack_set_root(PyThreadState *tstate, const void * pstackvar) { tstate->st.cstack_root = SLP_STACK_REFPLUS + (intptr_t *)pstackvar; } +PyObject * +slp_cstack_set_base_and_goodgap(PyThreadState *tstate, const void * pstackvar, PyFrameObject *f) { + intptr_t * stackref; + assert(tstate); + assert(pstackvar); + tstate->st.cstack_root = SLP_STACK_REFPLUS + (intptr_t *)pstackvar; + stackref = SLP_STACK_REFPLUS + (intptr_t *)pstackvar; + if (tstate->st.cstack_base == NULL) + tstate->st.cstack_base = stackref - SLP_CSTACK_GOODGAP; + if (stackref > tstate->st.cstack_base) + return climb_stack_and_eval_frame(f); /* recursively calls slp_eval_frame(f) */ + return (void *)1; +} + #ifdef Py_DEBUG int slp_transfer_return(PyCStackObject *cst) diff --git a/Stackless/core/stacklesseval.c b/Stackless/core/stacklesseval.c index 3721643f67fe61..373a6546037b2f 100644 --- a/Stackless/core/stacklesseval.c +++ b/Stackless/core/stacklesseval.c @@ -9,7 +9,7 @@ #include "pycore_slp_prickelpit.h" /* platform specific constants */ -#include "pycore_slp_platformselect.h" +//#include "pycore_slp_platformselect.h" /* Stackless extension for ceval.c */ @@ -316,7 +316,6 @@ slp_eval_frame(PyFrameObject *f) { PyThreadState *ts = _PyThreadState_GET(); PyFrameObject *fprev = f->f_back; - intptr_t * stackref; int set_cstack_base; PyObject *retval; @@ -345,13 +344,9 @@ slp_eval_frame(PyFrameObject *f) } /* mark the stack base */ - stackref = SLP_STACK_REFPLUS + (intptr_t *) &f; set_cstack_base = ts->st.cstack_base == NULL; - if (set_cstack_base) - ts->st.cstack_base = stackref - SLP_CSTACK_GOODGAP; - if (stackref > ts->st.cstack_base) { - retval = slp_climb_stack_and_eval_frame(f); /* recursively calls slp_eval_frame(f) */ - } else { + retval = slp_cstack_set_base_and_goodgap(ts, &f, f); + if (retval == (void*)1) { assert(SLP_CURRENT_FRAME(ts) == NULL); /* else we would change the current frame */ SLP_STORE_NEXT_FRAME(ts, f); returning = make_initial_stub(); From 24acb96f76311e18b182d1f5f93228d3cf16e903 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Thu, 1 Jul 2021 11:51:32 +0200 Subject: [PATCH 06/11] Stackless issue #283: Concentrate platform code in slp_transfer.c Move the definition of SLP_DO_NOT_OPTIMIZE_AWAY from pycore_stackless.h to slp_transfer.c, because it is only used there. --- Include/internal/pycore_stackless.h | 45 --------------------------- Stackless/core/slp_transfer.c | 47 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 45 deletions(-) diff --git a/Include/internal/pycore_stackless.h b/Include/internal/pycore_stackless.h index a5f9f639bc0ba9..aff5e11d677dcf 100644 --- a/Include/internal/pycore_stackless.h +++ b/Include/internal/pycore_stackless.h @@ -833,51 +833,6 @@ slp_cstack_set_root(PyThreadState *tstate, const void * pstackvar); PyObject * slp_cstack_set_base_and_goodgap(PyThreadState *tstate, const void * pstackvar, PyFrameObject *f); -/* - * Call SLP_DO_NOT_OPTIMIZE_AWAY(pointer) to ensure that pointer will be - * computed even post-optimization. Use it for pointers that are computed but - * otherwise are useless. The compiler tends to do a good job at eliminating - * unused variables, and this macro fools it into thinking var is in fact - * needed. - */ - -#ifndef SLP_DO_NOT_OPTIMIZE_AWAY - -/* Code is based on Facebook folly - * https://github.com/facebook/folly/blob/master/folly/Benchmark.h, - * which has an Apache 2 license. - */ -#ifdef _MSC_VER - -#pragma optimize("", off) - -static inline void doNotOptimizeDependencySink(const void* p) {} - -#pragma optimize("", on) - -#define SLP_DO_NOT_OPTIMIZE_AWAY(pointer) doNotOptimizeDependencySink(pointer) -#define SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS /* empty */ - -#elif (defined(__GNUC__) || defined(__clang__)) -/* - * The "r" constraint forces the compiler to make datum available - * in a register to the asm block, which means that it must have - * computed/loaded it. - */ -#define SLP_DO_NOT_OPTIMIZE_AWAY(pointer) \ - do {__asm__ volatile("" ::"r"(pointer));} while(0) -#define SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS /* empty */ -#else -/* - * Unknown compiler - */ -#define SLP_DO_NOT_OPTIMIZE_AWAY(pointer) \ - do { slp_do_not_opimize_away_sink = ((void*)(pointer)); } while(0) -extern uint8_t* volatile slp_do_not_opimize_away_sink; -#define SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS uint8_t* volatile slp_do_not_opimize_away_sink; -#endif -#endif /* #ifndef SLP_DO_NOT_OPTIMIZE_AWAY */ - #endif /* #ifdef SLP_BUILD_CORE */ diff --git a/Stackless/core/slp_transfer.c b/Stackless/core/slp_transfer.c index a0d28187d7d7b7..60b2236652ac7d 100644 --- a/Stackless/core/slp_transfer.c +++ b/Stackless/core/slp_transfer.c @@ -54,6 +54,53 @@ or disable the STACKLESS flag. ********** #endif +/* + * Call SLP_DO_NOT_OPTIMIZE_AWAY(pointer) to ensure that pointer will be + * computed even post-optimization. Use it for pointers that are computed but + * otherwise are useless. The compiler tends to do a good job at eliminating + * unused variables, and this macro fools it into thinking var is in fact + * needed. + * + * A platform specific include may provide its own definition of + * SLP_DO_NOT_OPTIMIZE_AWAY and SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS. + */ +#ifndef SLP_DO_NOT_OPTIMIZE_AWAY + +/* Code is based on Facebook folly + * https://github.com/facebook/folly/blob/master/folly/Benchmark.h, + * which has an Apache 2 license. + */ +#ifdef _MSC_VER + +#pragma optimize("", off) + +static inline void doNotOptimizeDependencySink(const void* p) {} + +#pragma optimize("", on) + +#define SLP_DO_NOT_OPTIMIZE_AWAY(pointer) doNotOptimizeDependencySink(pointer) +#define SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS /* empty */ + +#elif (defined(__GNUC__) || defined(__clang__)) +/* + * The "r" constraint forces the compiler to make datum available + * in a register to the asm block, which means that it must have + * computed/loaded it. + */ +#define SLP_DO_NOT_OPTIMIZE_AWAY(pointer) \ + do {__asm__ volatile("" ::"r"(pointer));} while(0) +#define SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS /* empty */ +#else +/* + * Unknown compiler + */ +#define SLP_DO_NOT_OPTIMIZE_AWAY(pointer) \ + do { slp_do_not_opimize_away_sink = ((void*)(pointer)); } while(0) +extern uint8_t* volatile slp_do_not_opimize_away_sink; +#define SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS uint8_t* volatile slp_do_not_opimize_away_sink; +#endif +#endif /* #ifndef SLP_DO_NOT_OPTIMIZE_AWAY */ + SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS #ifdef SLP_EXTERNAL_ASM From a5e69d5aef1cfc814edcd620afd4fd983d97c83a Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Thu, 1 Jul 2021 11:52:16 +0200 Subject: [PATCH 07/11] Stackless issue #283: Concentrate platform code in slp_transfer.c Remove commented code. --- Include/internal/pycore_slp_platformselect.h | 5 ---- Python/ceval.c | 1 - Stackless/core/stacklesseval.c | 29 -------------------- Stackless/module/scheduling.c | 1 - Stackless/module/stacklessmodule.c | 1 - Stackless/pickling/prickelpit.c | 3 -- Stackless/pickling/safe_pickle.c | 1 - 7 files changed, 41 deletions(-) diff --git a/Include/internal/pycore_slp_platformselect.h b/Include/internal/pycore_slp_platformselect.h index 1d874b799208e3..7c8d5b5fda3537 100644 --- a/Include/internal/pycore_slp_platformselect.h +++ b/Include/internal/pycore_slp_platformselect.h @@ -70,9 +70,4 @@ #define SLP_CSTACK_SUBTRACT(a, b) (b) - (a) #endif -#define SLP_CSTACK_SAVE_NOW_to_be_deleted(tstate, stackvar) \ - ((tstate)->st.cstack_root != NULL ? \ - SLP_CSTACK_SUBTRACT((tstate)->st.cstack_root, \ - (intptr_t*)&(stackvar)) > SLP_CSTACK_WATERMARK : 1) - #endif /* !STACKLESS_SLP_PLATFORM_SELECT_H */ diff --git a/Python/ceval.c b/Python/ceval.c index 56afb91eab83c4..1fb5d3d9cc5f91 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -22,7 +22,6 @@ #include "setobject.h" #include "structmember.h" #include "pycore_stackless.h" -// #include "pycore_slp_platformselect.h" /* for stack saving */ #include diff --git a/Stackless/core/stacklesseval.c b/Stackless/core/stacklesseval.c index 373a6546037b2f..73db0fa5a06d6e 100644 --- a/Stackless/core/stacklesseval.c +++ b/Stackless/core/stacklesseval.c @@ -8,9 +8,6 @@ #include "pycore_stackless.h" #include "pycore_slp_prickelpit.h" -/* platform specific constants */ -//#include "pycore_slp_platformselect.h" - /* Stackless extension for ceval.c */ @@ -243,32 +240,6 @@ make_initial_stub(void) return result; } -//static PyObject * -//climb_stack_and_eval_frame(PyFrameObject *f) -//{ -// /* -// * a similar case to climb_stack_and_transfer, -// * but here we need to incorporate a gap in the -// * stack into main and keep this gap on the stack. -// * This way, initial_stub is always valid to be -// * used to return to the main c stack. -// */ -// PyThreadState *ts = _PyThreadState_GET(); -// intptr_t probe; -// ptrdiff_t needed = &probe - ts->st.cstack_base; -// /* in rare cases, the need might have vanished due to the recursion */ -// if (needed > 0) { -// register void * stack_ptr_tmp = alloca(needed * sizeof(intptr_t)); -// if (stack_ptr_tmp == NULL) -// return NULL; -// /* hinder the compiler to optimise away -// stack_ptr_tmp and the alloca call. -// This happens with gcc 4.7.x and -O2 */ -// SLP_DO_NOT_OPTIMIZE_AWAY(stack_ptr_tmp); -// } -// return slp_eval_frame(f); -//} - static PyObject * slp_frame_dispatch_top(PyObject *retval); static PyObject * diff --git a/Stackless/module/scheduling.c b/Stackless/module/scheduling.c index 6d3b357c28e41f..3d7034c61901ea 100644 --- a/Stackless/module/scheduling.c +++ b/Stackless/module/scheduling.c @@ -5,7 +5,6 @@ #ifdef STACKLESS #include "pycore_stackless.h" -// #include "pycore_slp_platformselect.h" /* for SLP_DO_NOT_OPTIMIZE_AWAY */ /****************************************************** diff --git a/Stackless/module/stacklessmodule.c b/Stackless/module/stacklessmodule.c index 8b91410449c759..21ebd701c2a044 100644 --- a/Stackless/module/stacklessmodule.c +++ b/Stackless/module/stacklessmodule.c @@ -7,7 +7,6 @@ #include "pycore_stackless.h" #define IMPLEMENT_STACKLESSMODULE -// #include "pycore_slp_platformselect.h" #include "pycore_slp_prickelpit.h" #include /* for offsetof() */ diff --git a/Stackless/pickling/prickelpit.c b/Stackless/pickling/prickelpit.c index c894510dfaaa90..69d8fbed8b9189 100644 --- a/Stackless/pickling/prickelpit.c +++ b/Stackless/pickling/prickelpit.c @@ -7,9 +7,6 @@ #include "pycore_stackless.h" #include "pycore_slp_prickelpit.h" -/* platform specific constants */ -// #include "pycore_slp_platformselect.h" - /****************************************************** type template and support for pickle helper types diff --git a/Stackless/pickling/safe_pickle.c b/Stackless/pickling/safe_pickle.c index 42e7020271c061..241937bc343c43 100644 --- a/Stackless/pickling/safe_pickle.c +++ b/Stackless/pickling/safe_pickle.c @@ -5,7 +5,6 @@ #define SLP_BUILD_CORE #include "pycore_stackless.h" -// #include "pycore_slp_platformselect.h" /* safe pickling */ From aab7c93a247255bb4fd147b1744bc37e5bf5ae62 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Thu, 1 Jul 2021 12:17:15 +0200 Subject: [PATCH 08/11] Stackless issue #283: Concentrate platform code in slp_transfer.c Integrate include "pycore_slp_platformselect.h" into slp_transfer.c and remove this include. --- Include/internal/pycore_slp_platformselect.h | 73 --------------- Makefile.pre.in | 1 - PCbuild/pythoncore.vcxproj | 1 - PCbuild/pythoncore.vcxproj.filters | 3 - Stackless/core/slp_transfer.c | 95 ++++++++++++++++---- 5 files changed, 79 insertions(+), 94 deletions(-) delete mode 100644 Include/internal/pycore_slp_platformselect.h diff --git a/Include/internal/pycore_slp_platformselect.h b/Include/internal/pycore_slp_platformselect.h deleted file mode 100644 index 7c8d5b5fda3537..00000000000000 --- a/Include/internal/pycore_slp_platformselect.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef PYCORE_SLP_PLATFORMSELECT_H -#define PYCORE_SLP_PLATFORMSELECT_H - -/* - * Platform Selection for Stackless - */ - -#if defined(MS_WIN32) && !defined(MS_WIN64) && defined(_M_IX86) -#include "pycore_slp_switch_x86_msvc.h" /* MS Visual Studio on X86 */ -#elif defined(MS_WIN64) && defined(_M_X64) -#include "pycore_slp_switch_x64_msvc.h" /* MS Visual Studio on X64 */ -#elif defined(__GNUC__) && defined(__i386__) -#include "pycore_slp_switch_x86_unix.h" /* gcc on X86 */ -#elif defined(__GNUC__) && defined(__amd64__) -#include "pycore_slp_switch_amd64_unix.h" /* gcc on amd64 */ -#elif defined(__GNUC__) && defined(__PPC__) && defined(__linux__) -#include "pycore_slp_switch_ppc_unix.h" /* gcc on PowerPC */ -#elif defined(__GNUC__) && defined(__ppc__) && defined(__APPLE__) -#include "pycore_slp_switch_ppc_macosx.h" /* Apple MacOS X on PowerPC */ -#elif defined(__GNUC__) && defined(sparc) && defined(sun) -#include "pycore_slp_switch_sparc_sun_gcc.h" /* SunOS sparc with gcc */ -#elif defined(__GNUC__) && defined(__s390__) && defined(__linux__) -#include "pycore_slp_switch_s390_unix.h" /* Linux/S390 */ -#elif defined(__GNUC__) && defined(__s390x__) && defined(__linux__) -#include "pycore_slp_switch_s390_unix.h" /* Linux/S390 zSeries (identical) */ -#elif defined(__GNUC__) && defined(__arm__) && defined(__thumb__) -#include "pycore_slp_switch_arm_thumb_gcc.h" /* gcc using arm thumb */ -#elif defined(__GNUC__) && defined(__arm32__) -#include "pycore_slp_switch_arm32_gcc.h" /* gcc using arm32 */ -#elif defined(__GNUC__) && defined(__mips__) && defined(__linux__) -#include "pycore_slp_switch_mips_unix.h" /* MIPS */ -#elif defined(SN_TARGET_PS3) -#include "pycore_slp_switch_ps3_SNTools.h" /* Sony PS3 */ -#endif - -/* default definitions if not defined in above files */ - - -/* a good estimate how much the cstack level differs between - initialisation and main C-Python(r) code. Not critical, but saves time. - Note that this will vanish with the greenlet approach. */ - -#ifndef SLP_CSTACK_GOODGAP -#define SLP_CSTACK_GOODGAP 4096 -#endif - -/* stack size in pointer to trigger stack spilling */ - -#ifndef SLP_CSTACK_WATERMARK -#define SLP_CSTACK_WATERMARK 16384 -#endif - -/* define direction of stack growth */ - -#ifndef SLP_CSTACK_DOWNWARDS -#define SLP_CSTACK_DOWNWARDS 1 /* 0 for upwards */ -#endif - -/************************************************************** - - Don't change definitions below, please. - - **************************************************************/ - -#if SLP_CSTACK_DOWNWARDS == 1 -#define SLP_CSTACK_COMPARE(a, b) (a) < (b) -#define SLP_CSTACK_SUBTRACT(a, b) (a) - (b) -#else -#define SLP_CSTACK_COMPARE(a, b) (a) > (b) -#define SLP_CSTACK_SUBTRACT(a, b) (b) - (a) -#endif - -#endif /* !STACKLESS_SLP_PLATFORM_SELECT_H */ diff --git a/Makefile.pre.in b/Makefile.pre.in index 7596042b18337e..5a775608044b2f 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1093,7 +1093,6 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_stackless.h \ $(srcdir)/Include/internal/pycore_slp_pystate.h \ $(srcdir)/Include/internal/pycore_slp_prickelpit.h \ - $(srcdir)/Include/internal/pycore_slp_platformselect.h \ $(srcdir)/Include/internal/pycore_slp_switch_amd64_unix.h \ $(srcdir)/Include/internal/pycore_slp_switch_arm32_gcc.h \ $(srcdir)/Include/internal/pycore_slp_switch_arm_thumb_gcc.h \ diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 46863913aeaa06..295a984b5cc164 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -238,7 +238,6 @@ - diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 5a36316dea618b..484fdc8601911d 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -525,9 +525,6 @@ Include - - Include - Include diff --git a/Stackless/core/slp_transfer.c b/Stackless/core/slp_transfer.c index 60b2236652ac7d..0f31800dc21ac8 100644 --- a/Stackless/core/slp_transfer.c +++ b/Stackless/core/slp_transfer.c @@ -35,16 +35,37 @@ } /* - * Include pycore_slp_platformselect.h with SLP_EVAL defined. - * If the macro SLP_EVAL is defined, pycore_slp_platformselect.h defines - * the static function int slp_switch(void). + * Platform Selection for Stackless */ -#define SLP_EVAL -#ifdef PYCORE_SLP_PLATFORMSELECT_H -#undef PYCORE_SLP_PLATFORMSELECT_H +#define SLP_EVAL /* enable code generation in the included header */ + +#if defined(MS_WIN32) && !defined(MS_WIN64) && defined(_M_IX86) +#include "pycore_slp_switch_x86_msvc.h" /* MS Visual Studio on X86 */ +#elif defined(MS_WIN64) && defined(_M_X64) +#include "pycore_slp_switch_x64_msvc.h" /* MS Visual Studio on X64 */ +#elif defined(__GNUC__) && defined(__i386__) +#include "pycore_slp_switch_x86_unix.h" /* gcc on X86 */ +#elif defined(__GNUC__) && defined(__amd64__) +#include "pycore_slp_switch_amd64_unix.h" /* gcc on amd64 */ +#elif defined(__GNUC__) && defined(__PPC__) && defined(__linux__) +#include "pycore_slp_switch_ppc_unix.h" /* gcc on PowerPC */ +#elif defined(__GNUC__) && defined(__ppc__) && defined(__APPLE__) +#include "pycore_slp_switch_ppc_macosx.h" /* Apple MacOS X on PowerPC */ +#elif defined(__GNUC__) && defined(sparc) && defined(sun) +#include "pycore_slp_switch_sparc_sun_gcc.h" /* SunOS sparc with gcc */ +#elif defined(__GNUC__) && defined(__s390__) && defined(__linux__) +#include "pycore_slp_switch_s390_unix.h" /* Linux/S390 */ +#elif defined(__GNUC__) && defined(__s390x__) && defined(__linux__) +#include "pycore_slp_switch_s390_unix.h" /* Linux/S390 zSeries (identical) */ +#elif defined(__GNUC__) && defined(__arm__) && defined(__thumb__) +#include "pycore_slp_switch_arm_thumb_gcc.h" /* gcc using arm thumb */ +#elif defined(__GNUC__) && defined(__arm32__) +#include "pycore_slp_switch_arm32_gcc.h" /* gcc using arm32 */ +#elif defined(__GNUC__) && defined(__mips__) && defined(__linux__) +#include "pycore_slp_switch_mips_unix.h" /* MIPS */ +#elif defined(SN_TARGET_PS3) +#include "pycore_slp_switch_ps3_SNTools.h" /* Sony PS3 */ #endif -#include "pycore_slp_platformselect.h" - #ifndef STACKLESS ********** If you see this error message, @@ -54,6 +75,30 @@ or disable the STACKLESS flag. ********** #endif +/* default definitions if not defined in above files */ + + +/* a good estimate how much the cstack level differs between + initialisation and main C-Python(r) code. Not critical, but saves time. + Note that this will vanish with the greenlet approach. */ + +#ifndef SLP_CSTACK_GOODGAP +#define SLP_CSTACK_GOODGAP 4096 +#endif + +/* stack size in pointer to trigger stack spilling */ + +#ifndef SLP_CSTACK_WATERMARK +#define SLP_CSTACK_WATERMARK 16384 +#endif + +/* define direction of stack growth */ + +#ifndef SLP_CSTACK_DOWNWARDS +#define SLP_CSTACK_DOWNWARDS 1 /* 0 for upwards */ +#endif + + /* * Call SLP_DO_NOT_OPTIMIZE_AWAY(pointer) to ensure that pointer will be * computed even post-optimization. Use it for pointers that are computed but @@ -101,6 +146,24 @@ extern uint8_t* volatile slp_do_not_opimize_away_sink; #endif #endif /* #ifndef SLP_DO_NOT_OPTIMIZE_AWAY */ +/************************************************************** + + Don't change definitions below, please. + + **************************************************************/ + +#if SLP_CSTACK_DOWNWARDS == 1 +#define SLP_CSTACK_COMPARE(a, b) (a) < (b) +#define SLP_CSTACK_SUBTRACT(a, b) (a) - (b) +#else +#define SLP_CSTACK_COMPARE(a, b) (a) > (b) +#define SLP_CSTACK_SUBTRACT(a, b) (b) - (a) +#endif + +/************************************************************** + * End of definitions + ***************************************************************/ + SLP_DO_NOT_OPTIMIZE_AWAY_DEFINITIONS #ifdef SLP_EXTERNAL_ASM @@ -262,6 +325,14 @@ slp_transfer(PyCStackObject **cstprev, PyCStackObject *cst, return result; } +#ifdef Py_DEBUG +int +slp_transfer_return(PyCStackObject *cst) +{ + return slp_transfer(NULL, cst, NULL); +} +#endif + int slp_cstack_save_now(const PyThreadState *tstate, const void * pstackvar) { @@ -293,12 +364,4 @@ slp_cstack_set_base_and_goodgap(PyThreadState *tstate, const void * pstackvar, P return (void *)1; } -#ifdef Py_DEBUG -int -slp_transfer_return(PyCStackObject *cst) -{ - return slp_transfer(NULL, cst, NULL); -} -#endif - #endif From 12498e71455ee86dbd350bb46daf9f9a3827042c Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Thu, 1 Jul 2021 12:27:01 +0200 Subject: [PATCH 09/11] Stackless issue #283: Concentrate platform code in slp_transfer.c Move "slp_transfer.c" form "Stackless/core" to "Stackless/platf", because it depends on the platform. --- Makefile.pre.in | 6 +++--- PCbuild/pythoncore.vcxproj | 2 +- PCbuild/pythoncore.vcxproj.filters | 4 ++-- Stackless/{core => platf}/slp_transfer.c | 0 4 files changed, 6 insertions(+), 6 deletions(-) rename Stackless/{core => platf}/slp_transfer.c (100%) diff --git a/Makefile.pre.in b/Makefile.pre.in index 5a775608044b2f..0cf5c1c2ce443c 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -339,7 +339,7 @@ PYTHON_OBJS= \ Python/bltinmodule.o \ Python/ceval.o \ Stackless/core/cframeobject.o \ - Stackless/core/slp_transfer.o \ + Stackless/platf/slp_transfer.o \ Stackless/core/stacklesseval.o \ Stackless/core/stackless_util.o \ Stackless/module/channelobject.o \ @@ -989,8 +989,8 @@ regen-typeslots: $(srcdir)/Objects/typeslots.inc.new $(UPDATE_FILE) $(srcdir)/Objects/typeslots.inc $(srcdir)/Objects/typeslots.inc.new -Stackless/core/slp_transfer.o: $(srcdir)/Stackless/core/slp_transfer.c - $(CC) -c $(PY_CORE_CFLAGS) $(SLPFLAGS) -o $@ $(srcdir)/Stackless/core/slp_transfer.c +Stackless/platf/slp_transfer.o: $(srcdir)/Stackless/platf/slp_transfer.c + $(CC) -c $(PY_CORE_CFLAGS) $(SLPFLAGS) -o $@ $(srcdir)/Stackless/platf/slp_transfer.c ############################################################################ # Header files diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 295a984b5cc164..0fdf36d215dacb 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -438,7 +438,7 @@ - + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 484fdc8601911d..cc1816f4a629ed 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -1160,8 +1160,8 @@ Stackless\core - - Stackless\core + + Stackless\platf Stackless\core diff --git a/Stackless/core/slp_transfer.c b/Stackless/platf/slp_transfer.c similarity index 100% rename from Stackless/core/slp_transfer.c rename to Stackless/platf/slp_transfer.c From d289e99e450390aec043fbeabf1753c2bc359a81 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Thu, 1 Jul 2021 12:34:03 +0200 Subject: [PATCH 10/11] Stackless issue #283: Concentrate platform code in slp_transfer.c Add a changelog entry. --- Stackless/changelog.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Stackless/changelog.txt b/Stackless/changelog.txt index 6aaf94820b9923..7f5ff85d7b2825 100644 --- a/Stackless/changelog.txt +++ b/Stackless/changelog.txt @@ -9,6 +9,11 @@ What's New in Stackless 3.X.X? *Release date: 20XX-XX-XX* +- https://github.com/stackless-dev/stackless/issues/283 + Platform dependent source code is now completely in "Stackless/platf". The + API header files do not depend on the platform any longer and the header + "pycore_slp_platformselect.h" does not exist any more. + - https://github.com/stackless-dev/stackless/issues/281 Per tasklet profiling and tracing state information is now stored in the tasklet itself. This increases the size of tasklet objects a bit, but saves a From 82eaada208cbaa5bc07963103931cebda2f065cd Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Thu, 1 Jul 2021 13:08:04 +0200 Subject: [PATCH 11/11] Stackless issue #283: Concentrate platform code in slp_transfer.c Move all pycore_slp_switch_*.h includes from Include/internal to Stackless/platf. These headers are included by "slp_transfer.c" only. --- Makefile.pre.in | 24 ++++++++--------- PCbuild/pythoncore.vcxproj | 4 +-- PCbuild/pythoncore.vcxproj.filters | 4 +-- Stackless/platf/slp_transfer.c | 26 +++++++++---------- .../platf/switch_amd64_unix.h | 0 .../platf/switch_arm32_gcc.h | 0 .../platf/switch_arm_thumb_gcc.h | 0 .../platf/switch_mips_unix.h | 0 .../platf/switch_ppc_macosx.h | 0 .../platf/switch_ppc_unix.h | 0 .../platf/switch_ps3_SNTools.h | 0 .../platf/switch_s390_unix.h | 0 .../platf/switch_sparc_sun_gcc.h | 0 .../platf/switch_x64_msvc.h | 0 .../platf/switch_x86_msvc.h | 0 .../platf/switch_x86_unix.h | 0 16 files changed, 29 insertions(+), 29 deletions(-) rename Include/internal/pycore_slp_switch_amd64_unix.h => Stackless/platf/switch_amd64_unix.h (100%) rename Include/internal/pycore_slp_switch_arm32_gcc.h => Stackless/platf/switch_arm32_gcc.h (100%) rename Include/internal/pycore_slp_switch_arm_thumb_gcc.h => Stackless/platf/switch_arm_thumb_gcc.h (100%) rename Include/internal/pycore_slp_switch_mips_unix.h => Stackless/platf/switch_mips_unix.h (100%) rename Include/internal/pycore_slp_switch_ppc_macosx.h => Stackless/platf/switch_ppc_macosx.h (100%) rename Include/internal/pycore_slp_switch_ppc_unix.h => Stackless/platf/switch_ppc_unix.h (100%) rename Include/internal/pycore_slp_switch_ps3_SNTools.h => Stackless/platf/switch_ps3_SNTools.h (100%) rename Include/internal/pycore_slp_switch_s390_unix.h => Stackless/platf/switch_s390_unix.h (100%) rename Include/internal/pycore_slp_switch_sparc_sun_gcc.h => Stackless/platf/switch_sparc_sun_gcc.h (100%) rename Include/internal/pycore_slp_switch_x64_msvc.h => Stackless/platf/switch_x64_msvc.h (100%) rename Include/internal/pycore_slp_switch_x86_msvc.h => Stackless/platf/switch_x86_msvc.h (100%) rename Include/internal/pycore_slp_switch_x86_unix.h => Stackless/platf/switch_x86_unix.h (100%) diff --git a/Makefile.pre.in b/Makefile.pre.in index 0cf5c1c2ce443c..851a5707625c23 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1093,18 +1093,18 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_stackless.h \ $(srcdir)/Include/internal/pycore_slp_pystate.h \ $(srcdir)/Include/internal/pycore_slp_prickelpit.h \ - $(srcdir)/Include/internal/pycore_slp_switch_amd64_unix.h \ - $(srcdir)/Include/internal/pycore_slp_switch_arm32_gcc.h \ - $(srcdir)/Include/internal/pycore_slp_switch_arm_thumb_gcc.h \ - $(srcdir)/Include/internal/pycore_slp_switch_mips_unix.h \ - $(srcdir)/Include/internal/pycore_slp_switch_ppc_macosx.h \ - $(srcdir)/Include/internal/pycore_slp_switch_ppc_unix.h \ - $(srcdir)/Include/internal/pycore_slp_switch_ps3_SNTools.h \ - $(srcdir)/Include/internal/pycore_slp_switch_s390_unix.h \ - $(srcdir)/Include/internal/pycore_slp_switch_sparc_sun_gcc.h \ - $(srcdir)/Include/internal/pycore_slp_switch_x64_msvc.h \ - $(srcdir)/Include/internal/pycore_slp_switch_x86_msvc.h \ - $(srcdir)/Include/internal/pycore_slp_switch_x86_unix.h \ + $(srcdir)/Stackless/platf/switch_amd64_unix.h \ + $(srcdir)/Stackless/platf/switch_arm32_gcc.h \ + $(srcdir)/Stackless/platf/switch_arm_thumb_gcc.h \ + $(srcdir)/Stackless/platf/switch_mips_unix.h \ + $(srcdir)/Stackless/platf/switch_ppc_macosx.h \ + $(srcdir)/Stackless/platf/switch_ppc_unix.h \ + $(srcdir)/Stackless/platf/switch_ps3_SNTools.h \ + $(srcdir)/Stackless/platf/switch_s390_unix.h \ + $(srcdir)/Stackless/platf/switch_sparc_sun_gcc.h \ + $(srcdir)/Stackless/platf/switch_x64_msvc.h \ + $(srcdir)/Stackless/platf/switch_x86_msvc.h \ + $(srcdir)/Stackless/platf/switch_x86_unix.h \ \ pyconfig.h \ $(PARSER_HEADERS) \ diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 0fdf36d215dacb..1cab4c0cef4224 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -238,8 +238,8 @@ - - + + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index cc1816f4a629ed..880e47b1e2ab09 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -525,10 +525,10 @@ Include - + Include - + Include diff --git a/Stackless/platf/slp_transfer.c b/Stackless/platf/slp_transfer.c index 0f31800dc21ac8..522d602d4f4d34 100644 --- a/Stackless/platf/slp_transfer.c +++ b/Stackless/platf/slp_transfer.c @@ -40,31 +40,31 @@ #define SLP_EVAL /* enable code generation in the included header */ #if defined(MS_WIN32) && !defined(MS_WIN64) && defined(_M_IX86) -#include "pycore_slp_switch_x86_msvc.h" /* MS Visual Studio on X86 */ +#include "switch_x86_msvc.h" /* MS Visual Studio on X86 */ #elif defined(MS_WIN64) && defined(_M_X64) -#include "pycore_slp_switch_x64_msvc.h" /* MS Visual Studio on X64 */ +#include "switch_x64_msvc.h" /* MS Visual Studio on X64 */ #elif defined(__GNUC__) && defined(__i386__) -#include "pycore_slp_switch_x86_unix.h" /* gcc on X86 */ +#include "switch_x86_unix.h" /* gcc on X86 */ #elif defined(__GNUC__) && defined(__amd64__) -#include "pycore_slp_switch_amd64_unix.h" /* gcc on amd64 */ +#include "switch_amd64_unix.h" /* gcc on amd64 */ #elif defined(__GNUC__) && defined(__PPC__) && defined(__linux__) -#include "pycore_slp_switch_ppc_unix.h" /* gcc on PowerPC */ +#include "switch_ppc_unix.h" /* gcc on PowerPC */ #elif defined(__GNUC__) && defined(__ppc__) && defined(__APPLE__) -#include "pycore_slp_switch_ppc_macosx.h" /* Apple MacOS X on PowerPC */ +#include "switch_ppc_macosx.h" /* Apple MacOS X on PowerPC */ #elif defined(__GNUC__) && defined(sparc) && defined(sun) -#include "pycore_slp_switch_sparc_sun_gcc.h" /* SunOS sparc with gcc */ +#include "switch_sparc_sun_gcc.h" /* SunOS sparc with gcc */ #elif defined(__GNUC__) && defined(__s390__) && defined(__linux__) -#include "pycore_slp_switch_s390_unix.h" /* Linux/S390 */ +#include "switch_s390_unix.h" /* Linux/S390 */ #elif defined(__GNUC__) && defined(__s390x__) && defined(__linux__) -#include "pycore_slp_switch_s390_unix.h" /* Linux/S390 zSeries (identical) */ +#include "switch_s390_unix.h" /* Linux/S390 zSeries (identical) */ #elif defined(__GNUC__) && defined(__arm__) && defined(__thumb__) -#include "pycore_slp_switch_arm_thumb_gcc.h" /* gcc using arm thumb */ +#include "switch_arm_thumb_gcc.h" /* gcc using arm thumb */ #elif defined(__GNUC__) && defined(__arm32__) -#include "pycore_slp_switch_arm32_gcc.h" /* gcc using arm32 */ +#include "switch_arm32_gcc.h" /* gcc using arm32 */ #elif defined(__GNUC__) && defined(__mips__) && defined(__linux__) -#include "pycore_slp_switch_mips_unix.h" /* MIPS */ +#include "switch_mips_unix.h" /* MIPS */ #elif defined(SN_TARGET_PS3) -#include "pycore_slp_switch_ps3_SNTools.h" /* Sony PS3 */ +#include "switch_ps3_SNTools.h" /* Sony PS3 */ #endif #ifndef STACKLESS ********** diff --git a/Include/internal/pycore_slp_switch_amd64_unix.h b/Stackless/platf/switch_amd64_unix.h similarity index 100% rename from Include/internal/pycore_slp_switch_amd64_unix.h rename to Stackless/platf/switch_amd64_unix.h diff --git a/Include/internal/pycore_slp_switch_arm32_gcc.h b/Stackless/platf/switch_arm32_gcc.h similarity index 100% rename from Include/internal/pycore_slp_switch_arm32_gcc.h rename to Stackless/platf/switch_arm32_gcc.h diff --git a/Include/internal/pycore_slp_switch_arm_thumb_gcc.h b/Stackless/platf/switch_arm_thumb_gcc.h similarity index 100% rename from Include/internal/pycore_slp_switch_arm_thumb_gcc.h rename to Stackless/platf/switch_arm_thumb_gcc.h diff --git a/Include/internal/pycore_slp_switch_mips_unix.h b/Stackless/platf/switch_mips_unix.h similarity index 100% rename from Include/internal/pycore_slp_switch_mips_unix.h rename to Stackless/platf/switch_mips_unix.h diff --git a/Include/internal/pycore_slp_switch_ppc_macosx.h b/Stackless/platf/switch_ppc_macosx.h similarity index 100% rename from Include/internal/pycore_slp_switch_ppc_macosx.h rename to Stackless/platf/switch_ppc_macosx.h diff --git a/Include/internal/pycore_slp_switch_ppc_unix.h b/Stackless/platf/switch_ppc_unix.h similarity index 100% rename from Include/internal/pycore_slp_switch_ppc_unix.h rename to Stackless/platf/switch_ppc_unix.h diff --git a/Include/internal/pycore_slp_switch_ps3_SNTools.h b/Stackless/platf/switch_ps3_SNTools.h similarity index 100% rename from Include/internal/pycore_slp_switch_ps3_SNTools.h rename to Stackless/platf/switch_ps3_SNTools.h diff --git a/Include/internal/pycore_slp_switch_s390_unix.h b/Stackless/platf/switch_s390_unix.h similarity index 100% rename from Include/internal/pycore_slp_switch_s390_unix.h rename to Stackless/platf/switch_s390_unix.h diff --git a/Include/internal/pycore_slp_switch_sparc_sun_gcc.h b/Stackless/platf/switch_sparc_sun_gcc.h similarity index 100% rename from Include/internal/pycore_slp_switch_sparc_sun_gcc.h rename to Stackless/platf/switch_sparc_sun_gcc.h diff --git a/Include/internal/pycore_slp_switch_x64_msvc.h b/Stackless/platf/switch_x64_msvc.h similarity index 100% rename from Include/internal/pycore_slp_switch_x64_msvc.h rename to Stackless/platf/switch_x64_msvc.h diff --git a/Include/internal/pycore_slp_switch_x86_msvc.h b/Stackless/platf/switch_x86_msvc.h similarity index 100% rename from Include/internal/pycore_slp_switch_x86_msvc.h rename to Stackless/platf/switch_x86_msvc.h diff --git a/Include/internal/pycore_slp_switch_x86_unix.h b/Stackless/platf/switch_x86_unix.h similarity index 100% rename from Include/internal/pycore_slp_switch_x86_unix.h rename to Stackless/platf/switch_x86_unix.h