Synopsis - Cross-Reference

File: /src/Synopsis/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# 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 */