Synopsis - Cross-Reference
File: /src/Synopsis/gc/mach_dep.c1/* 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 32asm 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 noe 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 */ 81void 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(HAVE_PUSH_REGS) && defined(UNIX_LIKE) 163# include <ucontext.h> 164#endif 165 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. */ 169void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *), 170 ptr_t arg) 171{ 172 word dummy; 173 void * context = 0; 174 175# if defined(HAVE_PUSH_REGS) 176 GC_push_regs(); 177# elif defined(UNIX_LIKE) && !defined(DARWIN) && !defined(ARM32) 178 /* Older versions of Darwin seem to lack getcontext(). */ 179 /* ARM Linux often doesn't support a real getcontext(). */ 180 ucontext_t ctxt; 181 if (getcontext(&ctxt) < 0) 182 ABORT ("Getcontext failed: Use another register retrieval method?"); 183 context = &ctxt; 184# if defined(SPARC) || defined(IA64) 185 /* On a register window machine, we need to save register */ 186 /* contents on the stack for this to work. This may already be */ 187 /* subsumed by the getcontext() call. */ 188 { 189 GC_save_regs_ret_val = GC_save_regs_in_stack(); 190 } 191# endif /* register windows. */ 192# elif defined(HAVE_BUILTIN_UNWIND_INIT) 193 /* This was suggested by Richard Henderson as the way to */ 194 /* force callee-save registers and register windows onto */ 195 /* the stack. */ 196 __builtin_unwind_init(); 197# else /* !HAVE_BUILTIN_UNWIND_INIT && !UNIX_LIKE */ 198 /* && !HAVE_PUSH_REGS */ 199 /* Generic code */ 200 /* The idea is due to Parag Patel at HP. */ 201 /* We're not sure whether he would like */ 202 /* to be he acknowledged for it or not. */ 203 jmp_buf regs; 204 register word * i = (word *) regs; 205 register ptr_t lim = (ptr_t)(regs) + (sizeof regs); 206 207 /* Setjmp doesn't always clear all of the buffer. */ 208 /* That tends to preserve garbage. Clear it. */ 209 for (; (char *)i < lim; i++) { 210 *i = 0; 211 } 212# if defined(MSWIN32) || defined(MSWINCE) \ 213 || defined(UTS4) || defined(LINUX) || defined(EWS4800) 214 (void) setjmp(regs); 215# else 216 (void) _setjmp(regs); 217 /* We don't want to mess with signals. According to */ 218 /* SUSV3, setjmp() may or may not save signal mask. */ 219 /* _setjmp won't, but is less portable. */ 220# endif 221# endif /* !HAVE_PUSH_REGS ... */ 222 fn(arg, context); 223 /* Strongly discourage the compiler from treating the above */ 224 /* as a tail-call, since that would pop the register */ 225 /* contents before we get a chance to look at them. */ 226 GC_noop1((word)(&dummy)); 227} 228 229void GC_push_regs_and_stack(ptr_t cold_gc_frame) 230{ 231 GC_with_callee_saves_pushed(GC_push_current_stack, cold_gc_frame); 232} 233 234#if defined(ASM_CLEAR_CODE) 235# ifdef LINT 236 /*ARGSUSED*/ 237 ptr_t GC_clear_stack_inner(arg, limit) 238 ptr_t arg; word limit; 239 { return(arg); } 240 /* The real version is in a .S file */ 241# endif 242#endif /* ASM_CLEAR_CODE */