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 : #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 258 : GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
188 : ptr_t arg)
189 : {
190 : volatile int dummy;
191 258 : 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 258 : __asm__ __volatile__ ("fstcw %0" : "=m" (*&old_fcw));
208 : # else
209 : int except_mask = fegetexcept();
210 : # endif
211 : # endif
212 258 : if (getcontext(&ctxt) < 0)
213 0 : ABORT ("getcontext failed: Use another register retrieval method?");
214 : # ifdef GETCONTEXT_FPU_EXCMASK_BUG
215 : # ifdef X86_64
216 258 : __asm__ __volatile__ ("fldcw %0" : : "m" (*&old_fcw));
217 : {
218 : unsigned mxcsr;
219 : /* And now correct the exception mask in SSE MXCSR. */
220 258 : __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr));
221 516 : mxcsr = (mxcsr & ~(FE_ALL_EXCEPT << 7)) |
222 258 : ((old_fcw & FE_ALL_EXCEPT) << 7);
223 258 : __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 258 : 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 258 : 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 258 : GC_noop1((word)(&dummy));
278 258 : }
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 */
|