summaryrefslogtreecommitdiff
path: root/mach_dep.c
diff options
context:
space:
mode:
authorivmai <ivmai>2011-01-24 21:43:30 +0000
committerIvan Maidanski <ivmai@mail.ru>2011-07-26 21:06:56 +0400
commitbb4edc16faef98e2be3966eb1f6c9cec45c4ffeb (patch)
tree49666259893a4bc311454edc2c9d3ed8729bd457 /mach_dep.c
parentce3582069e602d1e6d1d1b17a2336484150fdef5 (diff)
downloadbdwgc-bb4edc16faef98e2be3966eb1f6c9cec45c4ffeb.tar.gz
2011-01-22 Ivan Maidanski <ivmai@mail.ru> (mostly Jean-Claude Beaudoin)
* darwin_stop_world.c (GC_FindTopOfStack): Prefix and suffix "volatile" keyword with double underscore. * mach_dep.c (GETCONTEXT_FPU_EXCMASK_BUG): Recognize new macro and include fenv.h if defined (unless NO_GETCONTEXT or HAVE_PUSH_REGS). * mach_dep.c (GC_with_callee_saves_pushed): Restore FPU exception mask corrupted by getcontext if GETCONTEXT_FPU_EXCMASK_BUG. * include/private/gcconfig.h (GETCONTEXT_FPU_EXCMASK_BUG): Define for Linux/amd64 (since its GLibc getcontext currently has the bug).
Diffstat (limited to 'mach_dep.c')
-rw-r--r--mach_dep.c40
1 files changed, 38 insertions, 2 deletions
diff --git a/mach_dep.c b/mach_dep.c
index 0829c8ca..0753d504 100644
--- a/mach_dep.c
+++ b/mach_dep.c
@@ -185,8 +185,11 @@ asm static void PushMacRegisters()
# include <signal.h>
# ifndef NO_GETCONTEXT
# include <ucontext.h>
+# ifdef GETCONTEXT_FPU_EXCMASK_BUG
+# include <fenv.h>
+# endif
# endif
-#endif
+#endif /* !HAVE_PUSH_REGS */
/* Ensure that either registers are pushed, or callee-save registers */
/* are somewhere on the stack, and then call fn(arg, ctxt). */
@@ -204,8 +207,41 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
/* ARM and MIPS Linux often doesn't support a real */
/* getcontext(). */
ucontext_t ctxt;
+# ifdef GETCONTEXT_FPU_EXCMASK_BUG
+ /* Workaround a bug (clearing the FPU exception mask) in */
+ /* getcontext on Linux/x86_64. */
+# ifdef X86_64
+ /* We inline fegetexcept and feenableexcept here just not to */
+ /* force the client application to use -lm linker option. */
+ unsigned short except_mask;
+ __asm__ __volatile__ ("fstcw %0" : "=m" (*&except_mask));
+ except_mask &= FE_ALL_EXCEPT;
+# else
+ int except_mask = fegetexcept();
+# endif
+# endif
if (getcontext(&ctxt) < 0)
- ABORT ("Getcontext failed: Use another register retrieval method?");
+ ABORT ("getcontext failed: Use another register retrieval method?");
+# ifdef GETCONTEXT_FPU_EXCMASK_BUG
+# ifdef X86_64
+ {
+ unsigned short new_exc;
+ unsigned int new_exc_sse;
+ /* Get the current control word of the x87 FPU. */
+ __asm__ __volatile__ ("fstcw %0" : "=m" (*&new_exc));
+ new_exc &= except_mask;
+ __asm__ __volatile__ ("fldcw %0" : : "m" (*&new_exc));
+ /* And now the same for the SSE MXCSR register. */
+ __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&new_exc_sse));
+ /* The SSE exception masks are shifted by 7 bits. */
+ new_exc_sse &= except_mask << 7;
+ __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&new_exc_sse));
+ }
+# else /* !X86_64 */
+ if (feenableexcept(except_mask) < 0)
+ ABORT("feenableexcept failed");
+# endif
+# endif
context = &ctxt;
# if defined(SPARC) || defined(IA64)
/* On a register window machine, we need to save register */