Skip to content

Commit 7ae6176

Browse files
author
Anselm Kruis
committed
Stackless issue python#97: Fix stack switching for optimized builds
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)
1 parent 0884eb3 commit 7ae6176

11 files changed

+616
-473
lines changed

Stackless/changelog.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ What's New in Stackless 3.X.X?
99

1010
*Release date: 20XX-XX-XX*
1111

12+
- https://bitbucket.org/stackless-dev/stackless/issues/97
13+
Fix the stack switching for optimized builds for all Unix-like architectures
14+
except amd64, where it was already OK. This change removes the "static"
15+
declaration from the function slp_switch(). This forces the compiler
16+
to adhere to the ABI specification. On i386 and amd64 it is now save to
17+
configure stackless with --enable-stacklessfewerregisters, except if you
18+
compile for darwin.
19+
1220
- https://bitbucket.org/stackless-dev/stackless/issues/94
1321
Calls to __init__(self, ...) are now stackless, if
1422
soft-switching is enabled.

Stackless/platf/switch_amd64_unix.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,20 @@ int
104104
slp_switch(void)
105105
{
106106
register long *stackref, stsizediff;
107-
void * rbp; int mxcsr; short x87cw;
107+
int mxcsr; short x87cw;
108+
#if STACKLESS_FRHACK
109+
__asm__ volatile (
110+
"fstcw %0\n\t"
111+
"stmxcsr %1\n\t"
112+
: "=m" (x87cw), "=m" (mxcsr) : : REGS_CLOBBERED );
113+
#else
114+
void * rbp;
108115
__asm__ volatile (
109116
"fstcw %0\n\t"
110117
"stmxcsr %1\n\t"
111118
"movq %%rbp, %2\n\t"
112119
: "=m" (x87cw), "=m" (mxcsr), "=m" (rbp) : : REGS_CLOBBERED );
120+
#endif
113121
__asm__ ("movq %%rsp, %0" : "=g" (stackref));
114122
{
115123
SLP_SAVE_STATE(stackref, stsizediff);
@@ -120,11 +128,18 @@ slp_switch(void)
120128
: "r" (stsizediff)
121129
);
122130
SLP_RESTORE_STATE();
131+
#if STACKLESS_FRHACK
132+
__asm__ volatile (
133+
"ldmxcsr %1\n\t"
134+
"fldcw %0\n\t"
135+
: : "m" (x87cw), "m" (mxcsr));
136+
#else
123137
__asm__ volatile (
124138
"movq %2, %%rbp\n\t"
125139
"ldmxcsr %1\n\t"
126140
"fldcw %0\n\t"
127141
: : "m" (x87cw), "m" (mxcsr), "m" (rbp));
142+
#endif
128143
return 0;
129144
}
130145
}

Stackless/platf/switch_arm32_gcc.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,15 @@
2727
#define STACK_MAGIC 0
2828
#define REGS_TO_SAVE /*"r1", "r2", "r3", "r4",*/ "r5", "r6", "fp", "ip", "lr"
2929

30-
static int
30+
/*
31+
* You may want to make the function static enable optimizations.
32+
* However, the ABI SPEC does not apply to static functions. Therefore
33+
* I make slp_switch a regular global function.
34+
*/
35+
#if 0
36+
static
37+
#endif
38+
int
3139
slp_switch(void)
3240
{
3341
register int *stackref, stsizediff;
@@ -44,7 +52,6 @@ slp_switch(void)
4452
SLP_RESTORE_STATE();
4553
return 0;
4654
}
47-
__asm__ volatile ("" : : : REGS_TO_SAVE);
4855
}
4956

5057
#endif

Stackless/platf/switch_mips_unix.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,16 @@
1919
#define REGS_TO_SAVE "$16", "$17", "$18", "$19", "$20", "$21", "$22", \
2020
"$23", "$30"
2121
#endif
22-
static int
22+
__asm__ volatile ("" : : : REGS_TO_SAVE);
23+
/*
24+
* You may want to make the function static enable optimizations.
25+
* However, the ABI SPEC does not apply to static functions. Therefore
26+
* I make slp_switch a regular global function.
27+
*/
28+
#if 0
29+
static
30+
#endif
31+
int
2332
slp_switch(void)
2433
{
2534
register int *stackref, stsizediff;
@@ -38,7 +47,6 @@ slp_switch(void)
3847
);
3948
SLP_RESTORE_STATE();
4049
}
41-
/* __asm__ __volatile__ ("" : : : REGS_TO_SAVE); */
4250
return 0;
4351
}
4452

Stackless/platf/switch_ppc_macosx.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,15 @@
4242
"cr2", "cr3", "cr4"
4343
#endif
4444

