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