Upgrade Boehm GC to 7.2alpha4.
[cacao.git] / src / mm / boehm-gc / 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)
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(UNIX_LIKE) && !defined(NO_GETCONTEXT) && \
175         (defined(DARWIN) || defined(HURD) || defined(OPENBSD) \
176          || defined(ARM32) || defined(MIPS))
177 # define NO_GETCONTEXT
178 #endif
179
180 #if defined(LINUX) && defined(SPARC) && !defined(NO_GETCONTEXT)
181 # define NO_GETCONTEXT
182 #endif
183
184 #if !defined(HAVE_PUSH_REGS) && defined(UNIX_LIKE)
185 # include <signal.h>
186 # ifndef NO_GETCONTEXT
187 #   include <ucontext.h>
188 # endif
189 #endif
190
191 /* Ensure that either registers are pushed, or callee-save registers    */
192 /* are somewhere on the stack, and then call fn(arg, ctxt).             */
193 /* ctxt is either a pointer to a ucontext_t we generated, or NULL.      */
194 GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
195                                           ptr_t arg)
196 {
197     word dummy;
198     void * context = 0;
199
200 #   if defined(HAVE_PUSH_REGS)
201       GC_push_regs();
202 #   elif defined(UNIX_LIKE) && !defined(NO_GETCONTEXT)
203       /* Older versions of Darwin seem to lack getcontext(). */
204       /* ARM and MIPS Linux often doesn't support a real     */
205       /* getcontext().                                       */
206       ucontext_t ctxt;
207       if (getcontext(&ctxt) < 0)
208         ABORT ("Getcontext failed: Use another register retrieval method?");
209       context = &ctxt;
210 #     if defined(SPARC) || defined(IA64)
211         /* On a register window machine, we need to save register       */
212         /* contents on the stack for this to work.  This may already be */
213         /* subsumed by the getcontext() call.                           */
214         GC_save_regs_ret_val = GC_save_regs_in_stack();
215 #     endif /* register windows. */
216 #   elif defined(HAVE_BUILTIN_UNWIND_INIT) && \
217          !(defined(POWERPC) && defined(DARWIN))
218       /* This was suggested by Richard Henderson as the way to  */
219       /* force callee-save registers and register windows onto  */
220       /* the stack.                                             */
221       /* Mark Sibly points out that this doesn't seem to work   */
222       /* on MacOS 10.3.9/PowerPC.                               */
223       __builtin_unwind_init();
224 #   else /* !HAVE_BUILTIN_UNWIND_INIT && !UNIX_LIKE  */
225          /* && !HAVE_PUSH_REGS                       */
226         /* Generic code                          */
227         /* The idea is due to Parag Patel at HP. */
228         /* We're not sure whether he would like  */
229         /* to be he acknowledged for it or not.  */
230         jmp_buf regs;
231         register word * i = (word *) regs;
232         register ptr_t lim = (ptr_t)(regs) + (sizeof regs);
233
234         /* Setjmp doesn't always clear all of the buffer.               */
235         /* That tends to preserve garbage.  Clear it.                   */
236         for (; (char *)i < lim; i++) {
237             *i = 0;
238         }
239 #       if defined(MSWIN32) || defined(MSWINCE) \
240                   || defined(UTS4) || defined(LINUX) || defined(EWS4800)
241           (void) setjmp(regs);
242 #       else
243           (void) _setjmp(regs);
244           /* We don't want to mess with signals. According to   */
245           /* SUSV3, setjmp() may or may not save signal mask.   */
246           /* _setjmp won't, but is less portable.               */
247 #       endif
248 #   endif /* !HAVE_PUSH_REGS ... */
249     /* FIXME: context here is sometimes just zero.  At the moment the   */
250     /* callees don't really need it.                                    */
251     fn(arg, context);
252     /* Strongly discourage the compiler from treating the above */
253     /* as a tail-call, since that would pop the register        */
254     /* contents before we get a chance to look at them.         */
255     GC_noop1((word)(&dummy));
256 }
257
258 #if defined(ASM_CLEAR_CODE)
259 # ifdef LINT
260     /*ARGSUSED*/
261     ptr_t GC_clear_stack_inner(ptr_t arg, word limit)
262     {
263       return(arg);
264     }
265     /* The real version is in a .S file */
266 # endif
267 #endif /* ASM_CLEAR_CODE */