2
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
5
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
6
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
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.
14
/* Boehm, November 17, 1995 12:13 pm PST */
15
# include "private/gc_priv.h"
18
# if defined(OS2) || defined(CX_UX)
19
# define _setjmp(b) setjmp(b)
20
# define _longjmp(b,v) longjmp(b,v)
26
# include <machine/reg.h>
30
#if defined(__MWERKS__) && !defined(POWERPC)
32
asm static void PushMacRegisters()
34
sub.w #4,sp // reserve space for one parameter.
41
# if !__option(a6frames)
42
// <pcb> perhaps a6 should be pushed if stack frames are not being used.
46
// skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
59
add.w #4,sp // fix stack.
63
#endif /* __MWERKS__ */
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;
71
/* Routine to mark from registers that are preserved by the C compiler. */
72
/* This must be ported to every new architecture. It is noe optional, */
73
/* and should not be used on platforms that are either UNIX-like, or */
74
/* require thread support. */
78
#if defined(USE_ASM_PUSH_REGS)
79
# define HAVE_PUSH_REGS
80
#else /* No asm implementation */
83
# if defined(M68K) && defined(AMIGA)
84
/* AMIGA - could be replaced by generic code */
85
/* a0, a1, d0 and d1 are caller save */
88
asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
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");
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));
109
/* Can probably be changed to #if 0 -Kjetil M. (a4=globals)*/
110
GC_push_one(getreg(REG_A4));
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__ */
125
# if defined(M68K) && defined(MACOS)
126
# if defined(THINK_C)
127
# define PushMacReg(reg) \
131
sub.w #4,sp ; reserve space for one parameter.
135
; skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
142
add.w #4,sp ; fix stack.
144
# define HAVE_PUSH_REGS
146
# endif /* THINK_C */
147
# if defined(__MWERKS__)
149
# define HAVE_PUSH_REGS
150
# endif /* __MWERKS__ */
153
#endif /* !USE_ASM_PUSH_REGS */
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 */
159
# undef HAVE_PUSH_REGS
162
#if !defined(HAVE_PUSH_REGS) && defined(UNIX_LIKE)
163
# include <ucontext.h>
166
/* Ensure that either registers are pushed, or callee-save registers */
167
/* are somewhere on the stack, and then call fn(arg, ctxt). */
168
/* ctxt is either a pointer to a ucontext_t we generated, or NULL. */
169
void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
175
# if defined(HAVE_PUSH_REGS)
177
# elif defined(UNIX_LIKE) && !defined(DARWIN) && !defined(ARM32) && \
179
/* Older versions of Darwin seem to lack getcontext(). */
180
/* ARM Linux often doesn't support a real getcontext(). */
182
if (getcontext(&ctxt) < 0)
183
ABORT ("Getcontext failed: Use another register retrieval method?");
185
# if defined(SPARC) || defined(IA64)
186
/* On a register window machine, we need to save register */
187
/* contents on the stack for this to work. This may already be */
188
/* subsumed by the getcontext() call. */
190
GC_save_regs_ret_val = GC_save_regs_in_stack();
192
# endif /* register windows. */
193
# elif defined(HAVE_BUILTIN_UNWIND_INIT)
194
/* This was suggested by Richard Henderson as the way to */
195
/* force callee-save registers and register windows onto */
197
__builtin_unwind_init();
198
# else /* !HAVE_BUILTIN_UNWIND_INIT && !UNIX_LIKE */
199
/* && !HAVE_PUSH_REGS */
201
/* The idea is due to Parag Patel at HP. */
202
/* We're not sure whether he would like */
203
/* to be he acknowledged for it or not. */
205
register word * i = (word *) regs;
206
register ptr_t lim = (ptr_t)(regs) + (sizeof regs);
208
/* Setjmp doesn't always clear all of the buffer. */
209
/* That tends to preserve garbage. Clear it. */
210
for (; (char *)i < lim; i++) {
213
# if defined(MSWIN32) || defined(MSWINCE) \
214
|| defined(UTS4) || defined(LINUX) || defined(EWS4800)
217
(void) _setjmp(regs);
218
/* We don't want to mess with signals. According to */
219
/* SUSV3, setjmp() may or may not save signal mask. */
220
/* _setjmp won't, but is less portable. */
222
# endif /* !HAVE_PUSH_REGS ... */
223
/* FIXME: context here is sometimes just zero. At the moment the callees */
224
/* don't really need it. */
226
/* Strongly discourage the compiler from treating the above */
227
/* as a tail-call, since that would pop the register */
228
/* contents before we get a chance to look at them. */
229
GC_noop1((word)(&dummy));
232
void GC_push_regs_and_stack(ptr_t cold_gc_frame)
234
GC_with_callee_saves_pushed(GC_push_current_stack, cold_gc_frame);
237
#if defined(ASM_CLEAR_CODE)
240
ptr_t GC_clear_stack_inner(arg, limit)
241
ptr_t arg; word limit;
243
/* The real version is in a .S file */
245
#endif /* ASM_CLEAR_CODE */