45-
static int
45+
/*
46+
* You may want to make the function static enable optimizations.
47+
* However, the ABI SPEC does not apply to static functions. Therefore
48+
* I make slp_switch a regular global function.
49+
*/
50+
#if 0
51+
static
52+
#endif
53+
int
4654
slp_switch(void)
4755
{
4856
static int x = 0;

Stackless/platf/switch_ppc_unix.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@
3737
#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \
3838
"r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r31", \
3939
"cr2", "cr3", "cr4"
40-
static int
40+
/*
41+
* You may want to make the function static enable optimizations.
42+
* However, the ABI SPEC does not apply to static functions. Therefore
43+
* I make slp_switch a regular global function.
44+
*/
45+
#if 0
46+
static
47+
#endif
48+
int
4149
slp_switch(void)
4250
{
4351
register int *stackref, stsizediff;

Stackless/platf/switch_s390_unix.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,15 @@
2121
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
2222
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15"
2323

24-
static int
24+
/*
25+
* You may want to make the function static enable optimizations.
26+
* However, the ABI SPEC does not apply to static functions. Therefore
27+
* I make slp_switch a regular global function.
28+
*/
29+
#if 0
30+
static
31+
#endif
32+
int
2533
slp_switch(void)
2634
{
2735
register int *stackref, stsizediff;
@@ -37,7 +45,6 @@ slp_switch(void)
3745
SLP_RESTORE_STATE();
3846
return 0;
3947
}
40-
__asm__ volatile ("" : : : REGS_TO_SAVE);
4148
}
4249

4350
#endif

Stackless/platf/switch_sparc_sun_gcc.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,15 @@
2323

2424
#define STACK_MAGIC 0
2525

26-
static int
26+
/*
27+
* You may want to make the function static enable optimizations.
28+
* However, the ABI SPEC does not apply to static functions. Therefore
29+
* I make slp_switch a regular global function.
30+
*/
31+
#if 0
32+
static
33+
#endif
34+
int
2735
slp_switch(void)
2836
{
2937
register int *stackref, stsizediff;

Stackless/platf/switch_x86_unix.h

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
* this is the internal transfer function.
33
*
44
* HISTORY
5+
* 06-Nov-16 Anselm Kruis <[email protected]>
6+
* Reworked based on the i386 ABI spec.
57
* 24-Nov-02 Christian Tismer <[email protected]>
68
* needed to add another magic constant to insure
79
* that f in slp_eval_frame(PyFrameObject *f)
@@ -23,36 +25,84 @@
2325

2426
#ifdef SLP_EVAL
2527

26-
/* #define STACK_MAGIC 3 */
27-
/* the above works fine with gcc 2.96, but 2.95.3 wants this */
2828
#define STACK_MAGIC 0
2929

30-
static int
30+
/*
31+
* In order to switch the stack, we use the fact, that the compiler
32+
* already knows how to preserve registers accross function calls.
33+
*
34+
* The relevant i386 ABI specifigation pecisely defines which registers
35+
* must be preserved and which registers may be modified.
36+
* We use a gcc inline assembly feature to pretend that the inline
37+
* assembly block modifies the registers to be preserved. As a result,
38+
* the compiler emits code to preserve those registers.
39+
*
40+
* The "System V Application Binary Interface Intel386 Architecture Processor Supplment, Fourth Edition"
41+
* Section 3 chapter "Function Calling Sequence" states:
42+
* All registers on the Intel386 are global and thus visible to both a calling and a
43+
* called function. Registers %ebp, %ebx, %edi, %esi, and %esp "belong" to the cal-
44+
* ling function. In other words, a called function must preserve these registers’
45+
* values for its caller. Remaining registers ‘‘belong’’ to the called function.
46+
*
47+
* The compiler always preserves the %esp register accros a function call.
48+
*
49+
* Depending on the usage of a frame pointer, which is optional
50+
* for the i386 ABI, the compiler already preserves the %ebp
51+
* register. Unfortunately, we must not add "ebp" to the clobber list, if
52+
* ebp is used as a frame pointer (won't compile). Therefore we save
53+
* ebp manually.
54+
*
55+
* For the other registers we tell the compiler,
56+
* that we are going to clobber the registers. The compiler will then save the registers
57+
* for us. (However the compiler gives no guarantee, when it will restore
58+
* the registers.) And the compiler only preserves those registers, that must
59+
* be preserved according to the calling convention. It does not preserve any other
60+
* register, that may be modified during a function call. Therefore specifying additional
61+
* registers has no effect at all. Take a look at the generated assembly code!
62+
*/
63+
64+
/* Registers marked as clobbered, minimum set according to the ABI spec. */
65+
#define REGS_CLOBBERED "ebx", "edi", "esi"
66+
67+
/*
68+
* You may want to make the function static enable optimizations.
69+
* However, the ABI SPEC does not apply to static functions. Therefore
70+
* I make slp_switch a regular global function.
71+
*/
72+
#if 0
73+
static
74+
#endif
75+
int
3176
slp_switch(void)
3277
{
3378
register int *stackref, stsizediff;
3479
#if STACKLESS_FRHACK
35-
__asm__ volatile ("" : : : "esi", "edi");
80+
__asm__ volatile (
81+
""
82+
: : : REGS_CLOBBERED );
3683
#else
37-
__asm__ volatile ("" : : : "ebx", "esi", "edi");
84+
void * ebp;
85+
__asm__ volatile (
86+
"movl %%ebp, %0\n\t"
87+
: "=m" (ebp) : : REGS_CLOBBERED );
3888
#endif
3989
__asm__ ("movl %%esp, %0" : "=g" (stackref));
4090
{
4191
SLP_SAVE_STATE(stackref, stsizediff);
4292
__asm__ volatile (
43-
"addl %0, %%esp\n"
44-
"addl %0, %%ebp\n"
93+
"addl %0, %%esp\n\t"
94+
"addl %0, %%ebp\n\t"
4595
:
4696
: "r" (stsizediff)
4797
);
4898
SLP_RESTORE_STATE();
99+
#if ! STACKLESS_FRHACK
100+
__asm__ volatile (
101+
"movl %0, %%ebp\n\t"
102+
: : "m" (ebp) );
103+
#endif
49104
return 0;
50105
}
51-
#if STACKLESS_FRHACK
52-
__asm__ volatile ("" : : : "esi", "edi");
53-
#else
54-
__asm__ volatile ("" : : : "ebx", "esi", "edi");
55-
#endif
56106
}
57107

58108

0 commit comments

Comments
 (0)