Skip to content

Commit

Permalink
Stackless issue python#97: Fix stack switching for optimized builds
Browse files Browse the repository at this point in the history
This change removes the "static" declaration from the function slp_switch().
This forces the compiler to adhere to the ABI specification.

On i386 and amd64 it is now save to configure stackless with
--enable-stacklessfewerregisters, except if you compile for darwin. The flag
disables explicit saving of %ebp/%rbp.

On Unix-like systems the source file slp_transfer.c now gets compiled
with the additional flag -fno-inline-functions instead of -O2.

https://bitbucket.org/stackless-dev/stackless/issues/98
(grafted from 4f7698499ad53e5fad61fb415fbfe2c036672a9c)
  • Loading branch information
Anselm Kruis committed Nov 7, 2016
1 parent 0884eb3 commit 7ae6176
Show file tree
Hide file tree
Showing 11 changed files with 616 additions and 473 deletions.
8 changes: 8 additions & 0 deletions Stackless/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ What's New in Stackless 3.X.X?

*Release date: 20XX-XX-XX*

- https://bitbucket.org/stackless-dev/stackless/issues/97
Fix the stack switching for optimized builds for all Unix-like architectures
except amd64, where it was already OK. This change removes the "static"
declaration from the function slp_switch(). This forces the compiler
to adhere to the ABI specification. On i386 and amd64 it is now save to
configure stackless with --enable-stacklessfewerregisters, except if you
compile for darwin.

- https://bitbucket.org/stackless-dev/stackless/issues/94
Calls to __init__(self, ...) are now stackless, if
soft-switching is enabled.
Expand Down
17 changes: 16 additions & 1 deletion Stackless/platf/switch_amd64_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,20 @@ int
slp_switch(void)
{
register long *stackref, stsizediff;
void * rbp; int mxcsr; short x87cw;
int mxcsr; short x87cw;
#if STACKLESS_FRHACK
__asm__ volatile (
"fstcw %0\n\t"
"stmxcsr %1\n\t"
: "=m" (x87cw), "=m" (mxcsr) : : REGS_CLOBBERED );
#else
void * rbp;
__asm__ volatile (
"fstcw %0\n\t"
"stmxcsr %1\n\t"
"movq %%rbp, %2\n\t"
: "=m" (x87cw), "=m" (mxcsr), "=m" (rbp) : : REGS_CLOBBERED );
#endif
__asm__ ("movq %%rsp, %0" : "=g" (stackref));
{
SLP_SAVE_STATE(stackref, stsizediff);
Expand All @@ -120,11 +128,18 @@ slp_switch(void)
: "r" (stsizediff)
);
SLP_RESTORE_STATE();
#if STACKLESS_FRHACK
__asm__ volatile (
"ldmxcsr %1\n\t"
"fldcw %0\n\t"
: : "m" (x87cw), "m" (mxcsr));
#else
__asm__ volatile (
"movq %2, %%rbp\n\t"
"ldmxcsr %1\n\t"
"fldcw %0\n\t"
: : "m" (x87cw), "m" (mxcsr), "m" (rbp));
#endif
return 0;
}
}
Expand Down
11 changes: 9 additions & 2 deletions Stackless/platf/switch_arm32_gcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,15 @@
#define STACK_MAGIC 0
#define REGS_TO_SAVE /*"r1", "r2", "r3", "r4",*/ "r5", "r6", "fp", "ip", "lr"

static int
/*
* You may want to make the function static enable optimizations.
* However, the ABI SPEC does not apply to static functions. Therefore
* I make slp_switch a regular global function.
*/
#if 0
static
#endif
int
slp_switch(void)
{
register int *stackref, stsizediff;
Expand All @@ -44,7 +52,6 @@ slp_switch(void)
SLP_RESTORE_STATE();
return 0;
}
__asm__ volatile ("" : : : REGS_TO_SAVE);
}

#endif
12 changes: 10 additions & 2 deletions Stackless/platf/switch_mips_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,16 @@
#define REGS_TO_SAVE "$16", "$17", "$18", "$19", "$20", "$21", "$22", \
"$23", "$30"
#endif
static int
__asm__ volatile ("" : : : REGS_TO_SAVE);
/*
* You may want to make the function static enable optimizations.
* However, the ABI SPEC does not apply to static functions. Therefore
* I make slp_switch a regular global function.
*/
#if 0
static
#endif
int
slp_switch(void)
{
register int *stackref, stsizediff;
Expand All @@ -38,7 +47,6 @@ slp_switch(void)
);
SLP_RESTORE_STATE();
}
/* __asm__ __volatile__ ("" : : : REGS_TO_SAVE); */
return 0;
}

Expand Down
10 changes: 9 additions & 1 deletion Stackless/platf/switch_ppc_macosx.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,15 @@
"cr2", "cr3", "cr4"
#endif

