Line data Source code
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 :
19 : #ifdef AMIGA
20 : # ifndef __GNUC__
21 : # include <dos.h>
22 : # else
23 : # include <machine/reg.h>
24 : # endif
25 : #endif
26 :
27 : #if defined(MACOS) && defined(__MWERKS__)
28 :
29 : #if defined(POWERPC)
30 :
31 : # define NONVOLATILE_GPR_COUNT 19
32 : struct ppc_registers {
33 : unsigned long gprs[NONVOLATILE_GPR_COUNT]; /* R13-R31 */
34 : };
35 : typedef struct ppc_registers ppc_registers;
36 :
37 : asm static void getRegisters(register ppc_registers* regs)
38 : {
39 : stmw r13,regs->gprs /* save R13-R31 */
40 : blr
41 : }
42 :
43 : static void PushMacRegisters(void)
44 : {
45 : ppc_registers regs;
46 : int i;
47 : getRegisters(®s);
48 : for (i = 0; i < NONVOLATILE_GPR_COUNT; i++)
49 : GC_push_one(regs.gprs[i]);
50 : }
51 :
52 : #else /* M68K */
53 :
54 : asm static void PushMacRegisters(void)
55 : {
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
83 : }
84 :
85 : #endif /* M68K */
86 :
87 : #endif /* MACOS && __MWERKS__ */
88 :
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
94 :
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. */
99 :
100 : #undef HAVE_PUSH_REGS
101 :
102 : #if defined(USE_ASM_PUSH_REGS)
103 : # define HAVE_PUSH_REGS
104 : #else /* No asm implementation */
105 :
106 : # if defined(M68K) && defined(AMIGA)
107 : /* This function is not static because it could also be */
108 : /* erroneously defined in .S file, so this error would be caught */
109 : /* by the linker. */
110 : void GC_push_regs(void)
111 : {
112 : /* AMIGA - could be replaced by generic code */
113 : /* a0, a1, d0 and d1 are caller save */
114 :
115 : # ifdef __GNUC__
116 : asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
117 :
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");
130 :
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__ */
149 : }
150 : # define HAVE_PUSH_REGS
151 :
152 : # elif defined(MACOS)
153 :
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)
159 : {
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.
173 : }
174 : }
175 : # define HAVE_PUSH_REGS
176 : # undef PushMacReg
177 : # elif defined(__MWERKS__)
178 : void GC_push_regs(void)
179 : {
180 : PushMacRegisters();
181 : }
182 : # define HAVE_PUSH_REGS
183 : # endif /* __MWERKS__ */
184 : # endif /* MACOS */
185 :
186 : #endif /* !USE_ASM_PUSH_REGS */
187 :
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
194 :
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 */
209 :
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 244 : GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
214 : ptr_t arg)
215 : {
216 : volatile int dummy;
217 244 : void * context = 0;
218 :
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 244 : __asm__ __volatile__ ("fstcw %0" : "=m" (*&old_fcw));
234 : # else
235 : int except_mask = fegetexcept();
236 : # endif
237 : # endif
238 244 : if (getcontext(&ctxt) < 0)
239 0 : ABORT ("getcontext failed: Use another register retrieval method?");
240 : # ifdef GETCONTEXT_FPU_EXCMASK_BUG
241 : # ifdef X86_64
242 244 : __asm__ __volatile__ ("fldcw %0" : : "m" (*&old_fcw));
243 : {
244 : unsigned mxcsr;
245 : /* And now correct the exception mask in SSE MXCSR. */
246 244 : __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr));
247 488 : mxcsr = (mxcsr & ~(FE_ALL_EXCEPT << 7)) |
248 244 : ((old_fcw & FE_ALL_EXCEPT) << 7);
249 244 : __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr));
250 : }
251 : # else /* !X86_64 */
252 : if (feenableexcept(except_mask) < 0)
253 : ABORT("feenableexcept failed");
254 : # endif
255 : # endif
256 244 : 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);
277 :
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;
282 : }
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 244 : 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 244 : GC_noop1((word)(&dummy));
301 244 : }
302 :
303 : #if defined(ASM_CLEAR_CODE)
304 : # ifdef LINT
305 : ptr_t GC_clear_stack_inner(ptr_t arg, word limit)
306 : {
307 : return limit ? arg : 0; /* use both arguments */
308 : }
309 : /* The real version is in a .S file */
310 : # endif
311 : #endif /* ASM_CLEAR_CODE */
|