b6e8ab99ec9f81f588a170d058d3f07f80921284
[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
16 #include "config.h"
17
18 # include "private/gc_priv.h"
19 # include <stdio.h>
20 # include <setjmp.h>
21 # if defined(OS2) || defined(CX_UX)
22 #   define _setjmp(b) setjmp(b)
23 #   define _longjmp(b,v) longjmp(b,v)
24 # endif
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     ptr_t GC_save_regs_ret_val;
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 noe 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 void GC_push_regs()
85 {
86 #       if defined(M68K) && defined(AMIGA)
87          /*  AMIGA - could be replaced by generic code                  */
88          /* a0, a1, d0 and d1 are caller save */
89
90 #        ifdef __GNUC__
91           asm("subq.w &0x4,%sp");       /* allocate word on top of stack */
92
93           asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one");
94           asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one");
95           asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one");
96           asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one");
97           asm("mov.l %a6,(%sp)"); asm("jsr _GC_push_one");
98           /* Skip frame pointer and stack pointer */
99           asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one");
100           asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one");
101           asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one");
102           asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one");
103           asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one");
104           asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
105
106           asm("addq.w &0x4,%sp");       /* put stack back where it was  */
107 #         define HAVE_PUSH_REGS
108 #        else /* !__GNUC__ */
109           GC_push_one(getreg(REG_A2));
110           GC_push_one(getreg(REG_A3));
111 #         ifndef __SASC
112               /* Can probably be changed to #if 0 -Kjetil M. (a4=globals)*/
113             GC_push_one(getreg(REG_A4));
114 #         endif
115           GC_push_one(getreg(REG_A5));
116           GC_push_one(getreg(REG_A6));
117           /* Skip stack pointer */
118           GC_push_one(getreg(REG_D2));
119           GC_push_one(getreg(REG_D3));
120           GC_push_one(getreg(REG_D4));
121           GC_push_one(getreg(REG_D5));
122           GC_push_one(getreg(REG_D6));
123           GC_push_one(getreg(REG_D7));
124 #         define HAVE_PUSH_REGS
125 #        endif /* !__GNUC__ */
126 #       endif /* AMIGA */
127
128 #       if defined(M68K) && defined(MACOS)
129 #       if defined(THINK_C)
130 #         define PushMacReg(reg) \
131               move.l  reg,(sp) \
132               jsr             GC_push_one
133           asm {
134               sub.w   #4,sp                   ; reserve space for one parameter.
135               PushMacReg(a2);
136               PushMacReg(a3);
137               PushMacReg(a4);
138               ; skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
139               PushMacReg(d2);
140               PushMacReg(d3);
141               PushMacReg(d4);
142               PushMacReg(d5);
143               PushMacReg(d6);
144               PushMacReg(d7);
145               add.w   #4,sp                   ; fix stack.
146           }
147 #         define HAVE_PUSH_REGS
148 #         undef PushMacReg
149 #       endif /* THINK_C */
150 #       if defined(__MWERKS__)
151           PushMacRegisters();
152 #         define HAVE_PUSH_REGS
153 #       endif   /* __MWERKS__ */
154 #   endif       /* MACOS */
155 }
156 #endif /* !USE_ASM_PUSH_REGS */
157
158 #if defined(HAVE_PUSH_REGS) && defined(THREADS)
159 # error GC_push_regs cannot be used with threads
160  /* Would fail for GC_do_blocking.  There are probably other safety     */
161  /* issues.                                                             */
162 # undef HAVE_PUSH_REGS
163 #endif
164
165 #if !defined(HAVE_PUSH_REGS) && defined(UNIX_LIKE)
166 # include <ucontext.h>
167 #endif
168
169 /* Ensure that either registers are pushed, or callee-save registers    */
170 /* are somewhere on the stack, and then call fn(arg, ctxt).             */
171 /* ctxt is either a pointer to a ucontext_t we generated, or NULL.      */
172 void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
173                                  ptr_t arg)
174 {
175     word dummy;
176     void * context = 0;
177
178 #   if defined(HAVE_PUSH_REGS)
179       GC_push_regs();
180 #   elif defined(UNIX_LIKE) && !defined(DARWIN) && !defined(ARM32) && \
181          !defined(MIPS) && !defined(HURD)
182       /* Older versions of Darwin seem to lack getcontext(). */
183       /* ARM Linux often doesn't support a real getcontext(). */
184       ucontext_t ctxt;
185       if (getcontext(&ctxt) < 0)
186         ABORT ("Getcontext failed: Use another register retrieval method?");
187       context = &ctxt;
188 #     if defined(SPARC) || defined(IA64)
189         /* On a register window machine, we need to save register       */
190         /* contents on the stack for this to work.  This may already be */
191         /* subsumed by the getcontext() call.                           */
192         {
193           GC_save_regs_ret_val = GC_save_regs_in_stack();
194         }
195 #     endif /* register windows. */
196 #   elif defined(HAVE_BUILTIN_UNWIND_INIT)
197       /* This was suggested by Richard Henderson as the way to  */
198       /* force callee-save registers and register windows onto  */
199       /* the stack.                                             */
200       __builtin_unwind_init();
201 #   else /* !HAVE_BUILTIN_UNWIND_INIT && !UNIX_LIKE  */
202          /* && !HAVE_PUSH_REGS                       */
203         /* Generic code                          */
204         /* The idea is due to Parag Patel at HP. */
205         /* We're not sure whether he would like  */
206         /* to be he acknowledged for it or not.  */
207         jmp_buf regs;
208         register word * i = (word *) regs;
209         register ptr_t lim = (ptr_t)(regs) + (sizeof regs);
210   
211         /* Setjmp doesn't always clear all of the buffer.               */
212         /* That tends to preserve garbage.  Clear it.                   */
213         for (; (char *)i < lim; i++) {
214             *i = 0;
215         }
216 #       if defined(MSWIN32) || defined(MSWINCE) \
217                   || defined(UTS4) || defined(LINUX) || defined(EWS4800)
218           (void) setjmp(regs);
219 #       else
220           (void) _setjmp(regs);
221           /* We don't want to mess with signals. According to   */
222           /* SUSV3, setjmp() may or may not save signal mask.   */
223           /* _setjmp won't, but is less portable.               */
224 #       endif
225 #   endif /* !HAVE_PUSH_REGS ... */
226     /* FIXME: context here is sometimes just zero.  At the moment the callees   */
227     /* don't really need it.                                                    */
228     fn(arg, context);
229     /* Strongly discourage the compiler from treating the above */
230     /* as a tail-call, since that would pop the register        */
231     /* contents before we get a chance to look at them.         */
232     GC_noop1((word)(&dummy));
233 }
234
235 void GC_push_regs_and_stack(ptr_t cold_gc_frame)
236 {
237     GC_with_callee_saves_pushed(GC_push_current_stack, cold_gc_frame);
238 }
239
240 #if defined(ASM_CLEAR_CODE)
241 # ifdef LINT
242     /*ARGSUSED*/
243     ptr_t GC_clear_stack_inner(arg, limit)
244     ptr_t arg; word limit;
245     { return(arg); }
246     /* The real version is in a .S file */
247 # endif
248 #endif /* ASM_CLEAR_CODE */