implemented Setup.hs to build boehm cpp libs and install them;
[hs-boehmgc.git] / gc-7.2 / mach_dep.c
1 /*
2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
4  *
5  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
6  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
7  *
8  * Permission is hereby granted to use or copy this program
9  * for any purpose,  provided the above notices are retained on all copies.
10  * Permission to modify the code and to distribute modified code is granted,
11  * provided the above notices are retained, and a notice that the code was
12  * modified is included with the above copyright notice.
13  */
14
15 #include "private/gc_priv.h"
16
17 #include <stdio.h>
18 #include <setjmp.h>
19
20 #if defined(OS2) || defined(CX_UX) || defined(__CC_ARM)
21 # define _setjmp(b) setjmp(b)
22 # define _longjmp(b,v) longjmp(b,v)
23 #endif
24
25 #ifdef AMIGA
26 # ifndef __GNUC__
27 #   include <dos.h>
28 # else
29 #   include <machine/reg.h>
30 # endif
31 #endif
32
33 #if defined(__MWERKS__) && !defined(POWERPC)
34
35 asm static void PushMacRegisters()
36 {
37     sub.w   #4,sp                   // reserve space for one parameter.
38     move.l  a2,(sp)
39     jsr         GC_push_one
40     move.l  a3,(sp)
41     jsr         GC_push_one
42     move.l  a4,(sp)
43     jsr         GC_push_one
44 #   if !__option(a6frames)
45         // <pcb> perhaps a6 should be pushed if stack frames are not being used.
46         move.l  a6,(sp)
47         jsr             GC_push_one
48 #   endif
49         // skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
50     move.l  d2,(sp)
51     jsr         GC_push_one
52     move.l  d3,(sp)
53     jsr         GC_push_one
54     move.l  d4,(sp)
55     jsr         GC_push_one
56     move.l  d5,(sp)
57     jsr         GC_push_one
58     move.l  d6,(sp)
59     jsr         GC_push_one
60     move.l  d7,(sp)
61     jsr         GC_push_one
62     add.w   #4,sp                   // fix stack.
63     rts
64 }
65
66 #endif /* __MWERKS__ */
67
68 # if defined(SPARC) || defined(IA64)
69     /* Value returned from register flushing routine; either sp (SPARC) */
70     /* or ar.bsp (IA64).                                                */
71     GC_INNER ptr_t GC_save_regs_ret_val = NULL;
72 # endif
73
74 /* Routine to mark from registers that are preserved by the C compiler. */
75 /* This must be ported to every new architecture.  It is not optional,  */
76 /* and should not be used on platforms that are either UNIX-like, or    */
77 /* require thread support.                                              */
78
79 #undef HAVE_PUSH_REGS
80
81 #if defined(USE_ASM_PUSH_REGS)
82 # define HAVE_PUSH_REGS
83 #else  /* No asm implementation */
84
85 # if defined(M68K) && defined(AMIGA)
86     /* This function is not static because it could also be             */
87     /* errorneously defined in .S file, so this error would be caught   */
88     /* by the linker.                                                   */
89     void GC_push_regs(void)
90     {
91          /*  AMIGA - could be replaced by generic code                  */
92          /* a0, a1, d0 and d1 are caller save */
93
94 #       ifdef __GNUC__
95           asm("subq.w &0x4,%sp");       /* allocate word on top of stack */
96
97           asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one");
98           asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one");
99           asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one");
100           asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one");
101           asm("mov.l %a6,(%sp)"); asm("jsr _GC_push_one");
102           /* Skip frame pointer and stack pointer */
103           asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one");
104           asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one");
105           asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one");
106           asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one");
107           asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one");
108           asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
109
110           asm("addq.w &0x4,%sp");       /* put stack back where it was  */
111 #       else /* !__GNUC__ */
112           GC_push_one(getreg(REG_A2));
113           GC_push_one(getreg(REG_A3));
114 #         ifndef __SASC
115             /* Can probably be changed to #if 0 -Kjetil M. (a4=globals) */
116             GC_push_one(getreg(REG_A4));
117 #         endif
118           GC_push_one(getreg(REG_A5));
119           GC_push_one(getreg(REG_A6));
120           /* Skip stack pointer */
121           GC_push_one(getreg(REG_D2));
122           GC_push_one(getreg(REG_D3));
123           GC_push_one(getreg(REG_D4));
124           GC_push_one(getreg(REG_D5));
125           GC_push_one(getreg(REG_D6));
126           GC_push_one(getreg(REG_D7));
127 #       endif /* !__GNUC__ */
128     }
129 #   define HAVE_PUSH_REGS
130
131 # elif defined(M68K) && defined(MACOS)
132
133 #   if defined(THINK_C)
134 #     define PushMacReg(reg) \
135               move.l  reg,(sp) \
136               jsr             GC_push_one
137       void GC_push_regs(void)
138       {
139           asm {
140               sub.w   #4,sp          ; reserve space for one parameter.
141               PushMacReg(a2);
142               PushMacReg(a3);
143               PushMacReg(a4);
144               ; skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
145               PushMacReg(d2);
146               PushMacReg(d3);
147               PushMacReg(d4);
148               PushMacReg(d5);
149               PushMacReg(d6);
150               PushMacReg(d7);
151               add.w   #4,sp          ; fix stack.
152           }
153       }
154 #     define HAVE_PUSH_REGS
155 #     undef PushMacReg
156 #   elif defined(__MWERKS__)
157       void GC_push_regs(void)
158       {
159           PushMacRegisters();
160       }
161 #     define HAVE_PUSH_REGS
162 #   endif /* __MWERKS__ */
163 # endif /* MACOS */
164
165 #endif /* !USE_ASM_PUSH_REGS */
166
167 #if defined(HAVE_PUSH_REGS) && defined(THREADS)
168 # error GC_push_regs cannot be used with threads
169  /* Would fail for GC_do_blocking.  There are probably other safety     */
170  /* issues.                                                             */
171 # undef HAVE_PUSH_REGS
172 #endif
173
174 #if !defined(HAVE_PUSH_REGS) && defined(UNIX_LIKE)
175 # include <signal.h>
176 # ifndef NO_GETCONTEXT
177 #   include <ucontext.h>
178 #   ifdef GETCONTEXT_FPU_EXCMASK_BUG
179 #     include <fenv.h>
180 #   endif
181 # endif
182 #endif /* !HAVE_PUSH_REGS */
183
184 /* Ensure that either registers are pushed, or callee-save registers    */
185 /* are somewhere on the stack, and then call fn(arg, ctxt).             */
186 /* ctxt is either a pointer to a ucontext_t we generated, or NULL.      */
187 GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
188                                           ptr_t arg)
189 {
190     volatile int dummy;
191     void * context = 0;
192
193 #   if defined(HAVE_PUSH_REGS)
194       GC_push_regs();
195 #   elif defined(UNIX_LIKE) && !defined(NO_GETCONTEXT)
196       /* Older versions of Darwin seem to lack getcontext(). */
197       /* ARM and MIPS Linux often doesn't support a real     */
198       /* getcontext().                                       */
199       ucontext_t ctxt;
200 #     ifdef GETCONTEXT_FPU_EXCMASK_BUG
201         /* Workaround a bug (clearing the FPU exception mask) in        */
202         /* getcontext on Linux/x86_64.                                  */
203 #       ifdef X86_64
204           /* We manipulate FPU control word here just not to force the  */
205           /* client application to use -lm linker option.               */
206           unsigned short old_fcw;
207           __asm__ __volatile__ ("fstcw %0" : "=m" (*&old_fcw));
208 #       else
209           int except_mask = fegetexcept();
210 #       endif
211 #     endif
212       if (getcontext(&ctxt) < 0)
213         ABORT ("getcontext failed: Use another register retrieval method?");
214 #     ifdef GETCONTEXT_FPU_EXCMASK_BUG
215 #       ifdef X86_64
216           __asm__ __volatile__ ("fldcw %0" : : "m" (*&old_fcw));
217           {
218             unsigned mxcsr;
219             /* And now correct the exception mask in SSE MXCSR. */
220             __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr));
221             mxcsr = (mxcsr & ~(FE_ALL_EXCEPT << 7)) |
222                         ((old_fcw & FE_ALL_EXCEPT) << 7);
223             __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr));
224           }
225 #       else /* !X86_64 */
226           if (feenableexcept(except_mask) < 0)
227             ABORT("feenableexcept failed");
228 #       endif
229 #     endif
230       context = &ctxt;
231 #     if defined(SPARC) || defined(IA64)
232         /* On a register window machine, we need to save register       */
233         /* contents on the stack for this to work.  This may already be */
234         /* subsumed by the getcontext() call.                           */
235         GC_save_regs_ret_val = GC_save_regs_in_stack();
236 #     endif /* register windows. */
237 #   elif defined(HAVE_BUILTIN_UNWIND_INIT) \
238          && !(defined(POWERPC) && defined(DARWIN)) \
239          && !(defined(I386) && defined(RTEMS))
240       /* This was suggested by Richard Henderson as the way to  */
241       /* force callee-save registers and register windows onto  */
242       /* the stack.                                             */
243       /* Mark Sibly points out that this doesn't seem to work   */
244       /* on MacOS 10.3.9/PowerPC.                               */
245       __builtin_unwind_init();
246 #   else /* !HAVE_BUILTIN_UNWIND_INIT && !UNIX_LIKE  */
247          /* && !HAVE_PUSH_REGS                       */
248         /* Generic code                          */
249         /* The idea is due to Parag Patel at HP. */
250         /* We're not sure whether he would like  */
251         /* to be he acknowledged for it or not.  */
252         jmp_buf regs;
253         register word * i = (word *) regs;
254         register ptr_t lim = (ptr_t)(regs) + (sizeof regs);
255
256         /* Setjmp doesn't always clear all of the buffer.               */
257         /* That tends to preserve garbage.  Clear it.                   */
258         for (; (char *)i < lim; i++) {
259             *i = 0;
260         }
261 #       if defined(MSWIN32) || defined(MSWINCE) || defined(UTS4) \
262            || defined(LINUX) || defined(EWS4800) || defined(RTEMS)
263           (void) setjmp(regs);
264 #       else
265           (void) _setjmp(regs);
266           /* We don't want to mess with signals. According to   */
267           /* SUSV3, setjmp() may or may not save signal mask.   */
268           /* _setjmp won't, but is less portable.               */
269 #       endif
270 #   endif /* !HAVE_PUSH_REGS ... */
271     /* FIXME: context here is sometimes just zero.  At the moment the   */
272     /* callees don't really need it.                                    */
273     fn(arg, context);
274     /* Strongly discourage the compiler from treating the above */
275     /* as a tail-call, since that would pop the register        */
276     /* contents before we get a chance to look at them.         */
277     GC_noop1((word)(&dummy));
278 }
279
280 #if defined(ASM_CLEAR_CODE)
281 # ifdef LINT
282     /*ARGSUSED*/
283     ptr_t GC_clear_stack_inner(ptr_t arg, word limit)
284     {
285       return(arg);
286     }
287     /* The real version is in a .S file */
288 # endif
289 #endif /* ASM_CLEAR_CODE */