static int
/*
* You may want to make the function static enable optimizations.
* However, the ABI SPEC does not apply to static functions. Therefore
* I make slp_switch a regular global function.
*/
#if 0
static
#endif
int
slp_switch(void)
{
static int x = 0;
Expand Down
10 changes: 9 additions & 1 deletion Stackless/platf/switch_ppc_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,15 @@
#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \
"r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r31", \
"cr2", "cr3", "cr4"
static int
/*
* You may want to make the function static enable optimizations.
* However, the ABI SPEC does not apply to static functions. Therefore
* I make slp_switch a regular global function.
*/
#if 0
static
#endif
int
slp_switch(void)
{
register int *stackref, stsizediff;
Expand Down
11 changes: 9 additions & 2 deletions Stackless/platf/switch_s390_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,15 @@
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15"

static int
/*
* You may want to make the function static enable optimizations.
* However, the ABI SPEC does not apply to static functions. Therefore
* I make slp_switch a regular global function.
*/
#if 0
static
#endif
int
slp_switch(void)
{
register int *stackref, stsizediff;
Expand All @@ -37,7 +45,6 @@ slp_switch(void)
SLP_RESTORE_STATE();
return 0;
}
__asm__ volatile ("" : : : REGS_TO_SAVE);
}

#endif
Expand Down
10 changes: 9 additions & 1 deletion Stackless/platf/switch_sparc_sun_gcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,15 @@

#define STACK_MAGIC 0

static int
/*
* You may want to make the function static enable optimizations.
* However, the ABI SPEC does not apply to static functions. Therefore
* I make slp_switch a regular global function.
*/
#if 0
static
#endif
int
slp_switch(void)
{
register int *stackref, stsizediff;
Expand Down
74 changes: 62 additions & 12 deletions Stackless/platf/switch_x86_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
* this is the internal transfer function.
*
* HISTORY
* 06-Nov-16 Anselm Kruis <[email protected]>
* Reworked based on the i386 ABI spec.
* 24-Nov-02 Christian Tismer <[email protected]>
* needed to add another magic constant to insure
* that f in slp_eval_frame(PyFrameObject *f)
Expand All @@ -23,36 +25,84 @@

#ifdef SLP_EVAL

/* #define STACK_MAGIC 3 */
/* the above works fine with gcc 2.96, but 2.95.3 wants this */
#define STACK_MAGIC 0

static int
/*
* In order to switch the stack, we use the fact, that the compiler
* already knows how to preserve registers accross function calls.
*
* The relevant i386 ABI specifigation pecisely defines which registers
* must be preserved and which registers may be modified.
* We use a gcc inline assembly feature to pretend that the inline
* assembly block modifies the registers to be preserved. As a result,
* the compiler emits code to preserve those registers.
*
* The "System V Application Binary Interface Intel386 Architecture Processor Supplment, Fourth Edition"
* Section 3 chapter "Function Calling Sequence" states:
* All registers on the Intel386 are global and thus visible to both a calling and a
* called function. Registers %ebp, %ebx, %edi, %esi, and %esp "belong" to the cal-
* ling function. In other words, a called function must preserve these registers’
* values for its caller. Remaining registers ‘‘belong’’ to the called function.
*
* The compiler always preserves the %esp register accros a function call.
*
* Depending on the usage of a frame pointer, which is optional
* for the i386 ABI, the compiler already preserves the %ebp
* register. Unfortunately, we must not add "ebp" to the clobber list, if
* ebp is used as a frame pointer (won't compile). Therefore we save
* ebp manually.
*
* For the other registers we tell the compiler,
* that we are going to clobber the registers. The compiler will then save the registers
* for us. (However the compiler gives no guarantee, when it will restore
* the registers.) And the compiler only preserves those registers, that must
* be preserved according to the calling convention. It does not preserve any other
* register, that may be modified during a function call. Therefore specifying additional
* registers has no effect at all. Take a look at the generated assembly code!
*/

/* Registers marked as clobbered, minimum set according to the ABI spec. */
#define REGS_CLOBBERED "ebx", "edi", "esi"

/*
* You may want to make the function static enable optimizations.
* However, the ABI SPEC does not apply to static functions. Therefore
* I make slp_switch a regular global function.
*/
#if 0
static
#endif
int
slp_switch(void)
{
register int *stackref, stsizediff;
#if STACKLESS_FRHACK
__asm__ volatile ("" : : : "esi", "edi");
__asm__ volatile (
""
: : : REGS_CLOBBERED );
#else
__asm__ volatile ("" : : : "ebx", "esi", "edi");
void * ebp;
__asm__ volatile (
"movl %%ebp, %0\n\t"
: "=m" (ebp) : : REGS_CLOBBERED );
#endif
__asm__ ("movl %%esp, %0" : "=g" (stackref));
{
SLP_SAVE_STATE(stackref, stsizediff);
__asm__ volatile (
"addl %0, %%esp\n"
"addl %0, %%ebp\n"
"addl %0, %%esp\n\t"
"addl %0, %%ebp\n\t"
:
: "r" (stsizediff)
);
SLP_RESTORE_STATE();
#if ! STACKLESS_FRHACK
__asm__ volatile (
"movl %0, %%ebp\n\t"
: : "m" (ebp) );
#endif
return 0;
}
#if STACKLESS_FRHACK
__asm__ volatile ("" : : : "esi", "edi");
#else
__asm__ volatile ("" : : : "ebx", "esi", "edi");
#endif
}


Expand Down
Loading

0 comments on commit 7ae6176

Please sign in to comment.