boehm-gc: revert all CACAO-specific modifications; this is now an exact copy of the...
[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 /* Boehm, November 17, 1995 12:13 pm PST */
15 # include "private/gc_priv.h"
16 # include <stdio.h>
17 # include <setjmp.h>
18 # if defined(OS2) || defined(CX_UX)
19 #   define _setjmp(b) setjmp(b)
20 #   define _longjmp(b,v) longjmp(b,v)
21 # endif
22 # ifdef AMIGA
23 #   ifndef __GNUC__
24 #     include <dos.h>
25 #   else
26 #     include <machine/reg.h>
27 #   endif
28 # endif
29
30 #if defined(__MWERKS__) && !defined(POWERPC)
31
32 asm static void PushMacRegisters()
33 {
34     sub.w   #4,sp                   // reserve space for one parameter.
35     move.l  a2,(sp)
36     jsr         GC_push_one
37     move.l  a3,(sp)
38     jsr         GC_push_one
39     move.l  a4,(sp)
40     jsr         GC_push_one
41 #   if !__option(a6frames)
42         // <pcb> perhaps a6 should be pushed if stack frames are not being used.    
43         move.l  a6,(sp)
44         jsr             GC_push_one
45 #   endif
46         // skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
47     move.l  d2,(sp)
48     jsr         GC_push_one
49     move.l  d3,(sp)
50     jsr         GC_push_one
51     move.l  d4,(sp)
52     jsr         GC_push_one
53     move.l  d5,(sp)
54     jsr         GC_push_one
55     move.l  d6,(sp)
56     jsr         GC_push_one
57     move.l  d7,(sp)
58     jsr         GC_push_one
59     add.w   #4,sp                   // fix stack.
60     rts
61 }
62
63 #endif /* __MWERKS__ */
64
65 # if defined(SPARC) || defined(IA64)
66     /* Value returned from register flushing routine; either sp (SPARC) */
67     /* or ar.bsp (IA64)                                                 */
68     ptr_t GC_save_regs_ret_val;
69 # endif
70
71 /* Routine to mark from registers that are preserved by the C compiler. */
72 /* This must be ported to every new architecture.  It is not optional,  */
73 /* and should not be used on platforms that are either UNIX-like, or    */
74 /* require thread support.                                              */
75
76 #undef HAVE_PUSH_REGS
77
78 #if defined(USE_ASM_PUSH_REGS)
79 #  define HAVE_PUSH_REGS
80 #else  /* No asm implementation */
81 void GC_push_regs()
82 {
83 #       if defined(M68K) && defined(AMIGA)
84          /*  AMIGA - could be replaced by generic code                  */
85          /* a0, a1, d0 and d1 are caller save */
86
87 #        ifdef __GNUC__
88           asm("subq.w &0x4,%sp");       /* allocate word on top of stack */
89
90           asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one");
91           asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one");
92           asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one");
93           asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one");
94           asm("mov.l %a6,(%sp)"); asm("jsr _GC_push_one");
95           /* Skip frame pointer and stack pointer */
96           asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one");
97           asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one");
98           asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one");
99           asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one");
100           asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one");
101           asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
102
103           asm("addq.w &0x4,%sp");       /* put stack back where it was  */
104 #         define HAVE_PUSH_REGS
105 #        else /* !__GNUC__ */
106           GC_push_one(getreg(REG_A2));
107           GC_push_one(getreg(REG_A3));
108 #         ifndef __SASC
109               /* Can probably be changed to #if 0 -Kjetil M. (a4=globals)*/
110             GC_push_one(getreg(REG_A4));
111 #         endif
112           GC_push_one(getreg(REG_A5));
113           GC_push_one(getreg(REG_A6));
114           /* Skip stack pointer */
115           GC_push_one(getreg(REG_D2));
116           GC_push_one(getreg(REG_D3));
117           GC_push_one(getreg(REG_D4));
118           GC_push_one(getreg(REG_D5));
119           GC_push_one(getreg(REG_D6));
120           GC_push_one(getreg(REG_D7));
121 #         define HAVE_PUSH_REGS
122 #        endif /* !__GNUC__ */
123 #       endif /* AMIGA */
124
125 #       if defined(M68K) && defined(MACOS)
126 #       if defined(THINK_C)
127 #         define PushMacReg(reg) \
128               move.l  reg,(sp) \
129               jsr             GC_push_one
130           asm {
131               sub.w   #4,sp                   ; reserve space for one parameter.
132               PushMacReg(a2);
133               PushMacReg(a3);
134               PushMacReg(a4);
135               ; skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
136               PushMacReg(d2);
137               PushMacReg(d3);
138               PushMacReg(d4);
139               PushMacReg(d5);
140               PushMacReg(d6);
141               PushMacReg(d7);
142               add.w   #4,sp                   ; fix stack.
143           }
144 #         define HAVE_PUSH_REGS
145 #         undef PushMacReg
146 #       endif /* THINK_C */
147 #       if defined(__MWERKS__)
148           PushMacRegisters();
149 #         define HAVE_PUSH_REGS
150 #       endif   /* __MWERKS__ */
151 #   endif       /* MACOS */
152 }
153 #endif /* !USE_ASM_PUSH_REGS */
154
155 #if defined(HAVE_PUSH_REGS) && defined(THREADS)
156 # error GC_push_regs cannot be used with threads
157  /* Would fail for GC_do_blocking.  There are probably other safety     */
158  /* issues.                                                             */
159 # undef HAVE_PUSH_REGS
160 #endif
161
162 #if defined(UNIX_LIKE) && !defined(NO_GETCONTEXT) &&  \
163         (defined(DARWIN) || defined(HURD) || defined(ARM32) || defined(MIPS))
164 #  define NO_GETCONTEXT
165 #endif
166
167 #if defined(LINUX) && defined(SPARC) && !defined(NO_GETCONTEXT)
168 #  define NO_GETCONTEXT
169 #endif
170
171 #if !defined(HAVE_PUSH_REGS) && defined(UNIX_LIKE)
172 # include <signal.h>
173 # ifndef NO_GETCONTEXT
174 #   include <ucontext.h>
175 # endif
176 #endif
177
178 /* Ensure that either registers are pushed, or callee-save registers    */
179 /* are somewhere on the stack, and then call fn(arg, ctxt).             */
180 /* ctxt is either a pointer to a ucontext_t we generated, or NULL.      */
181 void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
182                                  ptr_t arg)
183 {
184     word dummy;
185     void * context = 0;
186
187 #   if defined(HAVE_PUSH_REGS)
188       GC_push_regs();
189 #   elif defined(UNIX_LIKE) && !defined(NO_GETCONTEXT)
190       /* Older versions of Darwin seem to lack getcontext(). */
191       /* ARM and MIPS Linux often doesn't support a real     */
192       /* getcontext().                                       */
193       ucontext_t ctxt;
194       if (getcontext(&ctxt) < 0)
195         ABORT ("Getcontext failed: Use another register retrieval method?");
196       context = &ctxt;
197 #     if defined(SPARC) || defined(IA64)
198         /* On a register window machine, we need to save register       */
199         /* contents on the stack for this to work.  This may already be */
200         /* subsumed by the getcontext() call.                           */
201         {
202           GC_save_regs_ret_val = GC_save_regs_in_stack();
203         }
204 #     endif /* register windows. */
205 #   elif defined(HAVE_BUILTIN_UNWIND_INIT) && \
206          !(defined(POWERPC) && defined(DARWIN))
207       /* This was suggested by Richard Henderson as the way to  */
208       /* force callee-save registers and register windows onto  */
209       /* the stack.                                             */
210       /* Mark Sibly points out that this doesn't seem to work   */
211       /* on MacOS 10.3.9/PowerPC.                               */
212       __builtin_unwind_init();
213 #   else /* !HAVE_BUILTIN_UNWIND_INIT && !UNIX_LIKE  */
214          /* && !HAVE_PUSH_REGS                       */
215         /* Generic code                          */
216         /* The idea is due to Parag Patel at HP. */
217         /* We're not sure whether he would like  */
218         /* to be he acknowledged for it or not.  */
219         jmp_buf regs;
220         register word * i = (word *) regs;
221         register ptr_t lim = (ptr_t)(regs) + (sizeof regs);
222   
223         /* Setjmp doesn't always clear all of the buffer.               */
224         /* That tends to preserve garbage.  Clear it.                   */
225         for (; (char *)i < lim; i++) {
226             *i = 0;
227         }
228 #       if defined(MSWIN32) || defined(MSWINCE) \
229                   || defined(UTS4) || defined(LINUX) || defined(EWS4800)
230           (void) setjmp(regs);
231 #       else
232           (void) _setjmp(regs);
233           /* We don't want to mess with signals. According to   */
234           /* SUSV3, setjmp() may or may not save signal mask.   */
235           /* _setjmp won't, but is less portable.               */
236 #       endif
237 #   endif /* !HAVE_PUSH_REGS ... */
238     /* FIXME: context here is sometimes just zero.  At the moment the callees   */
239     /* don't really need it.                                                    */
240     fn(arg, context);
241     /* Strongly discourage the compiler from treating the above */
242     /* as a tail-call, since that would pop the register        */
243     /* contents before we get a chance to look at them.         */
244     GC_noop1((word)(&dummy));
245 }
246
247 #if defined(ASM_CLEAR_CODE)
248 # ifdef LINT
249     /*ARGSUSED*/
250     ptr_t GC_clear_stack_inner(arg, limit)
251     ptr_t arg; word limit;
252     { return(arg); }
253     /* The real version is in a .S file */
254 # endif
255 #endif /* ASM_CLEAR_CODE */