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