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