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