Back to index

plt-scheme  4.2.1
mach_dep.c
Go to the documentation of this file.
00001 /* 
00002  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
00003  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
00004  *
00005  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
00006  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
00007  *
00008  * Permission is hereby granted to use or copy this program
00009  * for any purpose,  provided the above notices are retained on all copies.
00010  * Permission to modify the code and to distribute modified code is granted,
00011  * provided the above notices are retained, and a notice that the code was
00012  * modified is included with the above copyright notice.
00013  */
00014 /* Boehm, November 17, 1995 12:13 pm PST */
00015 # include "private/gc_priv.h"
00016 # include <stdio.h>
00017 # include <setjmp.h>
00018 # if defined(OS2) || defined(CX_UX)
00019 #   define _setjmp(b) setjmp(b)
00020 #   define _longjmp(b,v) longjmp(b,v)
00021 # endif
00022 # ifdef AMIGA
00023 #   ifndef __GNUC__
00024 #     include <dos.h>
00025 #   else
00026 #     include <machine/reg.h>
00027 #   endif
00028 # endif
00029 
00030 #if defined(RS6000) || defined(POWERPC)
00031 # include <ucontext.h>
00032 #endif
00033 
00034 #if defined(__MWERKS__) && !defined(POWERPC)
00035 
00036 asm static void PushMacRegisters()
00037 {
00038     sub.w   #4,sp                   // reserve space for one parameter.
00039     move.l  a2,(sp)
00040     jsr              GC_push_one
00041     move.l  a3,(sp)
00042     jsr              GC_push_one
00043     move.l  a4,(sp)
00044     jsr              GC_push_one
00045 #   if !__option(a6frames)
00046        // <pcb> perhaps a6 should be pushed if stack frames are not being used.    
00047        move.l a6,(sp)
00048        jsr           GC_push_one
00049 #   endif
00050        // skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
00051     move.l  d2,(sp)
00052     jsr              GC_push_one
00053     move.l  d3,(sp)
00054     jsr              GC_push_one
00055     move.l  d4,(sp)
00056     jsr              GC_push_one
00057     move.l  d5,(sp)
00058     jsr              GC_push_one
00059     move.l  d6,(sp)
00060     jsr              GC_push_one
00061     move.l  d7,(sp)
00062     jsr              GC_push_one
00063     add.w   #4,sp                   // fix stack.
00064     rts
00065 }
00066 
00067 #endif /* __MWERKS__ */
00068 
00069 # if defined(SPARC) || defined(IA64)
00070     /* Value returned from register flushing routine; either sp (SPARC) */
00071     /* or ar.bsp (IA64)                                               */
00072     word GC_save_regs_ret_val;
00073 # endif
00074 
00075 /* Routine to mark from registers that are preserved by the C compiler. */
00076 /* This must be ported to every new architecture.  There is a generic   */
00077 /* version at the end, that is likely, but not guaranteed to work       */
00078 /* on your architecture.  Run the test_setjmp program to see whether    */
00079 /* there is any chance it will work.                                    */
00080 
00081 #if !defined(USE_GENERIC_PUSH_REGS) && !defined(USE_ASM_PUSH_REGS)
00082 #undef HAVE_PUSH_REGS
00083 void GC_push_regs()
00084 {
00085 #       ifdef RT
00086          register long TMP_SP; /* must be bound to r11 */
00087 #       endif
00088 
00089 #       ifdef VAX
00090          /* VAX - generic code below does not work under 4.2 */
00091          /* r1 through r5 are caller save, and therefore     */
00092          /* on the stack or dead.                            */
00093          asm("pushl r11");     asm("calls $1,_GC_push_one");
00094          asm("pushl r10");  asm("calls $1,_GC_push_one");
00095          asm("pushl r9");   asm("calls $1,_GC_push_one");
00096          asm("pushl r8");   asm("calls $1,_GC_push_one");
00097          asm("pushl r7");   asm("calls $1,_GC_push_one");
00098          asm("pushl r6");   asm("calls $1,_GC_push_one");
00099 #        define HAVE_PUSH_REGS
00100 #       endif
00101 #       if defined(M68K) && (defined(SUNOS4) || defined(NEXT))
00102        /*  M68K SUNOS - could be replaced by generic code */
00103          /* a0, a1 and d1 are caller save          */
00104          /*  and therefore are on stack or dead.   */
00105        
00106          asm("subqw #0x4,sp");            /* allocate word on top of stack */
00107 
00108          asm("movl a2,sp@");       asm("jbsr _GC_push_one");
00109          asm("movl a3,sp@");       asm("jbsr _GC_push_one");
00110          asm("movl a4,sp@");       asm("jbsr _GC_push_one");
00111          asm("movl a5,sp@");       asm("jbsr _GC_push_one");
00112          /* Skip frame pointer and stack pointer */
00113          asm("movl d1,sp@");       asm("jbsr _GC_push_one");
00114          asm("movl d2,sp@");       asm("jbsr _GC_push_one");
00115          asm("movl d3,sp@");       asm("jbsr _GC_push_one");
00116          asm("movl d4,sp@");       asm("jbsr _GC_push_one");
00117          asm("movl d5,sp@");       asm("jbsr _GC_push_one");
00118          asm("movl d6,sp@");       asm("jbsr _GC_push_one");
00119          asm("movl d7,sp@");       asm("jbsr _GC_push_one");
00120 
00121          asm("addqw #0x4,sp");            /* put stack back where it was     */
00122 #        define HAVE_PUSH_REGS
00123 #       endif
00124 
00125 #       if defined(M68K) && defined(HP)
00126        /*  M68K HP - could be replaced by generic code */
00127          /* a0, a1 and d1 are caller save.  */
00128        
00129          asm("subq.w &0x4,%sp");   /* allocate word on top of stack */
00130 
00131          asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one");
00132          asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one");
00133          asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one");
00134          asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one");
00135          /* Skip frame pointer and stack pointer */
00136          asm("mov.l %d1,(%sp)"); asm("jsr _GC_push_one");
00137          asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one");
00138          asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one");
00139          asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one");
00140          asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one");
00141          asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one");
00142          asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
00143 
00144          asm("addq.w &0x4,%sp");   /* put stack back where it was     */
00145 #        define HAVE_PUSH_REGS
00146 #       endif /* M68K HP */
00147 
00148 #      if defined(M68K) && defined(AMIGA)
00149         /*  AMIGA - could be replaced by generic code                 */
00150         /* a0, a1, d0 and d1 are caller save */
00151 
00152 #        ifdef __GNUC__
00153          asm("subq.w &0x4,%sp");   /* allocate word on top of stack */
00154 
00155          asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one");
00156          asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one");
00157          asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one");
00158          asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one");
00159          asm("mov.l %a6,(%sp)"); asm("jsr _GC_push_one");
00160          /* Skip frame pointer and stack pointer */
00161          asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one");
00162          asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one");
00163          asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one");
00164          asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one");
00165          asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one");
00166          asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
00167 
00168          asm("addq.w &0x4,%sp");   /* put stack back where it was     */
00169 #        define HAVE_PUSH_REGS
00170 #        else /* !__GNUC__ */
00171          GC_push_one(getreg(REG_A2));
00172          GC_push_one(getreg(REG_A3));
00173 #         ifndef __SASC
00174              /* Can probably be changed to #if 0 -Kjetil M. (a4=globals)*/
00175            GC_push_one(getreg(REG_A4));
00176 #        endif
00177          GC_push_one(getreg(REG_A5));
00178          GC_push_one(getreg(REG_A6));
00179          /* Skip stack pointer */
00180          GC_push_one(getreg(REG_D2));
00181          GC_push_one(getreg(REG_D3));
00182          GC_push_one(getreg(REG_D4));
00183          GC_push_one(getreg(REG_D5));
00184          GC_push_one(getreg(REG_D6));
00185          GC_push_one(getreg(REG_D7));
00186 #        define HAVE_PUSH_REGS
00187 #       endif /* !__GNUC__ */
00188 #       endif /* AMIGA */
00189 
00190 #      if defined(M68K) && defined(MACOS)
00191 #      if defined(THINK_C)
00192 #         define PushMacReg(reg) \
00193               move.l  reg,(sp) \
00194               jsr             GC_push_one
00195          asm {
00196               sub.w   #4,sp                   ; reserve space for one parameter.
00197               PushMacReg(a2);
00198               PushMacReg(a3);
00199               PushMacReg(a4);
00200               ; skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
00201               PushMacReg(d2);
00202               PushMacReg(d3);
00203               PushMacReg(d4);
00204               PushMacReg(d5);
00205               PushMacReg(d6);
00206               PushMacReg(d7);
00207               add.w   #4,sp                   ; fix stack.
00208          }
00209 #        define HAVE_PUSH_REGS
00210 #        undef PushMacReg
00211 #      endif /* THINK_C */
00212 #      if defined(__MWERKS__)
00213          PushMacRegisters();
00214 #        define HAVE_PUSH_REGS
00215 #      endif  /* __MWERKS__ */
00216 #   endif     /* MACOS */
00217 
00218 #       if defined(I386) &&!defined(OS2) &&!defined(SVR4) \
00219        && (defined(__MINGW32__) || !defined(MSWIN32)) \
00220        && !defined(SCO) && !defined(SCO_ELF) \
00221        && !(defined(LINUX) && defined(__ELF__)) \
00222        && !(defined(FREEBSD) && defined(__ELF__)) \
00223        && !(defined(NETBSD) && defined(__ELF__)) \
00224        && !(defined(OPENBSD) && defined(__ELF__)) \
00225        && !(defined(BEOS) && defined(__ELF__)) \
00226        && !defined(DOS4GW) && !defined(HURD)
00227        /* I386 code, generic code does not appear to work */
00228        /* It does appear to work under OS2, and asms dont */
00229        /* This is used for some 38g UNIX variants and for CYGWIN32 */
00230          asm("pushl %eax");  asm("call _GC_push_one"); asm("addl $4,%esp");
00231          asm("pushl %ecx");  asm("call _GC_push_one"); asm("addl $4,%esp");
00232          asm("pushl %edx");  asm("call _GC_push_one"); asm("addl $4,%esp");
00233          asm("pushl %ebp");  asm("call _GC_push_one"); asm("addl $4,%esp");
00234          asm("pushl %esi");  asm("call _GC_push_one"); asm("addl $4,%esp");
00235          asm("pushl %edi");  asm("call _GC_push_one"); asm("addl $4,%esp");
00236          asm("pushl %ebx");  asm("call _GC_push_one"); asm("addl $4,%esp");
00237 #        define HAVE_PUSH_REGS
00238 #       endif
00239 
00240 #      if ( defined(I386) && defined(LINUX) && defined(__ELF__) ) \
00241        || ( defined(I386) && defined(FREEBSD) && defined(__ELF__) ) \
00242        || ( defined(I386) && defined(NETBSD) && defined(__ELF__) ) \
00243        || ( defined(I386) && defined(OPENBSD) && defined(__ELF__) ) \
00244        || ( defined(I386) && defined(HURD) && defined(__ELF__) ) \
00245        || ( defined(I386) && defined(DGUX) )
00246 
00247        /* This is modified for Linux with ELF (Note: _ELF_ only) */
00248        /* This section handles FreeBSD with ELF. */
00249        /* Eax is caller-save and dead here.  Other caller-save        */
00250        /* registers could also be skipped.  We assume there are no    */
00251        /* pointers in MMX registers, etc.                      */
00252        /* We combine instructions in a single asm to prevent gcc from        */
00253        /* inserting code in the middle.                        */
00254          asm("pushl %ecx; call GC_push_one; addl $4,%esp");
00255          asm("pushl %edx; call GC_push_one; addl $4,%esp");
00256          asm("pushl %ebp; call GC_push_one; addl $4,%esp");
00257          asm("pushl %esi; call GC_push_one; addl $4,%esp");
00258          asm("pushl %edi; call GC_push_one; addl $4,%esp");
00259          asm("pushl %ebx; call GC_push_one; addl $4,%esp");
00260 #        define HAVE_PUSH_REGS
00261 #      endif
00262 
00263 #      if ( defined(I386) && defined(BEOS) && defined(__ELF__) )
00264        /* As far as I can understand from                      */
00265        /* http://www.beunited.org/articles/jbq/nasm.shtml,            */
00266        /* only ebp, esi, edi and ebx are not scratch. How MMX         */
00267        /* etc. registers should be treated, I have no idea.           */
00268          asm("pushl %ebp; call GC_push_one; addl $4,%esp");
00269          asm("pushl %esi; call GC_push_one; addl $4,%esp");
00270          asm("pushl %edi; call GC_push_one; addl $4,%esp");
00271          asm("pushl %ebx; call GC_push_one; addl $4,%esp");
00272 #        define HAVE_PUSH_REGS
00273 #       endif
00274 
00275 #       if defined(I386) && defined(MSWIN32) && !defined(__MINGW32__) \
00276           && !defined(USE_GENERIC)
00277        /* I386 code, Microsoft variant           */
00278          __asm  push eax
00279          __asm  call GC_push_one
00280          __asm  add esp,4
00281          __asm  push ebx
00282          __asm  call GC_push_one
00283          __asm  add esp,4
00284          __asm  push ecx
00285          __asm  call GC_push_one
00286          __asm  add esp,4
00287          __asm  push edx
00288          __asm  call GC_push_one
00289          __asm  add esp,4
00290          __asm  push ebp
00291          __asm  call GC_push_one
00292          __asm  add esp,4
00293          __asm  push esi
00294          __asm  call GC_push_one
00295          __asm  add esp,4
00296          __asm  push edi
00297          __asm  call GC_push_one
00298          __asm  add esp,4
00299 #        define HAVE_PUSH_REGS
00300 #       endif
00301 
00302 #       if defined(I386) && (defined(SVR4) || defined(SCO) || defined(SCO_ELF))
00303        /* I386 code, SVR4 variant, generic code does not appear to work */
00304          asm("pushl %eax");  asm("call GC_push_one"); asm("addl $4,%esp");
00305          asm("pushl %ebx");  asm("call GC_push_one"); asm("addl $4,%esp");
00306          asm("pushl %ecx");  asm("call GC_push_one"); asm("addl $4,%esp");
00307          asm("pushl %edx");  asm("call GC_push_one"); asm("addl $4,%esp");
00308          asm("pushl %ebp");  asm("call GC_push_one"); asm("addl $4,%esp");
00309          asm("pushl %esi");  asm("call GC_push_one"); asm("addl $4,%esp");
00310          asm("pushl %edi");  asm("call GC_push_one"); asm("addl $4,%esp");
00311 #        define HAVE_PUSH_REGS
00312 #       endif
00313 
00314 #       ifdef NS32K
00315          asm ("movd r3, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
00316          asm ("movd r4, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
00317          asm ("movd r5, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
00318          asm ("movd r6, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
00319          asm ("movd r7, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
00320 #        define HAVE_PUSH_REGS
00321 #       endif
00322 
00323 #       if defined(SPARC)
00324          GC_save_regs_ret_val = GC_save_regs_in_stack();
00325 #        define HAVE_PUSH_REGS
00326 #       endif
00327 
00328 #      ifdef RT
00329            GC_push_one(TMP_SP);    /* GC_push_one from r11 */
00330 
00331            asm("cas r11, r6, r0"); GC_push_one(TMP_SP); /* r6 */
00332            asm("cas r11, r7, r0"); GC_push_one(TMP_SP); /* through */
00333            asm("cas r11, r8, r0"); GC_push_one(TMP_SP); /* r10 */
00334            asm("cas r11, r9, r0"); GC_push_one(TMP_SP);
00335            asm("cas r11, r10, r0"); GC_push_one(TMP_SP);
00336 
00337            asm("cas r11, r12, r0"); GC_push_one(TMP_SP); /* r12 */
00338            asm("cas r11, r13, r0"); GC_push_one(TMP_SP); /* through */
00339            asm("cas r11, r14, r0"); GC_push_one(TMP_SP); /* r15 */
00340            asm("cas r11, r15, r0"); GC_push_one(TMP_SP);
00341 #          define HAVE_PUSH_REGS
00342 #       endif
00343 
00344 #       if defined(M68K) && defined(SYSV)
00345        /*  Once again similar to SUN and HP, though setjmp appears to work.
00346               --Parag
00347         */
00348 #        ifdef __GNUC__
00349          asm("subqw #0x4,%sp");    /* allocate word on top of stack */
00350   
00351          asm("movl %a2,%sp@");     asm("jbsr GC_push_one");
00352          asm("movl %a3,%sp@");     asm("jbsr GC_push_one");
00353          asm("movl %a4,%sp@");     asm("jbsr GC_push_one");
00354          asm("movl %a5,%sp@");     asm("jbsr GC_push_one");
00355          /* Skip frame pointer and stack pointer */
00356          asm("movl %d1,%sp@");     asm("jbsr GC_push_one");
00357          asm("movl %d2,%sp@");     asm("jbsr GC_push_one");
00358          asm("movl %d3,%sp@");     asm("jbsr GC_push_one");
00359          asm("movl %d4,%sp@");     asm("jbsr GC_push_one");
00360          asm("movl %d5,%sp@");     asm("jbsr GC_push_one");
00361          asm("movl %d6,%sp@");     asm("jbsr GC_push_one");
00362          asm("movl %d7,%sp@");     asm("jbsr GC_push_one");
00363   
00364          asm("addqw #0x4,%sp");    /* put stack back where it was     */
00365 #        define HAVE_PUSH_REGS
00366 #        else /* !__GNUC__*/
00367          asm("subq.w &0x4,%sp");   /* allocate word on top of stack */
00368   
00369          asm("mov.l %a2,(%sp)"); asm("jsr GC_push_one");
00370          asm("mov.l %a3,(%sp)"); asm("jsr GC_push_one");
00371          asm("mov.l %a4,(%sp)"); asm("jsr GC_push_one");
00372          asm("mov.l %a5,(%sp)"); asm("jsr GC_push_one");
00373          /* Skip frame pointer and stack pointer */
00374          asm("mov.l %d1,(%sp)"); asm("jsr GC_push_one");
00375          asm("mov.l %d2,(%sp)"); asm("jsr GC_push_one");
00376          asm("mov.l %d3,(%sp)"); asm("jsr GC_push_one");
00377          asm("mov.l %d4,(%sp)"); asm("jsr GC_push_one");
00378          asm("mov.l %d5,(%sp)"); asm("jsr GC_push_one");
00379          asm("mov.l %d6,(%sp)"); asm("jsr GC_push_one");
00380          asm("mov.l %d7,(%sp)"); asm("jsr GC_push_one");
00381   
00382          asm("addq.w &0x4,%sp");   /* put stack back where it was     */
00383 #        define HAVE_PUSH_REGS
00384 #        endif /* !__GNUC__ */
00385 #       endif /* M68K/SYSV */
00386 
00387 #     if defined(PJ)
00388        {
00389            register int * sp asm ("optop");
00390            extern int *__libc_stack_end;
00391 
00392            GC_push_all_stack (sp, __libc_stack_end);
00393 #          define HAVE_PUSH_REGS
00394            /* Isn't this redundant with the code to push the stack? */
00395         }
00396 #     endif
00397 
00398       /* other machines... */
00399 #       if !defined(HAVE_PUSH_REGS)
00400            --> We just generated an empty GC_push_regs, which
00401            --> is almost certainly broken.  Try defining
00402            --> USE_GENERIC_PUSH_REGS instead.
00403 #       endif
00404 }
00405 #endif /* !USE_GENERIC_PUSH_REGS && !USE_ASM_PUSH_REGS */
00406 
00407 void GC_with_callee_saves_pushed(fn, arg)
00408 void (*fn)();
00409 ptr_t arg;
00410 {
00411     word dummy;
00412 
00413 #   if defined(USE_GENERIC_PUSH_REGS)
00414 #     ifdef HAVE_BUILTIN_UNWIND_INIT
00415         /* This was suggested by Richard Henderson as the way to      */
00416         /* force callee-save registers and register windows onto      */
00417         /* the stack.                                          */
00418         __builtin_unwind_init();
00419 #     else /* !HAVE_BUILTIN_UNWIND_INIT */
00420 #      if defined(RS6000) || defined(POWERPC)
00421        /* FIXME: RS6000 means AIX.                      */
00422         /* This should probably be used in all Posix/non-gcc   */
00423         /* settings.  We defer that change to minimize risk.   */
00424         ucontext_t ctxt;
00425         getcontext(&ctxt);
00426 #      else
00427         /* Generic code                          */
00428         /* The idea is due to Parag Patel at HP. */
00429         /* We're not sure whether he would like  */
00430         /* to be he acknowledged for it or not.  */
00431         jmp_buf regs;
00432         register word * i = (word *) regs;
00433         register ptr_t lim = (ptr_t)(regs) + (sizeof regs);
00434   
00435         /* Setjmp doesn't always clear all of the buffer.             */
00436         /* That tends to preserve garbage.  Clear it.                 */
00437        for (; (char *)i < lim; i++) {
00438            *i = 0;
00439        }
00440 #       if defined(MSWIN32) || defined(MSWINCE) \
00441                   || defined(UTS4) || defined(LINUX) || defined(EWS4800)
00442          (void) setjmp(regs);
00443 #       else
00444             (void) _setjmp(regs);
00445          /* We don't want to mess with signals. According to   */
00446          /* SUSV3, setjmp() may or may not save signal mask.   */
00447          /* _setjmp won't, but is less portable.        */
00448 #       endif
00449 #      endif /* !AIX ... */
00450 #     endif /* !HAVE_BUILTIN_UNWIND_INIT */
00451 #   else
00452 #     if defined(PTHREADS) && !defined(MSWIN32) /* !USE_GENERIC_PUSH_REGS */
00453         /* We may still need this to save thread contexts.     */
00454         ucontext_t ctxt;
00455         getcontext(&ctxt);
00456 #     else  /* Shouldn't be needed */
00457         ABORT("Unexpected call to GC_with_callee_saves_pushed");
00458 #     endif
00459 #   endif
00460 #   if (defined(SPARC) && !defined(HAVE_BUILTIN_UNWIND_INIT)) \
00461        || defined(IA64)
00462       /* On a register window machine, we need to save register       */
00463       /* contents on the stack for this to work.  The setjmp   */
00464       /* is probably not needed on SPARC, since pointers are   */
00465       /* only stored in windowed or scratch registers.  It is  */
00466       /* needed on IA64, since some non-windowed registers are */
00467       /* preserved.                                     */
00468       {
00469         GC_save_regs_ret_val = GC_save_regs_in_stack();
00470        /* On IA64 gcc, could use __builtin_ia64_flushrs() and  */
00471        /* __builtin_ia64_flushrs().  The latter will be done   */
00472        /* implicitly by __builtin_unwind_init() for gcc3.0.1   */
00473        /* and later.                                    */
00474       }
00475 #   endif
00476     fn(arg);
00477     /* Strongly discourage the compiler from treating the above       */
00478     /* as a tail-call, since that would pop the register       */
00479     /* contents before we get a chance to look at them.        */
00480     GC_noop1((word)(&dummy));
00481 }
00482 
00483 #if defined(USE_GENERIC_PUSH_REGS)
00484 void GC_generic_push_regs(cold_gc_frame)
00485 ptr_t cold_gc_frame;
00486 {
00487     GC_with_callee_saves_pushed(GC_push_current_stack, cold_gc_frame);
00488 }
00489 #endif /* USE_GENERIC_PUSH_REGS */
00490 
00491 /* On register window machines, we need a way to force registers into        */
00492 /* the stack. Return sp.                                       */
00493 # ifdef SPARC
00494     asm("     .seg   \"text\"");
00495 #   if defined(SVR4) || defined(NETBSD) || defined(FREEBSD)
00496       asm("   .globl GC_save_regs_in_stack");
00497       asm("GC_save_regs_in_stack:");
00498       asm("   .type GC_save_regs_in_stack,#function");
00499 #   else
00500       asm("   .globl _GC_save_regs_in_stack");
00501       asm("_GC_save_regs_in_stack:");
00502 #   endif
00503 #   if defined(__arch64__) || defined(__sparcv9)
00504       asm("   save   %sp,-128,%sp");
00505       asm("   flushw");
00506       asm("   ret");
00507       asm("   restore %sp,2047+128,%o0");
00508 #   else
00509       asm("   ta     0x3   ! ST_FLUSH_WINDOWS");
00510       asm("   retl");
00511       asm("   mov    %sp,%o0");
00512 #   endif
00513 #   ifdef SVR4
00514       asm("   .GC_save_regs_in_stack_end:");
00515       asm("   .size GC_save_regs_in_stack,.GC_save_regs_in_stack_end-GC_save_regs_in_stack");
00516 #   endif
00517 #   ifdef LINT
00518        word GC_save_regs_in_stack() { return(0 /* sp really */);}
00519 #   endif
00520 # endif
00521 
00522 /* On IA64, we also need to flush register windows.  But they end     */
00523 /* up on the other side of the stack segment.                         */
00524 /* Returns the backing store pointer for the register stack.          */
00525 /* We now implement this as a separate assembly file, since inline    */
00526 /* assembly code here doesn't work with either the Intel or HP               */
00527 /* compilers.                                                  */
00528 # if 0
00529 #   ifdef LINUX
00530        asm("        .text");
00531        asm("        .psr abi64");
00532        asm("        .psr lsb");
00533        asm("        .lsb");
00534        asm("");
00535        asm("        .text");
00536        asm("        .align 16");
00537        asm("        .global GC_save_regs_in_stack");
00538        asm("        .proc GC_save_regs_in_stack");
00539        asm("GC_save_regs_in_stack:");
00540        asm("        .body");
00541        asm("        flushrs");
00542        asm("        ;;");
00543        asm("        mov r8=ar.bsp");
00544        asm("        br.ret.sptk.few rp");
00545        asm("        .endp GC_save_regs_in_stack");
00546 #   endif /* LINUX */
00547 #   if 0 /* Other alternatives that don't work on HP/UX */
00548        word GC_save_regs_in_stack() {
00549 #        if USE_BUILTINS
00550            __builtin_ia64_flushrs();
00551            return __builtin_ia64_bsp();
00552 #        else
00553 #          ifdef HPUX
00554              _asm("        flushrs");
00555              _asm("        ;;");
00556              _asm("        mov r8=ar.bsp");
00557              _asm("        br.ret.sptk.few rp");
00558 #          else
00559              asm("        flushrs");
00560              asm("        ;;");
00561              asm("        mov r8=ar.bsp");
00562              asm("        br.ret.sptk.few rp");
00563 #          endif
00564 #        endif
00565        }
00566 #   endif
00567 # endif
00568 
00569 /* GC_clear_stack_inner(arg, limit) clears stack area up to limit and */
00570 /* returns arg.  Stack clearing is crucial on SPARC, so we supply     */
00571 /* an assembly version that's more careful.  Assumes limit is hotter  */
00572 /* than sp, and limit is 8 byte aligned.                       */
00573 #if defined(ASM_CLEAR_CODE)
00574 #ifndef SPARC
00575        --> fix it
00576 #endif
00577 # ifdef SUNOS4
00578     asm(".globl _GC_clear_stack_inner");
00579     asm("_GC_clear_stack_inner:");
00580 # else
00581     asm(".globl GC_clear_stack_inner");
00582     asm("GC_clear_stack_inner:");
00583     asm(".type GC_save_regs_in_stack,#function");
00584 # endif
00585 #if defined(__arch64__) || defined(__sparcv9)
00586   asm("mov %sp,%o2");              /* Save sp                  */
00587   asm("add %sp,2047-8,%o3");       /* p = sp+bias-8            */
00588   asm("add %o1,-2047-192,%sp");    /* Move sp out of the way,  */
00589                             /* so that traps still work.       */
00590                             /* Includes some extra words       */
00591                             /* so we can be sloppy below.      */
00592   asm("loop:");
00593   asm("stx %g0,[%o3]");            /* *(long *)p = 0           */
00594   asm("cmp %o3,%o1");
00595   asm("bgu,pt %xcc, loop"); /* if (p > limit) goto loop */
00596     asm("add %o3,-8,%o3");  /* p -= 8 (delay slot) */
00597   asm("retl");
00598     asm("mov %o2,%sp");            /* Restore sp., delay slot  */
00599 #else
00600   asm("mov %sp,%o2");              /* Save sp    */
00601   asm("add %sp,-8,%o3");    /* p = sp-8   */
00602   asm("clr %g1");           /* [g0,g1] = 0       */
00603   asm("add %o1,-0x60,%sp"); /* Move sp out of the way,  */
00604                             /* so that traps still work.       */
00605                             /* Includes some extra words       */
00606                             /* so we can be sloppy below.      */
00607   asm("loop:");
00608   asm("std %g0,[%o3]");            /* *(long long *)p = 0      */
00609   asm("cmp %o3,%o1");
00610   asm("bgu loop      ");           /* if (p > limit) goto loop */
00611     asm("add %o3,-8,%o3");  /* p -= 8 (delay slot) */
00612   asm("retl");
00613     asm("mov %o2,%sp");            /* Restore sp., delay slot  */
00614 #endif /* old SPARC */
00615   /* First argument = %o0 = return value */
00616 #   ifdef SVR4
00617       asm("   .GC_clear_stack_inner_end:");
00618       asm("   .size GC_clear_stack_inner,.GC_clear_stack_inner_end-GC_clear_stack_inner");
00619 #   endif
00620   
00621 # ifdef LINT
00622     /*ARGSUSED*/
00623     ptr_t GC_clear_stack_inner(arg, limit)
00624     ptr_t arg; word limit;
00625     { return(arg); }
00626 # endif
00627 #endif