[BACK]Return to os_dep.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib2 / asir2000 / gc

Diff for /OpenXM_contrib2/asir2000/gc/os_dep.c between version 1.1.1.1 and 1.6

version 1.1.1.1, 1999/12/03 07:39:10 version 1.6, 2002/07/24 08:00:11
Line 1 
Line 1 
 int ox_usr1_sent, ox_int_received, critical_when_signal;  
 static int inside_critical_section;  
   
 /*  /*
    * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.   * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1997 by Silicon Graphics.  All rights reserved.   * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
    * Copyright (c) 1999 by Hewlett-Packard Company.  All rights reserved.
  *   *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED   * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.   * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
Line 15  static int inside_critical_section;
Line 14  static int inside_critical_section;
  * modified is included with the above copyright notice.   * modified is included with the above copyright notice.
  */   */
   
 # include "gc_priv.h"  # include "private/gc_priv.h"
   
 # if defined(LINUX) && !defined(POWERPC)  # if defined(LINUX) && !defined(POWERPC)
 #   include <linux/version.h>  #   include <linux/version.h>
Line 34  static int inside_critical_section;
Line 33  static int inside_critical_section;
       /* make sure the former gets defined to be the latter if appropriate. */        /* make sure the former gets defined to be the latter if appropriate. */
 #     include <features.h>  #     include <features.h>
 #     if 2 <= __GLIBC__  #     if 2 <= __GLIBC__
 #       if 0 == __GLIBC_MINOR__  #       if 2 == __GLIBC__ && 0 == __GLIBC_MINOR__
           /* glibc 2.1 no longer has sigcontext.h.  But signal.h        */            /* glibc 2.1 no longer has sigcontext.h.  But signal.h        */
           /* has the right declaration for glibc 2.1.                   */            /* has the right declaration for glibc 2.1.                   */
 #         include <sigcontext.h>  #         include <sigcontext.h>
Line 46  static int inside_critical_section;
Line 45  static int inside_critical_section;
 #     endif /* 2 <= __GLIBC__ */  #     endif /* 2 <= __GLIBC__ */
 #   endif  #   endif
 # endif  # endif
 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS)  # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \
       && !defined(MSWINCE)
 #   include <sys/types.h>  #   include <sys/types.h>
 #   if !defined(MSWIN32) && !defined(SUNOS4)  #   if !defined(MSWIN32) && !defined(SUNOS4)
 #       include <unistd.h>  #       include <unistd.h>
Line 54  static int inside_critical_section;
Line 54  static int inside_critical_section;
 # endif  # endif
   
 # include <stdio.h>  # include <stdio.h>
 # include <signal.h>  # if defined(MSWINCE)
   #   define SIGSEGV 0 /* value is irrelevant */
   # else
   #   include <signal.h>
   # endif
   
 /* Blatantly OS dependent routines, except for those that are related   */  /* Blatantly OS dependent routines, except for those that are related   */
 /* dynamic loading.                                                     */  /* to dynamic loading.                                                  */
   
 # if !defined(THREADS) && !defined(STACKBOTTOM) && defined(HEURISTIC2)  # if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START)
 #   define NEED_FIND_LIMIT  #   define NEED_FIND_LIMIT
 # endif  # endif
   
 # if defined(IRIX_THREADS)  # if !defined(STACKBOTTOM) && defined(HEURISTIC2)
 #   define NEED_FIND_LIMIT  #   define NEED_FIND_LIMIT
 # endif  # endif
   
 # if (defined(SUNOS4) & defined(DYNAMIC_LOADING)) && !defined(PCR)  # if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR)
 #   define NEED_FIND_LIMIT  #   define NEED_FIND_LIMIT
 # endif  # endif
   
 # if (defined(SVR4) || defined(AUX) || defined(DGUX)) && !defined(PCR)  # if (defined(SVR4) || defined(AUX) || defined(DGUX) \
         || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
 #   define NEED_FIND_LIMIT  #   define NEED_FIND_LIMIT
 # endif  # endif
   
 # if defined(LINUX) && (defined(POWERPC) || defined(SPARC) || defined(ALPHA))  
 #   define NEED_FIND_LIMIT  
 # endif  
   
 #ifdef NEED_FIND_LIMIT  #ifdef NEED_FIND_LIMIT
 #   include <setjmp.h>  #   include <setjmp.h>
 #endif  #endif
   
 #ifdef FREEBSD  #if defined(FREEBSD) && defined(I386)
 #  include <machine/trap.h>  #  include <machine/trap.h>
 #endif  #endif
   
 #ifdef AMIGA  #ifdef AMIGA
 # include <proto/exec.h>  # define GC_AMIGA_DEF
 # include <proto/dos.h>  # include "AmigaOS.c"
 # include <dos/dosextens.h>  # undef GC_AMIGA_DEF
 # include <workbench/startup.h>  
 #endif  #endif
   
 #ifdef MSWIN32  #if defined(MSWIN32) || defined(MSWINCE)
 # define WIN32_LEAN_AND_MEAN  # define WIN32_LEAN_AND_MEAN
 # define NOSERVICE  # define NOSERVICE
 # include <windows.h>  # include <windows.h>
Line 112  static int inside_critical_section;
Line 112  static int inside_critical_section;
 # include <sys/types.h>  # include <sys/types.h>
 # include <sys/mman.h>  # include <sys/mman.h>
 # include <sys/stat.h>  # include <sys/stat.h>
   #endif
   
   #ifdef UNIX_LIKE
 # include <fcntl.h>  # include <fcntl.h>
 #endif  #endif
   
 #ifdef SUNOS5SIGS  #if defined(SUNOS5SIGS) || defined (HURD) || defined(LINUX)
 # include <sys/siginfo.h>  # ifdef SUNOS5SIGS
   #  include <sys/siginfo.h>
   # endif
 # undef setjmp  # undef setjmp
 # undef longjmp  # undef longjmp
 # define setjmp(env) sigsetjmp(env, 1)  # define setjmp(env) sigsetjmp(env, 1)
Line 125  static int inside_critical_section;
Line 130  static int inside_critical_section;
 #endif  #endif
   
 #ifdef DJGPP  #ifdef DJGPP
   /* Apparently necessary for djgpp 2.01.  May casuse problems with     */    /* Apparently necessary for djgpp 2.01.  May cause problems with      */
   /* other versions.                                                    */    /* other versions.                                                    */
   typedef long unsigned int caddr_t;    typedef long unsigned int caddr_t;
 #endif  #endif
Line 142  static int inside_critical_section;
Line 147  static int inside_critical_section;
 # define OPT_PROT_EXEC 0  # define OPT_PROT_EXEC 0
 #endif  #endif
   
 #if defined(LINUX) && (defined(POWERPC) || defined(SPARC) || defined(ALPHA))  #if defined(SEARCH_FOR_DATA_START)
   /* The I386 case can be handled without a search.  The Alpha case     */    /* The I386 case can be handled without a search.  The Alpha case     */
   /* used to be handled differently as well, but the rules changed      */    /* used to be handled differently as well, but the rules changed      */
   /* for recent Linux versions.  This seems to be the easiest way to    */    /* for recent Linux versions.  This seems to be the easiest way to    */
   /* cover all versions.                                                */    /* cover all versions.                                                */
   ptr_t GC_data_start;  
   
   extern char * GC_copyright[];  /* Any data symbol would do. */  # ifdef LINUX
   #   pragma weak __data_start
       extern int __data_start[];
   #   pragma weak data_start
       extern int data_start[];
   # endif /* LINUX */
     extern int _end[];
   
     ptr_t GC_data_start;
   
   void GC_init_linux_data_start()    void GC_init_linux_data_start()
   {    {
     extern ptr_t GC_find_limit();      extern ptr_t GC_find_limit();
   
     GC_data_start = GC_find_limit((ptr_t)GC_copyright, FALSE);  #   ifdef LINUX
         /* Try the easy approaches first: */
         if ((ptr_t)__data_start != 0) {
             GC_data_start = (ptr_t)(__data_start);
             return;
         }
         if ((ptr_t)data_start != 0) {
             GC_data_start = (ptr_t)(data_start);
             return;
         }
   #   endif /* LINUX */
       GC_data_start = GC_find_limit((ptr_t)(_end), FALSE);
   }    }
 #endif  #endif
   
   # ifdef ECOS
   
   # ifndef ECOS_GC_MEMORY_SIZE
   # define ECOS_GC_MEMORY_SIZE (448 * 1024)
   # endif /* ECOS_GC_MEMORY_SIZE */
   
   // setjmp() function, as described in ANSI para 7.6.1.1
   #define setjmp( __env__ )  hal_setjmp( __env__ )
   
   // FIXME: This is a simple way of allocating memory which is
   // compatible with ECOS early releases.  Later releases use a more
   // sophisticated means of allocating memory than this simple static
   // allocator, but this method is at least bound to work.
   static char memory[ECOS_GC_MEMORY_SIZE];
   static char *brk = memory;
   
   static void *tiny_sbrk(ptrdiff_t increment)
   {
     void *p = brk;
   
     brk += increment;
   
     if (brk >  memory + sizeof memory)
       {
         brk -= increment;
         return NULL;
       }
   
     return p;
   }
   #define sbrk tiny_sbrk
   # endif /* ECOS */
   
   #if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
     ptr_t GC_data_start;
   
     void GC_init_netbsd_elf()
     {
       extern ptr_t GC_find_limit();
       extern char **environ;
           /* This may need to be environ, without the underscore, for     */
           /* some versions.                                               */
       GC_data_start = GC_find_limit((ptr_t)&environ, FALSE);
     }
   #endif
   
 # ifdef OS2  # ifdef OS2
   
 # include <stddef.h>  # include <stddef.h>
Line 263  void GC_enable_signals(void)
Line 332  void GC_enable_signals(void)
 # else  # else
   
 #  if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \  #  if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \
       && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW)        && !defined(MSWINCE) \
         && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW) \
         && !defined(NOSYS) && !defined(ECOS)
   
 #   if defined(sigmask) && !defined(UTS4)  #   if defined(sigmask) && !defined(UTS4) && !defined(HURD)
         /* Use the traditional BSD interface */          /* Use the traditional BSD interface */
 #       define SIGSET_T int  #       define SIGSET_T int
 #       define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))  #       define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))
Line 322  void GC_disable_signals()
Line 393  void GC_disable_signals()
         GC_sig_disabled++;          GC_sig_disabled++;
 #   endif  #   endif
     SIGSETMASK(old_mask,new_mask);      SIGSETMASK(old_mask,new_mask);
         if ( critical_when_signal )  
                 inside_critical_section = 1;  
         else {  
                 inside_critical_section = 0;  
                 critical_when_signal = 1;  
         }  
 }  }
   
 void GC_enable_signals()  void GC_enable_signals()
Line 337  void GC_enable_signals()
Line 402  void GC_enable_signals()
         GC_sig_disabled--;          GC_sig_disabled--;
 #   endif  #   endif
     SIGSETMASK(dummy,old_mask);      SIGSETMASK(dummy,old_mask);
         if ( !inside_critical_section ) {  
                 critical_when_signal = 0;  
                 if ( ox_usr1_sent ) {  
                         ox_usr1_sent = 0; ox_usr1_handler();  
                 }  
                 if ( ox_int_received ) {  
                         ox_int_received = 0; int_handler();  
                 }  
         } else  
                 inside_critical_section = 0;  
 }  }
   
 #  endif  /* !PCR */  #  endif  /* !PCR */
Line 354  void GC_enable_signals()
Line 409  void GC_enable_signals()
 # endif /*!OS/2 */  # endif /*!OS/2 */
   
 /* Ivan Demakov: simplest way (to me) */  /* Ivan Demakov: simplest way (to me) */
 #ifdef DOS4GW  #if defined (DOS4GW)
   void GC_disable_signals() { }    void GC_disable_signals() { }
   void GC_enable_signals() { }    void GC_enable_signals() { }
 #endif  #endif
Line 362  void GC_enable_signals()
Line 417  void GC_enable_signals()
 /* Find the page size */  /* Find the page size */
 word GC_page_size;  word GC_page_size;
   
 # ifdef MSWIN32  # if defined(MSWIN32) || defined(MSWINCE)
   void GC_setpagesize()    void GC_setpagesize()
   {    {
     SYSTEM_INFO sysinfo;      GetSystemInfo(&GC_sysinfo);
       GC_page_size = GC_sysinfo.dwPageSize;
     GetSystemInfo(&sysinfo);  
     GC_page_size = sysinfo.dwPageSize;  
   }    }
   
 # else  # else
Line 393  word GC_page_size;
Line 446  word GC_page_size;
  * With threads, GC_mark_roots needs to know how to do this.   * With threads, GC_mark_roots needs to know how to do this.
  * Called with allocator lock held.   * Called with allocator lock held.
  */   */
 # ifdef MSWIN32  # if defined(MSWIN32) || defined(MSWINCE)
 # define is_writable(prot) ((prot) == PAGE_READWRITE \  # define is_writable(prot) ((prot) == PAGE_READWRITE \
                             || (prot) == PAGE_WRITECOPY \                              || (prot) == PAGE_WRITECOPY \
                             || (prot) == PAGE_EXECUTE_READWRITE \                              || (prot) == PAGE_EXECUTE_READWRITE \
Line 430  ptr_t GC_get_stack_base()
Line 483  ptr_t GC_get_stack_base()
 }  }
   
   
 # else  # endif /* MS Windows */
   
   # ifdef BEOS
   # include <kernel/OS.h>
   ptr_t GC_get_stack_base(){
           thread_info th;
           get_thread_info(find_thread(NULL),&th);
           return th.stack_end;
   }
   # endif /* BEOS */
   
   
 # ifdef OS2  # ifdef OS2
   
 ptr_t GC_get_stack_base()  ptr_t GC_get_stack_base()
Line 446  ptr_t GC_get_stack_base()
Line 509  ptr_t GC_get_stack_base()
     return((ptr_t)(ptib -> tib_pstacklimit));      return((ptr_t)(ptib -> tib_pstacklimit));
 }  }
   
 # else  # endif /* OS2 */
   
 # ifdef AMIGA  # ifdef AMIGA
   #   define GC_AMIGA_SB
   #   include "AmigaOS.c"
   #   undef GC_AMIGA_SB
   # endif /* AMIGA */
   
 ptr_t GC_get_stack_base()  # if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
 {  
     struct Process *proc = (struct Process*)SysBase->ThisTask;  
   
     /* Reference: Amiga Guru Book Pages: 42,567,574 */  
     if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS  
         && proc->pr_CLI != NULL) {  
         /* first ULONG is StackSize */  
         /*longPtr = proc->pr_ReturnAddr;  
         size = longPtr[0];*/  
   
         return (char *)proc->pr_ReturnAddr + sizeof(ULONG);  
     } else {  
         return (char *)proc->pr_Task.tc_SPUpper;  
     }  
 }  
   
 #if 0 /* old version */  
 ptr_t GC_get_stack_base()  
 {  
     extern struct WBStartup *_WBenchMsg;  
     extern long __base;  
     extern long __stack;  
     struct Task *task;  
     struct Process *proc;  
     struct CommandLineInterface *cli;  
     long size;  
   
     if ((task = FindTask(0)) == 0) {  
         GC_err_puts("Cannot find own task structure\n");  
         ABORT("task missing");  
     }  
     proc = (struct Process *)task;  
     cli = BADDR(proc->pr_CLI);  
   
     if (_WBenchMsg != 0 || cli == 0) {  
         size = (char *)task->tc_SPUpper - (char *)task->tc_SPLower;  
     } else {  
         size = cli->cli_DefaultStack * 4;  
     }  
     return (ptr_t)(__base + GC_max(size, __stack));  
 }  
 #endif /* 0 */  
   
 # else /* !AMIGA, !OS2, ... */  
   
 # ifdef NEED_FIND_LIMIT  
   /* Some tools to implement HEURISTIC2 */  
 #   define MIN_PAGE_SIZE 256    /* Smallest conceivable page size, bytes */  
     /* static */ jmp_buf GC_jmp_buf;  
   
     /*ARGSUSED*/  
     void GC_fault_handler(sig)  
     int sig;  
     {  
         longjmp(GC_jmp_buf, 1);  
     }  
   
 #   ifdef __STDC__  #   ifdef __STDC__
         typedef void (*handler)(int);          typedef void (*handler)(int);
 #   else  #   else
         typedef void (*handler)();          typedef void (*handler)();
 #   endif  #   endif
   
 #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)  #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) || defined(HURD)
         static struct sigaction old_segv_act;          static struct sigaction old_segv_act;
 #       if defined(_sigargs) /* !Irix6.x */  #       if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) || defined(HURD)
             static struct sigaction old_bus_act;              static struct sigaction old_bus_act;
 #       endif  #       endif
 #   else  #   else
         static handler old_segv_handler, old_bus_handler;          static handler old_segv_handler, old_bus_handler;
 #   endif  #   endif
   
     void GC_setup_temporary_fault_handler()  #   ifdef __STDC__
         void GC_set_and_save_fault_handler(handler h)
   #   else
         void GC_set_and_save_fault_handler(h)
         handler h;
   #   endif
     {      {
 #       if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)  #       if defined(SUNOS5SIGS) || defined(IRIX5)  \
           || defined(OSF1) || defined(HURD)
           struct sigaction      act;            struct sigaction      act;
   
           act.sa_handler        = GC_fault_handler;            act.sa_handler        = h;
           act.sa_flags          = SA_RESTART | SA_NODEFER;  #         ifdef SUNOS5SIGS
               act.sa_flags          = SA_RESTART | SA_NODEFER;
   #         else
               act.sa_flags          = SA_RESTART;
   #         endif
           /* The presence of SA_NODEFER represents yet another gross    */            /* The presence of SA_NODEFER represents yet another gross    */
           /* hack.  Under Solaris 2.3, siglongjmp doesn't appear to     */            /* hack.  Under Solaris 2.3, siglongjmp doesn't appear to     */
           /* interact correctly with -lthread.  We hide the confusion   */            /* interact correctly with -lthread.  We hide the confusion   */
Line 537  ptr_t GC_get_stack_base()
Line 558  ptr_t GC_get_stack_base()
           /* signal mask.                                               */            /* signal mask.                                               */
   
           (void) sigemptyset(&act.sa_mask);            (void) sigemptyset(&act.sa_mask);
 #         ifdef IRIX_THREADS  #         ifdef GC_IRIX_THREADS
                 /* Older versions have a bug related to retrieving and  */                  /* Older versions have a bug related to retrieving and  */
                 /* and setting a handler at the same time.              */                  /* and setting a handler at the same time.              */
                 (void) sigaction(SIGSEGV, 0, &old_segv_act);                  (void) sigaction(SIGSEGV, 0, &old_segv_act);
                 (void) sigaction(SIGSEGV, &act, 0);                  (void) sigaction(SIGSEGV, &act, 0);
 #         else  #         else
                 (void) sigaction(SIGSEGV, &act, &old_segv_act);                  (void) sigaction(SIGSEGV, &act, &old_segv_act);
 #               ifdef _sigargs  /* Irix 5.x, not 6.x */  #               if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
                     /* Under 5.x, we may get SIGBUS.                    */                     || defined(HPUX) || defined(HURD)
                     /* Pthreads doesn't exist under 5.x, so we don't    */                      /* Under Irix 5.x or HP/UX, we may get SIGBUS.      */
                     /* have to worry in the threads case.               */                      /* Pthreads doesn't exist under Irix 5.x, so we     */
                       /* don't have to worry in the threads case.         */
                     (void) sigaction(SIGBUS, &act, &old_bus_act);                      (void) sigaction(SIGBUS, &act, &old_bus_act);
 #               endif  #               endif
 #         endif /* IRIX_THREADS */  #         endif /* GC_IRIX_THREADS */
 #       else  #       else
           old_segv_handler = signal(SIGSEGV, GC_fault_handler);            old_segv_handler = signal(SIGSEGV, h);
 #         ifdef SIGBUS  #         ifdef SIGBUS
             old_bus_handler = signal(SIGBUS, GC_fault_handler);              old_bus_handler = signal(SIGBUS, h);
 #         endif  #         endif
 #       endif  #       endif
     }      }
   # endif /* NEED_FIND_LIMIT || UNIX_LIKE */
   
   # ifdef NEED_FIND_LIMIT
     /* Some tools to implement HEURISTIC2 */
   #   define MIN_PAGE_SIZE 256    /* Smallest conceivable page size, bytes */
       /* static */ jmp_buf GC_jmp_buf;
   
       /*ARGSUSED*/
       void GC_fault_handler(sig)
       int sig;
       {
           longjmp(GC_jmp_buf, 1);
       }
   
       void GC_setup_temporary_fault_handler()
       {
           GC_set_and_save_fault_handler(GC_fault_handler);
       }
   
     void GC_reset_fault_handler()      void GC_reset_fault_handler()
     {      {
 #       if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)  #       if defined(SUNOS5SIGS) || defined(IRIX5) \
              || defined(OSF1) || defined(HURD)
           (void) sigaction(SIGSEGV, &old_segv_act, 0);            (void) sigaction(SIGSEGV, &old_segv_act, 0);
 #         ifdef _sigargs        /* Irix 5.x, not 6.x */  #         if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
                || defined(HPUX) || defined(HURD)
               (void) sigaction(SIGBUS, &old_bus_act, 0);                (void) sigaction(SIGBUS, &old_bus_act, 0);
 #         endif  #         endif
 #       else  #       else
Line 608  ptr_t GC_get_stack_base()
Line 650  ptr_t GC_get_stack_base()
     }      }
 # endif  # endif
   
   #if defined(ECOS) || defined(NOSYS)
     ptr_t GC_get_stack_base()
     {
       return STACKBOTTOM;
     }
   #endif
   
   #ifdef LINUX_STACKBOTTOM
   
   #include <sys/types.h>
   #include <sys/stat.h>
   
   # define STAT_SKIP 27   /* Number of fields preceding startstack        */
                           /* field in /proc/self/stat                     */
   
   # pragma weak __libc_stack_end
     extern ptr_t __libc_stack_end;
   
   # ifdef IA64
   #   pragma weak __libc_ia64_register_backing_store_base
       extern ptr_t __libc_ia64_register_backing_store_base;
   
       ptr_t GC_get_register_stack_base(void)
       {
         if (0 != &__libc_ia64_register_backing_store_base
             && 0 != __libc_ia64_register_backing_store_base) {
           /* Glibc 2.2.4 has a bug such that for dynamically linked       */
           /* executables __libc_ia64_register_backing_store_base is       */
           /* defined but ininitialized during constructor calls.          */
           /* Hence we check for both nonzero address and value.           */
           return __libc_ia64_register_backing_store_base;
         } else {
           word result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
           result += BACKING_STORE_ALIGNMENT - 1;
           result &= ~(BACKING_STORE_ALIGNMENT - 1);
           return (ptr_t)result;
         }
       }
   # endif
   
     ptr_t GC_linux_stack_base(void)
     {
       /* We read the stack base value from /proc/self/stat.  We do this   */
       /* using direct I/O system calls in order to avoid calling malloc   */
       /* in case REDIRECT_MALLOC is defined.                              */
   #   define STAT_BUF_SIZE 4096
   #   if defined(GC_USE_LD_WRAP)
   #       define STAT_READ __real_read
   #   else
   #       define STAT_READ read
   #   endif
       char stat_buf[STAT_BUF_SIZE];
       int f;
       char c;
       word result = 0;
       size_t i, buf_offset = 0;
   
       /* First try the easy way.  This should work for glibc 2.2  */
         if (0 != &__libc_stack_end) {
   #       ifdef IA64
             /* Some versions of glibc set the address 16 bytes too        */
             /* low while the initialization code is running.              */
             if (((word)__libc_stack_end & 0xfff) + 0x10 < 0x1000) {
               return __libc_stack_end + 0x10;
             } /* Otherwise it's not safe to add 16 bytes and we fall      */
               /* back to using /proc.                                     */
   #       else
             return __libc_stack_end;
   #       endif
         }
       f = open("/proc/self/stat", O_RDONLY);
       if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {
           ABORT("Couldn't read /proc/self/stat");
       }
       c = stat_buf[buf_offset++];
       /* Skip the required number of fields.  This number is hopefully    */
       /* constant across all Linux implementations.                       */
         for (i = 0; i < STAT_SKIP; ++i) {
           while (isspace(c)) c = stat_buf[buf_offset++];
           while (!isspace(c)) c = stat_buf[buf_offset++];
         }
       while (isspace(c)) c = stat_buf[buf_offset++];
       while (isdigit(c)) {
         result *= 10;
         result += c - '0';
         c = stat_buf[buf_offset++];
       }
       close(f);
       if (result < 0x10000000) ABORT("Absurd stack bottom value");
       return (ptr_t)result;
     }
   
   #endif /* LINUX_STACKBOTTOM */
   
   #ifdef FREEBSD_STACKBOTTOM
   
   /* This uses an undocumented sysctl call, but at least one expert       */
   /* believes it will stay.                                               */
   
   #include <unistd.h>
   #include <sys/types.h>
   #include <sys/sysctl.h>
   
     ptr_t GC_freebsd_stack_base(void)
     {
       int nm[2] = {CTL_KERN, KERN_USRSTACK};
       ptr_t base;
       size_t len = sizeof(ptr_t);
       int r = sysctl(nm, 2, &base, &len, NULL, 0);
   
       if (r) ABORT("Error getting stack base");
   
       return base;
     }
   
   #endif /* FREEBSD_STACKBOTTOM */
   
   #if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \
       && !defined(MSWINCE) && !defined(OS2)
   
 ptr_t GC_get_stack_base()  ptr_t GC_get_stack_base()
 {  {
     word dummy;      word dummy;
Line 629  ptr_t GC_get_stack_base()
Line 790  ptr_t GC_get_stack_base()
                               & ~STACKBOTTOM_ALIGNMENT_M1);                                & ~STACKBOTTOM_ALIGNMENT_M1);
 #          endif  #          endif
 #       endif /* HEURISTIC1 */  #       endif /* HEURISTIC1 */
   #       ifdef LINUX_STACKBOTTOM
              result = GC_linux_stack_base();
   #       endif
   #       ifdef FREEBSD_STACKBOTTOM
              result = GC_freebsd_stack_base();
   #       endif
 #       ifdef HEURISTIC2  #       ifdef HEURISTIC2
 #           ifdef STACK_GROWS_DOWN  #           ifdef STACK_GROWS_DOWN
                 result = GC_find_limit((ptr_t)(&dummy), TRUE);                  result = GC_find_limit((ptr_t)(&dummy), TRUE);
Line 656  ptr_t GC_get_stack_base()
Line 823  ptr_t GC_get_stack_base()
 #   endif /* STACKBOTTOM */  #   endif /* STACKBOTTOM */
 }  }
   
 # endif /* ! AMIGA */  # endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS */
 # endif /* ! OS2 */  
 # endif /* ! MSWIN32 */  
   
 /*  /*
  * Register static data segment(s) as roots.   * Register static data segment(s) as roots.
Line 758  void GC_register_data_segments()
Line 923  void GC_register_data_segments()
     }      }
 }  }
   
 # else  # else /* !OS2 */
   
   # if defined(MSWIN32) || defined(MSWINCE)
   
 # ifdef MSWIN32  # ifdef MSWIN32
   /* Unfortunately, we have to handle win32s very differently from NT,  */    /* Unfortunately, we have to handle win32s very differently from NT,  */
   /* Since VirtualQuery has very different semantics.  In particular,   */    /* Since VirtualQuery has very different semantics.  In particular,   */
   /* under win32s a VirtualQuery call on an unmapped page returns an    */    /* under win32s a VirtualQuery call on an unmapped page returns an    */
   /* invalid result.  Under GC_register_data_segments is a noop and     */    /* invalid result.  Under NT, GC_register_data_segments is a noop and */
   /* all real work is done by GC_register_dynamic_libraries.  Under     */    /* all real work is done by GC_register_dynamic_libraries.  Under     */
   /* win32s, we cannot find the data segments associated with dll's.    */    /* win32s, we cannot find the data segments associated with dll's.    */
   /* We rgister the main data segment here.                             */    /* We rgister the main data segment here.                             */
   GC_bool GC_win32s = FALSE;    /* We're running under win32s.  */  #  ifdef __GCC__
     GC_bool GC_no_win32_dlls = TRUE;       /* GCC can't do SEH, so we can't use VirtualQuery */
   #  else
     GC_bool GC_no_win32_dlls = FALSE;
   #  endif
   
   GC_bool GC_is_win32s()  
   {  
       DWORD v = GetVersion();  
   
       /* Check that this is not NT, and Windows major version <= 3      */  
       return ((v & 0x80000000) && (v & 0xff) <= 3);  
   }  
   
   void GC_init_win32()    void GC_init_win32()
   {    {
       GC_win32s = GC_is_win32s();      /* if we're running under win32s, assume that no DLLs will be loaded */
       DWORD v = GetVersion();
       GC_no_win32_dlls |= ((v & 0x80000000) && (v & 0xff) <= 3);
   }    }
   
   /* Return the smallest address a such that VirtualQuery               */    /* Return the smallest address a such that VirtualQuery               */
   /* returns correct results for all addresses between a and start.     */    /* returns correct results for all addresses between a and start.     */
   /* Assumes VirtualQuery returns correct information for start.        */    /* Assumes VirtualQuery returns correct information for start.        */
   ptr_t GC_least_described_address(ptr_t start)    ptr_t GC_least_described_address(ptr_t start)
   {    {
     MEMORY_BASIC_INFORMATION buf;      MEMORY_BASIC_INFORMATION buf;
     SYSTEM_INFO sysinfo;  
     DWORD result;      DWORD result;
     LPVOID limit;      LPVOID limit;
     ptr_t p;      ptr_t p;
     LPVOID q;      LPVOID q;
   
     GetSystemInfo(&sysinfo);      limit = GC_sysinfo.lpMinimumApplicationAddress;
     limit = sysinfo.lpMinimumApplicationAddress;  
     p = (ptr_t)((word)start & ~(GC_page_size - 1));      p = (ptr_t)((word)start & ~(GC_page_size - 1));
     for (;;) {      for (;;) {
         q = (LPVOID)(p - GC_page_size);          q = (LPVOID)(p - GC_page_size);
Line 807  void GC_register_data_segments()
Line 970  void GC_register_data_segments()
     }      }
     return(p);      return(p);
   }    }
   # endif
   
   /* Is p the start of either the malloc heap, or of one of our */    /* Is p the start of either the malloc heap, or of one of our */
   /* heap sections?                                             */    /* heap sections?                                             */
Line 820  void GC_register_data_segments()
Line 984  void GC_register_data_segments()
   
        if (0 == malloc_heap_pointer) {         if (0 == malloc_heap_pointer) {
          MEMORY_BASIC_INFORMATION buf;           MEMORY_BASIC_INFORMATION buf;
          register DWORD result = VirtualQuery(malloc(1), &buf, sizeof(buf));           void *pTemp = malloc( 1 );
            register DWORD result = VirtualQuery(pTemp, &buf, sizeof(buf));
   
            free( pTemp );
   
   
          if (result != sizeof(buf)) {           if (result != sizeof(buf)) {
              ABORT("Weird VirtualQuery result");               ABORT("Weird VirtualQuery result");
Line 834  void GC_register_data_segments()
Line 1002  void GC_register_data_segments()
      }       }
      return(FALSE);       return(FALSE);
   }    }
   
   # ifdef MSWIN32
   void GC_register_root_section(ptr_t static_root)    void GC_register_root_section(ptr_t static_root)
   {    {
       MEMORY_BASIC_INFORMATION buf;        MEMORY_BASIC_INFORMATION buf;
       SYSTEM_INFO sysinfo;  
       DWORD result;        DWORD result;
       DWORD protect;        DWORD protect;
       LPVOID p;        LPVOID p;
       char * base;        char * base;
       char * limit, * new_limit;        char * limit, * new_limit;
   
       if (!GC_win32s) return;        if (!GC_no_win32_dlls) return;
       p = base = limit = GC_least_described_address(static_root);        p = base = limit = GC_least_described_address(static_root);
       GetSystemInfo(&sysinfo);        while (p < GC_sysinfo.lpMaximumApplicationAddress) {
       while (p < sysinfo.lpMaximumApplicationAddress) {  
         result = VirtualQuery(p, &buf, sizeof(buf));          result = VirtualQuery(p, &buf, sizeof(buf));
         if (result != sizeof(buf) || buf.AllocationBase == 0          if (result != sizeof(buf) || buf.AllocationBase == 0
             || GC_is_heap_base(buf.AllocationBase)) break;              || GC_is_heap_base(buf.AllocationBase)) break;
Line 869  void GC_register_data_segments()
Line 1036  void GC_register_data_segments()
       }        }
       if (base != limit) GC_add_roots_inner(base, limit, FALSE);        if (base != limit) GC_add_roots_inner(base, limit, FALSE);
   }    }
   #endif
   
   void GC_register_data_segments()    void GC_register_data_segments()
   {    {
   #     ifdef MSWIN32
       static char dummy;        static char dummy;
   
       GC_register_root_section((ptr_t)(&dummy));        GC_register_root_section((ptr_t)(&dummy));
   }  
 # else  
 # ifdef AMIGA  
   
    void GC_register_data_segments()  
    {  
      struct Process     *proc;  
      struct CommandLineInterface *cli;  
      BPTR myseglist;  
      ULONG *data;  
   
      int        num;  
   
   
 #    ifdef __GNUC__  
         ULONG dataSegSize;  
         GC_bool found_segment = FALSE;  
         extern char __data_size[];  
   
         dataSegSize=__data_size+8;  
         /* Can`t find the Location of __data_size, because  
            it`s possible that is it, inside the segment. */  
   
 #     endif  #     endif
   
         proc= (struct Process*)SysBase->ThisTask;  
   
         /* Reference: Amiga Guru Book Pages: 538ff,565,573  
                      and XOper.asm */  
         if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) {  
           if (proc->pr_CLI == NULL) {  
             myseglist = proc->pr_SegList;  
           } else {  
             /* ProcLoaded       'Loaded as a command: '*/  
             cli = BADDR(proc->pr_CLI);  
             myseglist = cli->cli_Module;  
           }  
         } else {  
           ABORT("Not a Process.");  
         }  
   
         if (myseglist == NULL) {  
             ABORT("Arrrgh.. can't find segments, aborting");  
         }  
   
         /* xoper hunks Shell Process */  
   
         num=0;  
         for (data = (ULONG *)BADDR(myseglist); data != NULL;  
              data = (ULONG *)BADDR(data[0])) {  
           if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||  
               ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {  
 #             ifdef __GNUC__  
                 if (dataSegSize == data[-1]) {  
                   found_segment = TRUE;  
                 }  
 #             endif  
               GC_add_roots_inner((char *)&data[1],  
                                  ((char *)&data[1]) + data[-1], FALSE);  
           }  
           ++num;  
         } /* for */  
 #       ifdef __GNUC__  
            if (!found_segment) {  
              ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library");  
            }  
 #       endif  
   }    }
   
 #if 0 /* old version */  # else /* !OS2 && !Windows */
   void GC_register_data_segments()  
   {  
     extern struct WBStartup *_WBenchMsg;  
     struct Process      *proc;  
     struct CommandLineInterface *cli;  
     BPTR myseglist;  
     ULONG *data;  
   
     if ( _WBenchMsg != 0 ) {  # if (defined(SVR4) || defined(AUX) || defined(DGUX) \
         if ((myseglist = _WBenchMsg->sm_Segment) == 0) {        || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
             GC_err_puts("No seglist from workbench\n");  
             return;  
         }  
     } else {  
         if ((proc = (struct Process *)FindTask(0)) == 0) {  
             GC_err_puts("Cannot find process structure\n");  
             return;  
         }  
         if ((cli = BADDR(proc->pr_CLI)) == 0) {  
             GC_err_puts("No CLI\n");  
             return;  
         }  
         if ((myseglist = cli->cli_Module) == 0) {  
             GC_err_puts("No seglist from CLI\n");  
             return;  
         }  
     }  
   
     for (data = (ULONG *)BADDR(myseglist); data != 0;  
          data = (ULONG *)BADDR(data[0])) {  
 #        ifdef AMIGA_SKIP_SEG  
            if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||  
            ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {  
 #        else  
            {  
 #        endif /* AMIGA_SKIP_SEG */  
           GC_add_roots_inner((char *)&data[1],  
                              ((char *)&data[1]) + data[-1], FALSE);  
          }  
     }  
   }  
 #endif /* old version */  
   
   
 # else  
   
 # if (defined(SVR4) || defined(AUX) || defined(DGUX)) && !defined(PCR)  
 char * GC_SysVGetDataStart(max_page_size, etext_addr)  char * GC_SysVGetDataStart(max_page_size, etext_addr)
 int max_page_size;  int max_page_size;
 int * etext_addr;  int * etext_addr;
Line 1025  int * etext_addr;
Line 1083  int * etext_addr;
 # endif  # endif
   
   
   #ifdef AMIGA
   
   #  define GC_AMIGA_DS
   #  include "AmigaOS.c"
   #  undef GC_AMIGA_DS
   
   #else /* !OS2 && !Windows && !AMIGA */
   
 void GC_register_data_segments()  void GC_register_data_segments()
 {  {
 #   if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS) \  #   if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS) \
        && !defined(MACOSX)         && !defined(MACOSX)
 #     if defined(REDIRECT_MALLOC) && defined(SOLARIS_THREADS)  #     if defined(REDIRECT_MALLOC) && defined(GC_SOLARIS_THREADS)
         /* As of Solaris 2.3, the Solaris threads implementation        */          /* As of Solaris 2.3, the Solaris threads implementation        */
         /* allocates the data structure for the initial thread with     */          /* allocates the data structure for the initial thread with     */
         /* sbrk at process startup.  It needs to be scanned, so that    */          /* sbrk at process startup.  It needs to be scanned, so that    */
Line 1040  void GC_register_data_segments()
Line 1106  void GC_register_data_segments()
         GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);          GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);
 #     else  #     else
         GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE);          GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE);
   #       if defined(DATASTART2)
            GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), FALSE);
   #       endif
 #     endif  #     endif
 #   endif  #   endif
 #   if !defined(PCR) && (defined(NEXT) || defined(MACOSX))  #   if !defined(PCR) && (defined(NEXT) || defined(MACOSX))
Line 1084  void GC_register_data_segments()
Line 1153  void GC_register_data_segments()
 }  }
   
 # endif  /* ! AMIGA */  # endif  /* ! AMIGA */
 # endif  /* ! MSWIN32 */  # endif  /* ! MSWIN32 && ! MSWINCE*/
 # endif  /* ! OS2 */  # endif  /* ! OS2 */
   
 /*  /*
  * Auxiliary routines for obtaining memory from OS.   * Auxiliary routines for obtaining memory from OS.
  */   */
   
 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \  # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
         && !defined(MSWIN32) && !defined(MACOS) && !defined(DOS4GW)          && !defined(MSWIN32) && !defined(MSWINCE) \
           && !defined(MACOS) && !defined(DOS4GW)
   
 # ifdef SUNOS4  # ifdef SUNOS4
     extern caddr_t sbrk();      extern caddr_t sbrk();
Line 1103  void GC_register_data_segments()
Line 1173  void GC_register_data_segments()
 #   define SBRK_ARG_T int  #   define SBRK_ARG_T int
 # endif  # endif
   
   
 # ifdef RS6000  # ifdef RS6000
 /* The compiler seems to generate speculative reads one past the end of */  /* The compiler seems to generate speculative reads one past the end of */
 /* an allocated object.  Hence we need to make sure that the page       */  /* an allocated object.  Hence we need to make sure that the page       */
Line 1135  word bytes;
Line 1206  word bytes;
 #else  /* Not RS6000 */  #else  /* Not RS6000 */
   
 #if defined(USE_MMAP)  #if defined(USE_MMAP)
 /* Tested only under IRIX5 and Solaris 2 */  /* Tested only under Linux, IRIX5 and Solaris 2 */
   
 #ifdef USE_MMAP_FIXED  #ifdef USE_MMAP_FIXED
 #   define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE  #   define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
Line 1145  word bytes;
Line 1216  word bytes;
 #   define GC_MMAP_FLAGS MAP_PRIVATE  #   define GC_MMAP_FLAGS MAP_PRIVATE
 #endif  #endif
   
   #ifndef HEAP_START
   #   define HEAP_START 0
   #endif
   
 ptr_t GC_unix_get_mem(bytes)  ptr_t GC_unix_get_mem(bytes)
 word bytes;  word bytes;
 {  {
Line 1163  word bytes;
Line 1238  word bytes;
     if (result == MAP_FAILED) return(0);      if (result == MAP_FAILED) return(0);
     last_addr = (ptr_t)result + bytes + GC_page_size - 1;      last_addr = (ptr_t)result + bytes + GC_page_size - 1;
     last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));      last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
   #   if !defined(LINUX)
         if (last_addr == 0) {
           /* Oops.  We got the end of the address space.  This isn't      */
           /* usable by arbitrary C code, since one-past-end pointers      */
           /* don't work, so we discard it and try again.                  */
           munmap(result, (size_t)(-GC_page_size) - (size_t)result);
                           /* Leave last page mapped, so we can't repeat. */
           return GC_unix_get_mem(bytes);
         }
   #   else
         GC_ASSERT(last_addr != 0);
   #   endif
     return((ptr_t)result);      return((ptr_t)result);
 }  }
   
Line 1216  void * os2_alloc(size_t bytes)
Line 1303  void * os2_alloc(size_t bytes)
 # endif /* OS2 */  # endif /* OS2 */
   
   
   # if defined(MSWIN32) || defined(MSWINCE)
   SYSTEM_INFO GC_sysinfo;
   # endif
   
 # ifdef MSWIN32  # ifdef MSWIN32
   
   # ifdef USE_GLOBAL_ALLOC
   #   define GLOBAL_ALLOC_TEST 1
   # else
   #   define GLOBAL_ALLOC_TEST GC_no_win32_dlls
   # endif
   
 word GC_n_heap_bases = 0;  word GC_n_heap_bases = 0;
   
 ptr_t GC_win32_get_mem(bytes)  ptr_t GC_win32_get_mem(bytes)
 word bytes;  word bytes;
 {  {
     ptr_t result;      ptr_t result;
   
     if (GC_win32s) {      if (GLOBAL_ALLOC_TEST) {
         /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE.    */          /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE.    */
         /* There are also unconfirmed rumors of other           */          /* There are also unconfirmed rumors of other           */
         /* problems, so we dodge the issue.                     */          /* problems, so we dodge the issue.                     */
         result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);          result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);
         result = (ptr_t)(((word)result + HBLKSIZE) & ~(HBLKSIZE-1));          result = (ptr_t)(((word)result + HBLKSIZE) & ~(HBLKSIZE-1));
     } else {      } else {
         result = (ptr_t) VirtualAlloc(NULL, bytes,          /* VirtualProtect only works on regions returned by a   */
           /* single VirtualAlloc call.  Thus we allocate one      */
           /* extra page, which will prevent merging of blocks     */
           /* in separate regions, and eliminate any temptation    */
           /* to call VirtualProtect on a range spanning regions.  */
           /* This wastes a small amount of memory, and risks      */
           /* increased fragmentation.  But better alternatives    */
           /* would require effort.                                */
           result = (ptr_t) VirtualAlloc(NULL, bytes + 1,
                                       MEM_COMMIT | MEM_RESERVE,                                        MEM_COMMIT | MEM_RESERVE,
                                       PAGE_EXECUTE_READWRITE);                                        PAGE_EXECUTE_READWRITE);
     }      }
Line 1245  word bytes;
Line 1351  word bytes;
   
 void GC_win32_free_heap ()  void GC_win32_free_heap ()
 {  {
     if (GC_win32s) {      if (GC_no_win32_dlls) {
         while (GC_n_heap_bases > 0) {          while (GC_n_heap_bases > 0) {
             GlobalFree (GC_heap_bases[--GC_n_heap_bases]);              GlobalFree (GC_heap_bases[--GC_n_heap_bases]);
             GC_heap_bases[GC_n_heap_bases] = 0;              GC_heap_bases[GC_n_heap_bases] = 0;
         }          }
     }      }
 }  }
   # endif
   
   #ifdef AMIGA
   # define GC_AMIGA_AM
   # include "AmigaOS.c"
   # undef GC_AMIGA_AM
   #endif
   
   
   # ifdef MSWINCE
   word GC_n_heap_bases = 0;
   
   ptr_t GC_wince_get_mem(bytes)
   word bytes;
   {
       ptr_t result;
       word i;
   
       /* Round up allocation size to multiple of page size */
       bytes = (bytes + GC_page_size-1) & ~(GC_page_size-1);
   
       /* Try to find reserved, uncommitted pages */
       for (i = 0; i < GC_n_heap_bases; i++) {
           if (((word)(-(signed_word)GC_heap_lengths[i])
                & (GC_sysinfo.dwAllocationGranularity-1))
               >= bytes) {
               result = GC_heap_bases[i] + GC_heap_lengths[i];
               break;
           }
       }
   
       if (i == GC_n_heap_bases) {
           /* Reserve more pages */
           word res_bytes = (bytes + GC_sysinfo.dwAllocationGranularity-1)
                            & ~(GC_sysinfo.dwAllocationGranularity-1);
           /* If we ever support MPROTECT_VDB here, we will probably need to       */
           /* ensure that res_bytes is strictly > bytes, so that VirtualProtect    */
           /* never spans regions.  It seems to be OK for a VirtualFree argument   */
           /* to span regions, so we should be OK for now.                         */
           result = (ptr_t) VirtualAlloc(NULL, res_bytes,
                                         MEM_RESERVE | MEM_TOP_DOWN,
                                         PAGE_EXECUTE_READWRITE);
           if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
               /* If I read the documentation correctly, this can  */
               /* only happen if HBLKSIZE > 64k or not a power of 2.       */
           if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
           GC_heap_bases[GC_n_heap_bases] = result;
           GC_heap_lengths[GC_n_heap_bases] = 0;
           GC_n_heap_bases++;
       }
   
       /* Commit pages */
       result = (ptr_t) VirtualAlloc(result, bytes,
                                     MEM_COMMIT,
                                     PAGE_EXECUTE_READWRITE);
       if (result != NULL) {
           if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
           GC_heap_lengths[i] += bytes;
       }
   
       return(result);
   }
 # endif  # endif
   
 #ifdef USE_MUNMAP  #ifdef USE_MUNMAP
   
 /* For now, this only works on some Unix-like systems.  If you  */  /* For now, this only works on Win32/WinCE and some Unix-like   */
 /* have something else, don't define USE_MUNMAP.                */  /* systems.  If you have something else, don't define           */
   /* USE_MUNMAP.                                                  */
 /* We assume ANSI C to support this feature.                    */  /* We assume ANSI C to support this feature.                    */
   
   #if !defined(MSWIN32) && !defined(MSWINCE)
   
 #include <unistd.h>  #include <unistd.h>
 #include <sys/mman.h>  #include <sys/mman.h>
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <sys/types.h>  #include <sys/types.h>
 #include <fcntl.h>  
   
   #endif
   
 /* Compute a page aligned starting address for the unmap        */  /* Compute a page aligned starting address for the unmap        */
 /* operation on a block of size bytes starting at start.        */  /* operation on a block of size bytes starting at start.        */
 /* Return 0 if the block is too small to make this feasible.    */  /* Return 0 if the block is too small to make this feasible.    */
Line 1289  ptr_t GC_unmap_end(ptr_t start, word bytes)
Line 1460  ptr_t GC_unmap_end(ptr_t start, word bytes)
     return end_addr;      return end_addr;
 }  }
   
   /* Under Win32/WinCE we commit (map) and decommit (unmap)       */
   /* memory using VirtualAlloc and VirtualFree.  These functions  */
   /* work on individual allocations of virtual memory, made       */
   /* previously using VirtualAlloc with the MEM_RESERVE flag.     */
   /* The ranges we need to (de)commit may span several of these   */
   /* allocations; therefore we use VirtualQuery to check          */
   /* allocation lengths, and split up the range as necessary.     */
   
 /* We assume that GC_remap is called on exactly the same range  */  /* We assume that GC_remap is called on exactly the same range  */
 /* as a previous call to GC_unmap.  It is safe to consistently  */  /* as a previous call to GC_unmap.  It is safe to consistently  */
 /* round the endpoints in both places.                          */  /* round the endpoints in both places.                          */
Line 1298  void GC_unmap(ptr_t start, word bytes)
Line 1477  void GC_unmap(ptr_t start, word bytes)
     ptr_t end_addr = GC_unmap_end(start, bytes);      ptr_t end_addr = GC_unmap_end(start, bytes);
     word len = end_addr - start_addr;      word len = end_addr - start_addr;
     if (0 == start_addr) return;      if (0 == start_addr) return;
     if (munmap(start_addr, len) != 0) ABORT("munmap failed");  #   if defined(MSWIN32) || defined(MSWINCE)
     GC_unmapped_bytes += len;        while (len != 0) {
             MEMORY_BASIC_INFORMATION mem_info;
             GC_word free_len;
             if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
                 != sizeof(mem_info))
                 ABORT("Weird VirtualQuery result");
             free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
             if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
                 ABORT("VirtualFree failed");
             GC_unmapped_bytes += free_len;
             start_addr += free_len;
             len -= free_len;
         }
   #   else
         if (munmap(start_addr, len) != 0) ABORT("munmap failed");
         GC_unmapped_bytes += len;
   #   endif
 }  }
   
   
Line 1311  void GC_remap(ptr_t start, word bytes)
Line 1506  void GC_remap(ptr_t start, word bytes)
     word len = end_addr - start_addr;      word len = end_addr - start_addr;
     ptr_t result;      ptr_t result;
   
     if (-1 == zero_descr) zero_descr = open("/dev/zero", O_RDWR);  #   if defined(MSWIN32) || defined(MSWINCE)
     if (0 == start_addr) return;        if (0 == start_addr) return;
     result = mmap(start_addr, len, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,        while (len != 0) {
                   MAP_FIXED | MAP_PRIVATE, zero_descr, 0);            MEMORY_BASIC_INFORMATION mem_info;
     if (result != start_addr) {            GC_word alloc_len;
         ABORT("mmap remapping failed");            if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
     }                != sizeof(mem_info))
     GC_unmapped_bytes -= len;                ABORT("Weird VirtualQuery result");
             alloc_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
             result = VirtualAlloc(start_addr, alloc_len,
                                   MEM_COMMIT,
                                   PAGE_EXECUTE_READWRITE);
             if (result != start_addr) {
                 ABORT("VirtualAlloc remapping failed");
             }
             GC_unmapped_bytes -= alloc_len;
             start_addr += alloc_len;
             len -= alloc_len;
         }
   #   else
         if (-1 == zero_descr) zero_descr = open("/dev/zero", O_RDWR);
         if (0 == start_addr) return;
         result = mmap(start_addr, len, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
                       MAP_FIXED | MAP_PRIVATE, zero_descr, 0);
         if (result != start_addr) {
             ABORT("mmap remapping failed");
         }
         GC_unmapped_bytes -= len;
   #   endif
 }  }
   
 /* Two adjacent blocks have already been unmapped and are about to      */  /* Two adjacent blocks have already been unmapped and are about to      */
Line 1339  void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t sta
Line 1555  void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t sta
     if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2);      if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2);
     if (0 == start_addr) return;      if (0 == start_addr) return;
     len = end_addr - start_addr;      len = end_addr - start_addr;
     if (len != 0 && munmap(start_addr, len) != 0) ABORT("munmap failed");  #   if defined(MSWIN32) || defined(MSWINCE)
     GC_unmapped_bytes += len;        while (len != 0) {
             MEMORY_BASIC_INFORMATION mem_info;
             GC_word free_len;
             if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
                 != sizeof(mem_info))
                 ABORT("Weird VirtualQuery result");
             free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
             if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
                 ABORT("VirtualFree failed");
             GC_unmapped_bytes += free_len;
             start_addr += free_len;
             len -= free_len;
         }
   #   else
         if (len != 0 && munmap(start_addr, len) != 0) ABORT("munmap failed");
         GC_unmapped_bytes += len;
   #   endif
 }  }
   
 #endif /* USE_MUNMAP */  #endif /* USE_MUNMAP */
   
 /* Routine for pushing any additional roots.  In THREADS        */  /* Routine for pushing any additional roots.  In THREADS        */
 /* environment, this is also responsible for marking from       */  /* environment, this is also responsible for marking from       */
 /* thread stacks.  In the SRC_M3 case, it also handles          */  /* thread stacks.                                               */
 /* global variables.                                            */  
 #ifndef THREADS  #ifndef THREADS
 void (*GC_push_other_roots)() = 0;  void (*GC_push_other_roots)() = 0;
 #else /* THREADS */  #else /* THREADS */
Line 1375  PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any
Line 1606  PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any
 }  }
   
   
 void GC_default_push_other_roots()  void GC_default_push_other_roots GC_PROTO((void))
 {  {
     /* Traverse data allocated by previous memory managers.             */      /* Traverse data allocated by previous memory managers.             */
         {          {
Line 1403  void GC_default_push_other_roots()
Line 1634  void GC_default_push_other_roots()
     --> misconfigured      --> misconfigured
 # endif  # endif
   
   void GC_push_thread_structures GC_PROTO((void))
   {
       /* Not our responsibibility. */
   }
   
 extern void ThreadF__ProcessStacks();  extern void ThreadF__ProcessStacks();
   
Line 1420  int dummy3;
Line 1655  int dummy3;
 {  {
     word q = *p;      word q = *p;
   
     if ((ptr_t)(q) >= GC_least_plausible_heap_addr      GC_PUSH_ONE_STACK(q, p);
          && (ptr_t)(q) < GC_greatest_plausible_heap_addr) {  
          GC_push_one_checked(q,FALSE);  
     }  
 }  }
   
 /* M3 set equivalent to RTHeap.TracedRefTypes */  /* M3 set equivalent to RTHeap.TracedRefTypes */
 typedef struct { int elts[1]; }  RefTypeSet;  typedef struct { int elts[1]; }  RefTypeSet;
 RefTypeSet GC_TracedRefTypes = {{0x1}};  RefTypeSet GC_TracedRefTypes = {{0x1}};
   
 /* From finalize.c */  void GC_default_push_other_roots GC_PROTO((void))
 extern void GC_push_finalizer_structures();  
   
 /* From stubborn.c: */  
 # ifdef STUBBORN_ALLOC  
     extern GC_PTR * GC_changing_list_start;  
 # endif  
   
   
 void GC_default_push_other_roots()  
 {  {
     /* Use the M3 provided routine for finding static roots.    */      /* Use the M3 provided routine for finding static roots.     */
     /* This is a bit dubious, since it presumes no C roots.     */      /* This is a bit dubious, since it presumes no C roots.      */
     /* We handle the collector roots explicitly.                */      /* We handle the collector roots explicitly in GC_push_roots */
        {          RTMain__GlobalMapProc(GC_m3_push_root, 0, GC_TracedRefTypes);
 #        ifdef STUBBORN_ALLOC  
            GC_push_one(GC_changing_list_start);  
 #        endif  
          GC_push_finalizer_structures();  
          RTMain__GlobalMapProc(GC_m3_push_root, 0, GC_TracedRefTypes);  
        }  
         if (GC_words_allocd > 0) {          if (GC_words_allocd > 0) {
             ThreadF__ProcessStacks(GC_push_thread_stack);              ThreadF__ProcessStacks(GC_push_thread_stack);
         }          }
Line 1460  void GC_default_push_other_roots()
Line 1677  void GC_default_push_other_roots()
   
 # endif /* SRC_M3 */  # endif /* SRC_M3 */
   
 # if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \  # if defined(GC_SOLARIS_THREADS) || defined(GC_PTHREADS) || \
      || defined(IRIX_THREADS) || defined(LINUX_THREADS) \       defined(GC_WIN32_THREADS)
      || defined(IRIX_PCR_THREADS)  
   
 extern void GC_push_all_stacks();  extern void GC_push_all_stacks();
   
 void GC_default_push_other_roots()  void GC_default_push_other_roots GC_PROTO((void))
 {  {
     GC_push_all_stacks();      GC_push_all_stacks();
 }  }
   
 # endif /* SOLARIS_THREADS || ... */  # endif /* GC_SOLARIS_THREADS || GC_PTHREADS */
   
 void (*GC_push_other_roots)() = GC_default_push_other_roots;  void (*GC_push_other_roots) GC_PROTO((void)) = GC_default_push_other_roots;
   
 #endif  #endif /* THREADS */
   
 /*  /*
  * Routines for accessing dirty  bits on virtual pages.   * Routines for accessing dirty  bits on virtual pages.
  * We plan to eventaually implement four strategies for doing so:   * We plan to eventually implement four strategies for doing so:
  * DEFAULT_VDB: A simple dummy implementation that treats every page   * DEFAULT_VDB: A simple dummy implementation that treats every page
  *              as possibly dirty.  This makes incremental collection   *              as possibly dirty.  This makes incremental collection
  *              useless, but the implementation is still correct.   *              useless, but the implementation is still correct.
Line 1552  word n;
Line 1768  word n;
 {  {
 }  }
   
 /* A call hints that h is about to be written.  */  /* A call that:                                         */
 /* May speed up some dirty bit implementations. */  /* I) hints that [h, h+nblocks) is about to be written. */
   /* II) guarantees that protection is removed.           */
   /* (I) may speed up some dirty bit implementations.     */
   /* (II) may be essential if we need to ensure that      */
   /* pointer-free system call buffers in the heap are     */
   /* not protected.                                       */
 /*ARGSUSED*/  /*ARGSUSED*/
 void GC_write_hint(h)  void GC_remove_protection(h, nblocks, is_ptrfree)
 struct hblk *h;  struct hblk *h;
   word nblocks;
   GC_bool is_ptrfree;
 {  {
 }  }
   
Line 1572  struct hblk *h;
Line 1795  struct hblk *h;
 /*  /*
  * This implementation maintains dirty bits itself by catching write   * This implementation maintains dirty bits itself by catching write
  * faults and keeping track of them.  We assume nobody else catches   * faults and keeping track of them.  We assume nobody else catches
  * SIGBUS or SIGSEGV.  We assume no write faults occur in system calls   * SIGBUS or SIGSEGV.  We assume no write faults occur in system calls.
  * except as a result of a read system call.  This means clients must   * This means that clients must ensure that system calls don't write
  * either ensure that system calls do not touch the heap, or must   * to the write-protected heap.  Probably the best way to do this is to
  * provide their own wrappers analogous to the one for read.   * ensure that system calls write at most to POINTERFREE objects in the
    * heap, and do even that only if we are on a platform on which those
    * are not protected.  Another alternative is to wrap system calls
    * (see example for read below), but the current implementation holds
    * a lock across blocking calls, making it problematic for multithreaded
    * applications.
  * We assume the page size is a multiple of HBLKSIZE.   * We assume the page size is a multiple of HBLKSIZE.
  * This implementation is currently SunOS 4.X and IRIX 5.X specific, though we   * We prefer them to be the same.  We avoid protecting POINTERFREE
  * tried to use portable code where easily possible.  It is known   * objects only if they are the same.
  * not to work under a number of other systems.  
  */   */
   
 # ifndef MSWIN32  # if !defined(MSWIN32) && !defined(MSWINCE)
   
 #   include <sys/mman.h>  #   include <sys/mman.h>
 #   include <signal.h>  #   include <signal.h>
 #   include <sys/syscall.h>  #   include <sys/syscall.h>
   
 #   define PROTECT(addr, len) \  #   define PROTECT(addr, len) \
           if (mprotect((caddr_t)(addr), (int)(len), \            if (mprotect((caddr_t)(addr), (size_t)(len), \
                        PROT_READ | OPT_PROT_EXEC) < 0) { \                         PROT_READ | OPT_PROT_EXEC) < 0) { \
             ABORT("mprotect failed"); \              ABORT("mprotect failed"); \
           }            }
 #   define UNPROTECT(addr, len) \  #   define UNPROTECT(addr, len) \
           if (mprotect((caddr_t)(addr), (int)(len), \            if (mprotect((caddr_t)(addr), (size_t)(len), \
                        PROT_WRITE | PROT_READ | OPT_PROT_EXEC ) < 0) { \                         PROT_WRITE | PROT_READ | OPT_PROT_EXEC ) < 0) { \
             ABORT("un-mprotect failed"); \              ABORT("un-mprotect failed"); \
           }            }
   
 # else  # else
   
 #   include <signal.h>  #   ifndef MSWINCE
   #     include <signal.h>
   #   endif
   
     static DWORD protect_junk;      static DWORD protect_junk;
 #   define PROTECT(addr, len) \  #   define PROTECT(addr, len) \
Line 1622  struct hblk *h;
Line 1851  struct hblk *h;
 #if defined(SUNOS4) || defined(FREEBSD)  #if defined(SUNOS4) || defined(FREEBSD)
     typedef void (* SIG_PF)();      typedef void (* SIG_PF)();
 #endif  #endif
 #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX)  #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
       || defined(MACOSX) || defined(HURD)
   # ifdef __STDC__
     typedef void (* SIG_PF)(int);      typedef void (* SIG_PF)(int);
   # else
       typedef void (* SIG_PF)();
   # endif
 #endif  #endif
 #if defined(MSWIN32)  #if defined(MSWIN32)
     typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;      typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
 #   undef SIG_DFL  #   undef SIG_DFL
 #   define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER) (-1)  #   define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER) (-1)
 #endif  #endif
   #if defined(MSWINCE)
       typedef LONG (WINAPI *SIG_PF)(struct _EXCEPTION_POINTERS *);
   #   undef SIG_DFL
   #   define SIG_DFL (SIG_PF) (-1)
   #endif
   
 #if defined(IRIX5) || defined(OSF1)  #if defined(IRIX5) || defined(OSF1) || defined(HURD)
     typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);      typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
 #endif  #endif
 #if defined(SUNOS5SIGS)  #if defined(SUNOS5SIGS)
     typedef void (* REAL_SIG_PF)(int, struct siginfo *, void *);  # ifdef HPUX
   #   define SIGINFO __siginfo
   # else
   #   define SIGINFO siginfo
   # endif
   # ifdef __STDC__
       typedef void (* REAL_SIG_PF)(int, struct SIGINFO *, void *);
   # else
       typedef void (* REAL_SIG_PF)();
   # endif
 #endif  #endif
 #if defined(LINUX)  #if defined(LINUX)
 #   include <linux/version.h>  #   if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
 #   if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA)  
       typedef struct sigcontext s_c;        typedef struct sigcontext s_c;
   #   else  /* glibc < 2.2 */
   #     include <linux/version.h>
   #     if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA) || defined(ARM32)
           typedef struct sigcontext s_c;
   #     else
           typedef struct sigcontext_struct s_c;
   #     endif
   #   endif  /* glibc < 2.2 */
   #   if defined(ALPHA) || defined(M68K)
         typedef void (* REAL_SIG_PF)(int, int, s_c *);
 #   else  #   else
       typedef struct sigcontext_struct s_c;  #     if defined(IA64) || defined(HP_PA)
           typedef void (* REAL_SIG_PF)(int, siginfo_t *, s_c *);
   #     else
           typedef void (* REAL_SIG_PF)(int, s_c);
   #     endif
 #   endif  #   endif
 #   ifdef ALPHA  #   ifdef ALPHA
     typedef void (* REAL_SIG_PF)(int, int, s_c *);  
     /* Retrieve fault address from sigcontext structure by decoding     */      /* Retrieve fault address from sigcontext structure by decoding     */
     /* instruction.                                                     */      /* instruction.                                                     */
     char * get_fault_addr(s_c *sc) {      char * get_fault_addr(s_c *sc) {
Line 1657  struct hblk *h;
Line 1917  struct hblk *h;
         faultaddr += (word) (((int)instr << 16) >> 16);          faultaddr += (word) (((int)instr << 16) >> 16);
         return (char *)faultaddr;          return (char *)faultaddr;
     }      }
 #   else /* !ALPHA */  
     typedef void (* REAL_SIG_PF)(int, s_c);  
 #   endif /* !ALPHA */  #   endif /* !ALPHA */
 # endif  # endif
   
   # if defined(MACOSX) /* Should also test for PowerPC? */
       typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
   
   /* Decodes the machine instruction which was responsible for the sending of the
      SIGBUS signal. Sadly this is the only way to find the faulting address because
      the signal handler doesn't get it directly from the kernel (although it is
      available on the Mach level, but droppped by the BSD personality before it
      calls our signal handler...)
      This code should be able to deal correctly with all PPCs starting from the
      601 up to and including the G4s (including Velocity Engine). */
   #define EXTRACT_OP1(iw)     (((iw) & 0xFC000000) >> 26)
   #define EXTRACT_OP2(iw)     (((iw) & 0x000007FE) >> 1)
   #define EXTRACT_REGA(iw)    (((iw) & 0x001F0000) >> 16)
   #define EXTRACT_REGB(iw)    (((iw) & 0x03E00000) >> 21)
   #define EXTRACT_REGC(iw)    (((iw) & 0x0000F800) >> 11)
   #define EXTRACT_DISP(iw)    ((short *) &(iw))[1]
   
   static char *get_fault_addr(struct sigcontext *scp)
   {
      unsigned int   instr = *((unsigned int *) scp->sc_ir);
      unsigned int * regs = &((unsigned int *) scp->sc_regs)[2];
      int            disp = 0, tmp;
      unsigned int   baseA = 0, baseB = 0;
      unsigned int   addr, alignmask = 0xFFFFFFFF;
   
   #ifdef GC_DEBUG_DECODER
      GC_err_printf1("Instruction: 0x%lx\n", instr);
      GC_err_printf1("Opcode 1: d\n", (int)EXTRACT_OP1(instr));
   #endif
      switch(EXTRACT_OP1(instr)) {
         case 38:   /* stb */
         case 39:   /* stbu */
         case 54:   /* stfd */
         case 55:   /* stfdu */
         case 52:   /* stfs */
         case 53:   /* stfsu */
         case 44:   /* sth */
         case 45:   /* sthu */
         case 47:   /* stmw */
         case 36:   /* stw */
         case 37:   /* stwu */
               tmp = EXTRACT_REGA(instr);
               if(tmp > 0)
                  baseA = regs[tmp];
               disp = EXTRACT_DISP(instr);
               break;
         case 31:
   #ifdef GC_DEBUG_DECODER
               GC_err_printf1("Opcode 2: %d\n", (int)EXTRACT_OP2(instr));
   #endif
               switch(EXTRACT_OP2(instr)) {
                  case 86:    /* dcbf */
                  case 54:    /* dcbst */
                  case 1014:  /* dcbz */
                  case 247:   /* stbux */
                  case 215:   /* stbx */
                  case 759:   /* stfdux */
                  case 727:   /* stfdx */
                  case 983:   /* stfiwx */
                  case 695:   /* stfsux */
                  case 663:   /* stfsx */
                  case 918:   /* sthbrx */
                  case 439:   /* sthux */
                  case 407:   /* sthx */
                  case 661:   /* stswx */
                  case 662:   /* stwbrx */
                  case 150:   /* stwcx. */
                  case 183:   /* stwux */
                  case 151:   /* stwx */
                  case 135:   /* stvebx */
                  case 167:   /* stvehx */
                  case 199:   /* stvewx */
                  case 231:   /* stvx */
                  case 487:   /* stvxl */
                        tmp = EXTRACT_REGA(instr);
                        if(tmp > 0)
                           baseA = regs[tmp];
                           baseB = regs[EXTRACT_REGC(instr)];
                           /* determine Altivec alignment mask */
                           switch(EXTRACT_OP2(instr)) {
                              case 167:   /* stvehx */
                                    alignmask = 0xFFFFFFFE;
                                    break;
                              case 199:   /* stvewx */
                                    alignmask = 0xFFFFFFFC;
                                    break;
                              case 231:   /* stvx */
                                    alignmask = 0xFFFFFFF0;
                                    break;
                              case 487:  /* stvxl */
                                    alignmask = 0xFFFFFFF0;
                                    break;
                           }
                           break;
                  case 725:   /* stswi */
                        tmp = EXTRACT_REGA(instr);
                        if(tmp > 0)
                           baseA = regs[tmp];
                           break;
                  default:   /* ignore instruction */
   #ifdef GC_DEBUG_DECODER
                        GC_err_printf("Ignored by inner handler\n");
   #endif
                        return NULL;
                       break;
               }
               break;
         default:   /* ignore instruction */
   #ifdef GC_DEBUG_DECODER
               GC_err_printf("Ignored by main handler\n");
   #endif
               return NULL;
               break;
      }
   
      addr = (baseA + baseB) + disp;
     addr &= alignmask;
   #ifdef GC_DEBUG_DECODER
      GC_err_printf1("BaseA: %d\n", baseA);
      GC_err_printf1("BaseB: %d\n", baseB);
      GC_err_printf1("Disp:  %d\n", disp);
      GC_err_printf1("Address: %d\n", addr);
   #endif
      return (char *)addr;
   }
   #endif /* MACOSX */
   
 SIG_PF GC_old_bus_handler;  SIG_PF GC_old_bus_handler;
 SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */  SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */
   
   #ifdef THREADS
   /* We need to lock around the bitmap update in the write fault handler  */
   /* in order to avoid the risk of losing a bit.  We do this with a       */
   /* test-and-set spin lock if we know how to do that.  Otherwise we      */
   /* check whether we are already in the handler and use the dumb but     */
   /* safe fallback algorithm of setting all bits in the word.             */
   /* Contention should be very rare, so we do the minimum to handle it    */
   /* correctly.                                                           */
   #ifdef GC_TEST_AND_SET_DEFINED
     static VOLATILE unsigned int fault_handler_lock = 0;
     void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
       while (GC_test_and_set(&fault_handler_lock)) {}
       /* Could also revert to set_pht_entry_from_index_safe if initial    */
       /* GC_test_and_set fails.                                           */
       set_pht_entry_from_index(db, index);
       GC_clear(&fault_handler_lock);
     }
   #else /* !GC_TEST_AND_SET_DEFINED */
     /* THIS IS INCORRECT! The dirty bit vector may be temporarily wrong,  */
     /* just before we notice the conflict and correct it. We may end up   */
     /* looking at it while it's wrong.  But this requires contention      */
     /* exactly when a GC is triggered, which seems far less likely to     */
     /* fail than the old code, which had no reported failures.  Thus we   */
     /* leave it this way while we think of something better, or support   */
     /* GC_test_and_set on the remaining platforms.                        */
     static VOLATILE word currently_updating = 0;
     void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
       unsigned int update_dummy;
       currently_updating = (word)(&update_dummy);
       set_pht_entry_from_index(db, index);
       /* If we get contention in the 10 or so instruction window here,    */
       /* and we get stopped by a GC between the two updates, we lose!     */
       if (currently_updating != (word)(&update_dummy)) {
           set_pht_entry_from_index_safe(db, index);
           /* We claim that if two threads concurrently try to update the  */
           /* dirty bit vector, the first one to execute UPDATE_START      */
           /* will see it changed when UPDATE_END is executed.  (Note that */
           /* &update_dummy must differ in two distinct threads.)  It      */
           /* will then execute set_pht_entry_from_index_safe, thus        */
           /* returning us to a safe state, though not soon enough.        */
       }
     }
   #endif /* !GC_TEST_AND_SET_DEFINED */
   #else /* !THREADS */
   # define async_set_pht_entry_from_index(db, index) \
           set_pht_entry_from_index(db, index)
   #endif /* !THREADS */
   
 /*ARGSUSED*/  /*ARGSUSED*/
 # if defined (SUNOS4) || defined(FREEBSD)  # if defined (SUNOS4) || defined(FREEBSD)
     void GC_write_fault_handler(sig, code, scp, addr)      void GC_write_fault_handler(sig, code, scp, addr)
Line 1682  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2115  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #     define CODE_OK (code == BUS_PAGE_FAULT)  #     define CODE_OK (code == BUS_PAGE_FAULT)
 #   endif  #   endif
 # endif  # endif
 # if defined(IRIX5) || defined(OSF1)  # if defined(IRIX5) || defined(OSF1) || defined(HURD)
 #   include <errno.h>  #   include <errno.h>
     void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)      void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
 #   define SIG_OK (sig == SIGSEGV)  
 #   ifdef OSF1  #   ifdef OSF1
   #     define SIG_OK (sig == SIGSEGV)
 #     define CODE_OK (code == 2 /* experimentally determined */)  #     define CODE_OK (code == 2 /* experimentally determined */)
 #   endif  #   endif
 #   ifdef IRIX5  #   ifdef IRIX5
   #     define SIG_OK (sig == SIGSEGV)
 #     define CODE_OK (code == EACCES)  #     define CODE_OK (code == EACCES)
 #   endif  #   endif
   #   ifdef HURD
   #     define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
   #     define CODE_OK  TRUE
   #   endif
 # endif  # endif
 # if defined(LINUX)  # if defined(LINUX)
 #   ifdef ALPHA  #   if defined(ALPHA) || defined(M68K)
       void GC_write_fault_handler(int sig, int code, s_c * sc)        void GC_write_fault_handler(int sig, int code, s_c * sc)
 #   else  #   else
       void GC_write_fault_handler(int sig, s_c sc)  #     if defined(IA64) || defined(HP_PA)
           void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp)
   #     else
   #       if defined(ARM32)
             void GC_write_fault_handler(int sig, int a2, int a3, int a4, s_c sc)
   #       else
             void GC_write_fault_handler(int sig, s_c sc)
   #       endif
   #     endif
 #   endif  #   endif
 #   define SIG_OK (sig == SIGSEGV)  #   define SIG_OK (sig == SIGSEGV)
 #   define CODE_OK TRUE  #   define CODE_OK TRUE
         /* Empirically c.trapno == 14, but is that useful?      */          /* Empirically c.trapno == 14, on IA32, but is that useful?     */
         /* We assume Intel architecture, so alignment           */          /* Should probably consider alignment issues on other           */
         /* faults are not possible.                             */          /* architectures.                                               */
 # endif  # endif
 # if defined(SUNOS5SIGS)  # if defined(SUNOS5SIGS)
     void GC_write_fault_handler(int sig, struct siginfo *scp, void * context)  #  ifdef __STDC__
 #   define SIG_OK (sig == SIGSEGV)      void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context)
 #   define CODE_OK (scp -> si_code == SEGV_ACCERR)  #  else
       void GC_write_fault_handler(sig, scp, context)
       int sig;
       struct SIGINFO *scp;
       void * context;
   #  endif
   #   ifdef HPUX
   #     define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
   #     define CODE_OK (scp -> si_code == SEGV_ACCERR) \
                        || (scp -> si_code == BUS_ADRERR) \
                        || (scp -> si_code == BUS_UNKNOWN) \
                        || (scp -> si_code == SEGV_UNKNOWN) \
                        || (scp -> si_code == BUS_OBJERR)
   #   else
   #     define SIG_OK (sig == SIGSEGV)
   #     define CODE_OK (scp -> si_code == SEGV_ACCERR)
   #   endif
 # endif  # endif
 # if defined(MSWIN32)  
   # if defined(MACOSX)
       void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
   #   define SIG_OK (sig == SIGBUS)
   #   define CODE_OK (code == 0 /* experimentally determined */)
   # endif
   
   # if defined(MSWIN32) || defined(MSWINCE)
     LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)      LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
 #   define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \  #   define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \
                         EXCEPTION_ACCESS_VIOLATION)                          STATUS_ACCESS_VIOLATION)
 #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)  #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
                         /* Write fault */                          /* Write fault */
 # endif  # endif
 {  {
     register unsigned i;      register unsigned i;
   #   if defined(HURD)
           char *addr = (char *) code;
   #   endif
 #   ifdef IRIX5  #   ifdef IRIX5
         char * addr = (char *) (size_t) (scp -> sc_badvaddr);          char * addr = (char *) (size_t) (scp -> sc_badvaddr);
 #   endif  #   endif
Line 1735  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2207  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #       if defined(M68K)  #       if defined(M68K)
           char * addr = NULL;            char * addr = NULL;
   
           struct sigcontext *scp = (struct sigcontext *)(&sc);            struct sigcontext *scp = (struct sigcontext *)(sc);
   
           int format = (scp->sc_formatvec >> 12) & 0xf;            int format = (scp->sc_formatvec >> 12) & 0xf;
           unsigned long *framedata = (unsigned long *)(scp + 1);            unsigned long *framedata = (unsigned long *)(scp + 1);
Line 1747  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2219  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
           } else if (format == 7) {            } else if (format == 7) {
                 /* 68040 */                  /* 68040 */
                 ea = framedata[3];                  ea = framedata[3];
                   if (framedata[1] & 0x08000000) {
                           /* correct addr on misaligned access */
                           ea = (ea+4095)&(~4095);
                   }
           } else if (format == 4) {            } else if (format == 4) {
                 /* 68060 */                  /* 68060 */
                 ea = framedata[0];                  ea = framedata[0];
Line 1760  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2236  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #         ifdef ALPHA  #         ifdef ALPHA
             char * addr = get_fault_addr(sc);              char * addr = get_fault_addr(sc);
 #         else  #         else
                 --> architecture not supported  #           if defined(IA64) || defined(HP_PA)
                 char * addr = si -> si_addr;
                 /* I believe this is claimed to work on all platforms for */
                 /* Linux 2.3.47 and later.  Hopefully we don't have to    */
                 /* worry about earlier kernels on IA64.                   */
   #           else
   #             if defined(POWERPC)
                   char * addr = (char *) (sc.regs->dar);
   #             else
   #               if defined(ARM32)
                     char * addr = (char *)sc.fault_address;
   #               else
                     --> architecture not supported
   #               endif
   #             endif
   #           endif
 #         endif  #         endif
 #       endif  #       endif
 #     endif  #     endif
 #   endif  #   endif
 #   if defined(MSWIN32)  #   if defined(MACOSX)
           char * addr = get_fault_addr(scp);
   #   endif
   #   if defined(MSWIN32) || defined(MSWINCE)
         char * addr = (char *) (exc_info -> ExceptionRecord          char * addr = (char *) (exc_info -> ExceptionRecord
                                 -> ExceptionInformation[1]);                                  -> ExceptionInformation[1]);
 #       define sig SIGSEGV  #       define sig SIGSEGV
Line 1797  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2291  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
                 old_handler = GC_old_bus_handler;                  old_handler = GC_old_bus_handler;
             }              }
             if (old_handler == SIG_DFL) {              if (old_handler == SIG_DFL) {
 #               ifndef MSWIN32  #               if !defined(MSWIN32) && !defined(MSWINCE)
                     GC_err_printf1("Segfault at 0x%lx\n", addr);                      GC_err_printf1("Segfault at 0x%lx\n", addr);
                     ABORT("Unexpected bus error or segmentation fault");                      ABORT("Unexpected bus error or segmentation fault");
 #               else  #               else
Line 1813  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2307  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
                     return;                      return;
 #               endif  #               endif
 #               if defined (LINUX)  #               if defined (LINUX)
 #                   ifdef ALPHA  #                   if defined(ALPHA) || defined(M68K)
                         (*(REAL_SIG_PF)old_handler) (sig, code, sc);                          (*(REAL_SIG_PF)old_handler) (sig, code, sc);
 #                   else  #                   else
   #                     if defined(IA64) || defined(HP_PA)
                           (*(REAL_SIG_PF)old_handler) (sig, si, scp);
   #                     else
                         (*(REAL_SIG_PF)old_handler) (sig, sc);                          (*(REAL_SIG_PF)old_handler) (sig, sc);
   #                     endif
 #                   endif  #                   endif
                     return;                      return;
 #               endif  #               endif
 #               if defined (IRIX5) || defined(OSF1)  #               if defined (IRIX5) || defined(OSF1) || defined(HURD)
                     (*(REAL_SIG_PF)old_handler) (sig, code, scp);                      (*(REAL_SIG_PF)old_handler) (sig, code, scp);
                     return;                      return;
 #               endif  #               endif
   #               ifdef MACOSX
                       (*(REAL_SIG_PF)old_handler) (sig, code, scp);
   #               endif
 #               ifdef MSWIN32  #               ifdef MSWIN32
                     return((*old_handler)(exc_info));                      return((*old_handler)(exc_info));
 #               endif  #               endif
             }              }
         }          }
           UNPROTECT(h, GC_page_size);
           /* We need to make sure that no collection occurs between       */
           /* the UNPROTECT and the setting of the dirty bit.  Otherwise   */
           /* a write by a third thread might go unnoticed.  Reversing     */
           /* the order is just as bad, since we would end up unprotecting */
           /* a page in a GC cycle during which it's not marked.           */
           /* Currently we do this by disabling the thread stopping        */
           /* signals while this handler is running.  An alternative might */
           /* be to record the fact that we're about to unprotect, or      */
           /* have just unprotected a page in the GC's thread structure,   */
           /* and then to have the thread stopping code set the dirty      */
           /* flag, if necessary.                                          */
         for (i = 0; i < divHBLKSZ(GC_page_size); i++) {          for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
             register int index = PHT_HASH(h+i);              register int index = PHT_HASH(h+i);
   
             set_pht_entry_from_index(GC_dirty_pages, index);              async_set_pht_entry_from_index(GC_dirty_pages, index);
         }          }
         UNPROTECT(h, GC_page_size);  #       if defined(OSF1)
 #       if defined(OSF1) || defined(LINUX)  
             /* These reset the signal handler each time by default. */              /* These reset the signal handler each time by default. */
             signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);              signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);
 #       endif  #       endif
         /* The write may not take place before dirty bits are read.     */          /* The write may not take place before dirty bits are read.     */
         /* But then we'll fault again ...                               */          /* But then we'll fault again ...                               */
 #       ifdef MSWIN32  #       if defined(MSWIN32) || defined(MSWINCE)
             return(EXCEPTION_CONTINUE_EXECUTION);              return(EXCEPTION_CONTINUE_EXECUTION);
 #       else  #       else
             return;              return;
 #       endif  #       endif
     }      }
 #ifdef MSWIN32  #if defined(MSWIN32) || defined(MSWINCE)
     return EXCEPTION_CONTINUE_SEARCH;      return EXCEPTION_CONTINUE_SEARCH;
 #else  #else
     GC_err_printf1("Segfault at 0x%lx\n", addr);      GC_err_printf1("Segfault at 0x%lx\n", addr);
Line 1857  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2369  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
   
 /*  /*
  * We hold the allocation lock.  We expect block h to be written   * We hold the allocation lock.  We expect block h to be written
  * shortly.   * shortly.  Ensure that all pages containing any part of the n hblks
    * starting at h are no longer protected.  If is_ptrfree is false,
    * also ensure that they will subsequently appear to be dirty.
  */   */
 void GC_write_hint(h)  void GC_remove_protection(h, nblocks, is_ptrfree)
 struct hblk *h;  struct hblk *h;
   word nblocks;
   GC_bool is_ptrfree;
 {  {
     register struct hblk * h_trunc;      struct hblk * h_trunc;  /* Truncated to page boundary */
     register unsigned i;      struct hblk * h_end;    /* Page boundary following block end */
     register GC_bool found_clean;      struct hblk * current;
       GC_bool found_clean;
   
     if (!GC_dirty_maintained) return;      if (!GC_dirty_maintained) return;
     h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));      h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));
       h_end = (struct hblk *)(((word)(h + nblocks) + GC_page_size-1)
                               & ~(GC_page_size-1));
     found_clean = FALSE;      found_clean = FALSE;
     for (i = 0; i < divHBLKSZ(GC_page_size); i++) {      for (current = h_trunc; current < h_end; ++current) {
         register int index = PHT_HASH(h_trunc+i);          int index = PHT_HASH(current);
   
         if (!get_pht_entry_from_index(GC_dirty_pages, index)) {          if (!is_ptrfree || current < h || current >= h + nblocks) {
             found_clean = TRUE;              async_set_pht_entry_from_index(GC_dirty_pages, index);
             set_pht_entry_from_index(GC_dirty_pages, index);  
         }          }
     }      }
     if (found_clean) {      UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);
         UNPROTECT(h_trunc, GC_page_size);  
     }  
 }  }
   
 void GC_dirty_init()  void GC_dirty_init()
 {  {
 #if defined(SUNOS5SIGS) || defined(IRIX5) /* || defined(OSF1) */  #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
     struct sigaction    act, oldact;         defined(OSF1) || defined(HURD)
 #   ifdef IRIX5        struct sigaction  act, oldact;
         /* We should probably specify SA_SIGINFO for Linux, and handle    */
         /* the different architectures more uniformly.                    */
   #     if defined(IRIX5) || defined(LINUX) || defined(OSF1) || defined(HURD)
         act.sa_flags    = SA_RESTART;          act.sa_flags    = SA_RESTART;
         act.sa_handler  = GC_write_fault_handler;          act.sa_handler  = (SIG_PF)GC_write_fault_handler;
 #   else  #     else
         act.sa_flags    = SA_RESTART | SA_SIGINFO;          act.sa_flags    = SA_RESTART | SA_SIGINFO;
         act.sa_sigaction = GC_write_fault_handler;          act.sa_sigaction = GC_write_fault_handler;
   #     endif
         (void)sigemptyset(&act.sa_mask);
   #     ifdef SIG_SUSPEND
           /* Arrange to postpone SIG_SUSPEND while we're in a write fault */
           /* handler.  This effectively makes the handler atomic w.r.t.   */
           /* stopping the world for GC.                                   */
           (void)sigaddset(&act.sa_mask, SIG_SUSPEND);
   #     endif /* SIG_SUSPEND */
   #    endif
   #   if defined(MACOSX)
         struct sigaction act, oldact;
   
         act.sa_flags = SA_RESTART;
         act.sa_handler = GC_write_fault_handler;
         sigemptyset(&act.sa_mask);
 #   endif  #   endif
     (void)sigemptyset(&act.sa_mask);  
 #endif  
 #   ifdef PRINTSTATS  #   ifdef PRINTSTATS
         GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");          GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
 #   endif  #   endif
Line 1915  void GC_dirty_init()
Line 2447  void GC_dirty_init()
 #       endif  #       endif
       }        }
 #   endif  #   endif
 #   if defined(OSF1) || defined(SUNOS4) || defined(LINUX)  #   if defined(SUNOS4)
       GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler);        GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler);
       if (GC_old_segv_handler == SIG_IGN) {        if (GC_old_segv_handler == SIG_IGN) {
         GC_err_printf0("Previously ignored segmentation violation!?");          GC_err_printf0("Previously ignored segmentation violation!?");
Line 1927  void GC_dirty_init()
Line 2459  void GC_dirty_init()
 #       endif  #       endif
       }        }
 #   endif  #   endif
 #   if defined(SUNOS5SIGS) || defined(IRIX5)  #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) \
 #     if defined(IRIX_THREADS) || defined(IRIX_PCR_THREADS)         || defined(OSF1) || defined(HURD)
         /* SUNOS5SIGS includes HPUX */
   #     if defined(GC_IRIX_THREADS)
         sigaction(SIGSEGV, 0, &oldact);          sigaction(SIGSEGV, 0, &oldact);
         sigaction(SIGSEGV, &act, 0);          sigaction(SIGSEGV, &act, 0);
 #     else  #     else
         sigaction(SIGSEGV, &act, &oldact);          sigaction(SIGSEGV, &act, &oldact);
 #     endif  #     endif
 #     if defined(_sigargs)  #     if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
         /* This is Irix 5.x, not 6.x.  Irix 5.x does not have   */          /* This is Irix 5.x, not 6.x.  Irix 5.x does not have   */
         /* sa_sigaction.                                        */          /* sa_sigaction.                                        */
         GC_old_segv_handler = oldact.sa_handler;          GC_old_segv_handler = oldact.sa_handler;
 #     else /* Irix 6.x or SUNOS5SIGS */  #     else /* Irix 6.x or SUNOS5SIGS or LINUX */
         if (oldact.sa_flags & SA_SIGINFO) {          if (oldact.sa_flags & SA_SIGINFO) {
           GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction);            GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction);
         } else {          } else {
Line 1954  void GC_dirty_init()
Line 2488  void GC_dirty_init()
           GC_err_printf0("Replaced other SIGSEGV handler\n");            GC_err_printf0("Replaced other SIGSEGV handler\n");
 #       endif  #       endif
       }        }
 #    endif  #   endif
   #   if defined(MACOSX) || defined(HPUX) || defined(LINUX) || defined(HURD)
         sigaction(SIGBUS, &act, &oldact);
         GC_old_bus_handler = oldact.sa_handler;
         if (GC_old_bus_handler == SIG_IGN) {
                GC_err_printf0("Previously ignored bus error!?");
                GC_old_bus_handler = SIG_DFL;
         }
         if (GC_old_bus_handler != SIG_DFL) {
   #       ifdef PRINTSTATS
             GC_err_printf0("Replaced other SIGBUS handler\n");
   #       endif
         }
   #   endif /* MACOS || HPUX || LINUX */
 #   if defined(MSWIN32)  #   if defined(MSWIN32)
       GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);        GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
       if (GC_old_segv_handler != NULL) {        if (GC_old_segv_handler != NULL) {
Line 1967  void GC_dirty_init()
Line 2514  void GC_dirty_init()
 #   endif  #   endif
 }  }
   
   int GC_incremental_protection_needs()
   {
       if (GC_page_size == HBLKSIZE) {
           return GC_PROTECTS_POINTER_HEAP;
       } else {
           return GC_PROTECTS_POINTER_HEAP | GC_PROTECTS_PTRFREE_HEAP;
       }
   }
   
   #define HAVE_INCREMENTAL_PROTECTION_NEEDS
   
   #define IS_PTRFREE(hhdr) ((hhdr)->hb_descr == 0)
   
   #define PAGE_ALIGNED(x) !((word)(x) & (GC_page_size - 1))
 void GC_protect_heap()  void GC_protect_heap()
 {  {
     ptr_t start;      ptr_t start;
     word len;      word len;
       struct hblk * current;
       struct hblk * current_start;  /* Start of block to be protected. */
       struct hblk * limit;
     unsigned i;      unsigned i;
       GC_bool protect_all =
             (0 != (GC_incremental_protection_needs() & GC_PROTECTS_PTRFREE_HEAP));
     for (i = 0; i < GC_n_heap_sects; i++) {      for (i = 0; i < GC_n_heap_sects; i++) {
         start = GC_heap_sects[i].hs_start;          start = GC_heap_sects[i].hs_start;
         len = GC_heap_sects[i].hs_bytes;          len = GC_heap_sects[i].hs_bytes;
         PROTECT(start, len);          if (protect_all) {
             PROTECT(start, len);
           } else {
             GC_ASSERT(PAGE_ALIGNED(len))
             GC_ASSERT(PAGE_ALIGNED(start))
             current_start = current = (struct hblk *)start;
             limit = (struct hblk *)(start + len);
             while (current < limit) {
               hdr * hhdr;
               word nhblks;
               GC_bool is_ptrfree;
   
               GC_ASSERT(PAGE_ALIGNED(current));
               GET_HDR(current, hhdr);
               if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
                 /* This can happen only if we're at the beginning of a    */
                 /* heap segment, and a block spans heap segments.         */
                 /* We will handle that block as part of the preceding     */
                 /* segment.                                               */
                 GC_ASSERT(current_start == current);
                 current_start = ++current;
                 continue;
               }
               if (HBLK_IS_FREE(hhdr)) {
                 GC_ASSERT(PAGE_ALIGNED(hhdr -> hb_sz));
                 nhblks = divHBLKSZ(hhdr -> hb_sz);
                 is_ptrfree = TRUE;        /* dirty on alloc */
               } else {
                 nhblks = OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
                 is_ptrfree = IS_PTRFREE(hhdr);
               }
               if (is_ptrfree) {
                 if (current_start < current) {
                   PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
                 }
                 current_start = (current += nhblks);
               } else {
                 current += nhblks;
               }
             }
             if (current_start < current) {
               PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
             }
           }
     }      }
 }  }
   
Line 2007  struct hblk * h;
Line 2613  struct hblk * h;
  * happens to work.   * happens to work.
  * On other systems, SET_LOCK_HOLDER and friends must be suitably defined.   * On other systems, SET_LOCK_HOLDER and friends must be suitably defined.
  */   */
   
   static GC_bool syscall_acquired_lock = FALSE;   /* Protected by GC lock. */
   
 void GC_begin_syscall()  void GC_begin_syscall()
 {  {
     if (!I_HOLD_LOCK()) LOCK();      if (!I_HOLD_LOCK()) {
           LOCK();
           syscall_acquired_lock = TRUE;
       }
 }  }
   
 void GC_end_syscall()  void GC_end_syscall()
 {  {
     if (!I_HOLD_LOCK()) UNLOCK();      if (syscall_acquired_lock) {
           syscall_acquired_lock = FALSE;
           UNLOCK();
       }
 }  }
   
 void GC_unprotect_range(addr, len)  void GC_unprotect_range(addr, len)
Line 2027  word len;
Line 2641  word len;
     register struct hblk *h;      register struct hblk *h;
     ptr_t obj_start;      ptr_t obj_start;
   
     if (!GC_incremental) return;      if (!GC_dirty_maintained) return;
     obj_start = GC_base(addr);      obj_start = GC_base(addr);
     if (obj_start == 0) return;      if (obj_start == 0) return;
     if (GC_base(addr + len - 1) != obj_start) {      if (GC_base(addr + len - 1) != obj_start) {
Line 2039  word len;
Line 2653  word len;
     for (h = start_block; h <= end_block; h++) {      for (h = start_block; h <= end_block; h++) {
         register word index = PHT_HASH(h);          register word index = PHT_HASH(h);
   
         set_pht_entry_from_index(GC_dirty_pages, index);          async_set_pht_entry_from_index(GC_dirty_pages, index);
     }      }
     UNPROTECT(start_block,      UNPROTECT(start_block,
               ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);                ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
 }  }
   
 #ifndef MSWIN32  #if 0
 /* Replacement for UNIX system call.     */  
 /* Other calls that write to the heap    */  /* We no longer wrap read by default, since that was causing too many   */
 /* should be handled similarly.          */  /* problems.  It is preferred that the client instead avoids writing    */
   /* to the write-protected heap with a system call.                      */
   /* This still serves as sample code if you do want to wrap system calls.*/
   
   #if !defined(MSWIN32) && !defined(MSWINCE) && !defined(GC_USE_LD_WRAP)
   /* Replacement for UNIX system call.                                      */
   /* Other calls that write to the heap should be handled similarly.        */
   /* Note that this doesn't work well for blocking reads:  It will hold     */
   /* the allocation lock for the entire duration of the call. Multithreaded */
   /* clients should really ensure that it won't block, either by setting    */
   /* the descriptor nonblocking, or by calling select or poll first, to     */
   /* make sure that input is available.                                     */
   /* Another, preferred alternative is to ensure that system calls never    */
   /* write to the protected heap (see above).                               */
 # if defined(__STDC__) && !defined(SUNOS4)  # if defined(__STDC__) && !defined(SUNOS4)
 #   include <unistd.h>  #   include <unistd.h>
   #   include <sys/uio.h>
     ssize_t read(int fd, void *buf, size_t nbyte)      ssize_t read(int fd, void *buf, size_t nbyte)
 # else  # else
 #   ifndef LINT  #   ifndef LINT
Line 2067  word len;
Line 2695  word len;
   
     GC_begin_syscall();      GC_begin_syscall();
     GC_unprotect_range(buf, (word)nbyte);      GC_unprotect_range(buf, (word)nbyte);
 #   ifdef IRIX5  #   if defined(IRIX5) || defined(GC_LINUX_THREADS)
         /* Indirect system call may not always be easily available.     */          /* Indirect system call may not always be easily available.     */
         /* We could call _read, but that would interfere with the       */          /* We could call _read, but that would interfere with the       */
         /* libpthread interception of read.                             */          /* libpthread interception of read.                             */
           /* On Linux, we have to be careful with the linuxthreads        */
           /* read interception.                                           */
         {          {
             struct iovec iov;              struct iovec iov;
   
Line 2079  word len;
Line 2709  word len;
             result = readv(fd, &iov, 1);              result = readv(fd, &iov, 1);
         }          }
 #   else  #   else
         result = syscall(SYS_read, fd, buf, nbyte);  #     if defined(HURD)
           result = __read(fd, buf, nbyte);
   #     else
           /* The two zero args at the end of this list are because one
              IA-64 syscall() implementation actually requires six args
              to be passed, even though they aren't always used. */
           result = syscall(SYS_read, fd, buf, nbyte, 0, 0);
   #     endif /* !HURD */
 #   endif  #   endif
     GC_end_syscall();      GC_end_syscall();
     return(result);      return(result);
 }  }
 #endif /* !MSWIN32 */  #endif /* !MSWIN32 && !MSWINCE && !GC_LINUX_THREADS */
   
   #if defined(GC_USE_LD_WRAP) && !defined(THREADS)
       /* We use the GNU ld call wrapping facility.                        */
       /* This requires that the linker be invoked with "--wrap read".     */
       /* This can be done by passing -Wl,"--wrap read" to gcc.            */
       /* I'm not sure that this actually wraps whatever version of read   */
       /* is called by stdio.  That code also mentions __read.             */
   #   include <unistd.h>
       ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
       {
           int result;
   
           GC_begin_syscall();
           GC_unprotect_range(buf, (word)nbyte);
           result = __real_read(fd, buf, nbyte);
           GC_end_syscall();
           return(result);
       }
   
       /* We should probably also do this for __read, or whatever stdio    */
       /* actually calls.                                                  */
   #endif
   
   #endif /* 0 */
   
 /*ARGSUSED*/  /*ARGSUSED*/
 GC_bool GC_page_was_ever_dirty(h)  GC_bool GC_page_was_ever_dirty(h)
 struct hblk *h;  struct hblk *h;
Line 2101  word n;
Line 2762  word n;
 {  {
 }  }
   
   # else /* !MPROTECT_VDB */
   
   #   ifdef GC_USE_LD_WRAP
         ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
         { return __real_read(fd, buf, nbyte); }
   #   endif
   
 # endif /* MPROTECT_VDB */  # endif /* MPROTECT_VDB */
   
 # ifdef PROC_VDB  # ifdef PROC_VDB
Line 2123  word n;
Line 2791  word n;
 #include <sys/syscall.h>  #include <sys/syscall.h>
 #include <sys/procfs.h>  #include <sys/procfs.h>
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <fcntl.h>  
   
 #define INITIAL_BUF_SZ 4096  #define INITIAL_BUF_SZ 4096
 word GC_proc_buf_size = INITIAL_BUF_SZ;  word GC_proc_buf_size = INITIAL_BUF_SZ;
 char *GC_proc_buf;  char *GC_proc_buf;
   
 #ifdef SOLARIS_THREADS  #ifdef GC_SOLARIS_THREADS
 /* We don't have exact sp values for threads.  So we count on   */  /* We don't have exact sp values for threads.  So we count on   */
 /* occasionally declaring stack pages to be fresh.  Thus we     */  /* occasionally declaring stack pages to be fresh.  Thus we     */
 /* need a real implementation of GC_is_fresh.  We can't clear   */  /* need a real implementation of GC_is_fresh.  We can't clear   */
Line 2184  void GC_dirty_init()
Line 2851  void GC_dirty_init()
         ABORT("/proc ioctl failed");          ABORT("/proc ioctl failed");
     }      }
     GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);      GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
 #   ifdef SOLARIS_THREADS  #   ifdef GC_SOLARIS_THREADS
         GC_fresh_pages = (struct hblk **)          GC_fresh_pages = (struct hblk **)
           GC_scratch_alloc(MAX_FRESH_PAGES * sizeof (struct hblk *));            GC_scratch_alloc(MAX_FRESH_PAGES * sizeof (struct hblk *));
         if (GC_fresh_pages == 0) {          if (GC_fresh_pages == 0) {
Line 2197  void GC_dirty_init()
Line 2864  void GC_dirty_init()
   
 /* Ignore write hints. They don't help us here. */  /* Ignore write hints. They don't help us here. */
 /*ARGSUSED*/  /*ARGSUSED*/
 void GC_write_hint(h)  void GC_remove_protection(h, nblocks, is_ptrfree)
 struct hblk *h;  struct hblk *h;
   word nblocks;
   GC_bool is_ptrfree;
 {  {
 }  }
   
 #ifdef SOLARIS_THREADS  #ifdef GC_SOLARIS_THREADS
 #   define READ(fd,buf,nbytes) syscall(SYS_read, fd, buf, nbytes)  #   define READ(fd,buf,nbytes) syscall(SYS_read, fd, buf, nbytes)
 #else  #else
 #   define READ(fd,buf,nbytes) read(fd, buf, nbytes)  #   define READ(fd,buf,nbytes) read(fd, buf, nbytes)
Line 2241  int dummy;
Line 2910  int dummy;
                 /* Punt:        */                  /* Punt:        */
                 memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));                  memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
                 memset(GC_written_pages, 0xff, sizeof(page_hash_table));                  memset(GC_written_pages, 0xff, sizeof(page_hash_table));
 #               ifdef SOLARIS_THREADS  #               ifdef GC_SOLARIS_THREADS
                     BZERO(GC_fresh_pages,                      BZERO(GC_fresh_pages,
                           MAX_FRESH_PAGES * sizeof (struct hblk *));                            MAX_FRESH_PAGES * sizeof (struct hblk *));
 #               endif  #               endif
Line 2271  int dummy;
Line 2940  int dummy;
                         register word index = PHT_HASH(h);                          register word index = PHT_HASH(h);
   
                         set_pht_entry_from_index(GC_grungy_pages, index);                          set_pht_entry_from_index(GC_grungy_pages, index);
 #                       ifdef SOLARIS_THREADS  #                       ifdef GC_SOLARIS_THREADS
                           {                            {
                             register int slot = FRESH_PAGE_SLOT(h);                              register int slot = FRESH_PAGE_SLOT(h);
   
Line 2289  int dummy;
Line 2958  int dummy;
         }          }
     /* Update GC_written_pages. */      /* Update GC_written_pages. */
         GC_or_pages(GC_written_pages, GC_grungy_pages);          GC_or_pages(GC_written_pages, GC_grungy_pages);
 #   ifdef SOLARIS_THREADS  #   ifdef GC_SOLARIS_THREADS
       /* Make sure that old stacks are considered completely clean      */        /* Make sure that old stacks are considered completely clean      */
       /* unless written again.                                          */        /* unless written again.                                          */
         GC_old_stacks_are_fresh();          GC_old_stacks_are_fresh();
Line 2305  struct hblk *h;
Line 2974  struct hblk *h;
     register GC_bool result;      register GC_bool result;
   
     result = get_pht_entry_from_index(GC_grungy_pages, index);      result = get_pht_entry_from_index(GC_grungy_pages, index);
 #   ifdef SOLARIS_THREADS  #   ifdef GC_SOLARIS_THREADS
         if (result && PAGE_IS_FRESH(h)) result = FALSE;          if (result && PAGE_IS_FRESH(h)) result = FALSE;
         /* This happens only if page was declared fresh since   */          /* This happens only if page was declared fresh since   */
         /* the read_dirty call, e.g. because it's in an unused  */          /* the read_dirty call, e.g. because it's in an unused  */
Line 2323  struct hblk *h;
Line 2992  struct hblk *h;
     register GC_bool result;      register GC_bool result;
   
     result = get_pht_entry_from_index(GC_written_pages, index);      result = get_pht_entry_from_index(GC_written_pages, index);
 #   ifdef SOLARIS_THREADS  #   ifdef GC_SOLARIS_THREADS
         if (result && PAGE_IS_FRESH(h)) result = FALSE;          if (result && PAGE_IS_FRESH(h)) result = FALSE;
 #   endif  #   endif
     return(result);      return(result);
Line 2337  word n;
Line 3006  word n;
   
     register word index;      register word index;
   
 #   ifdef SOLARIS_THREADS  #   ifdef GC_SOLARIS_THREADS
       register word i;        register word i;
   
       if (GC_fresh_pages != 0) {        if (GC_fresh_pages != 0) {
Line 2406  struct hblk *h;
Line 3075  struct hblk *h;
 }  }
   
 /*ARGSUSED*/  /*ARGSUSED*/
 void GC_write_hint(h)  void GC_remove_protection(h, nblocks, is_ptrfree)
 struct hblk *h;  struct hblk *h;
   word nblocks;
   GC_bool is_ptrfree;
 {  {
     PCR_VD_WriteProtectDisable(h, HBLKSIZE);      PCR_VD_WriteProtectDisable(h, nblocks*HBLKSIZE);
     PCR_VD_WriteProtectEnable(h, HBLKSIZE);      PCR_VD_WriteProtectEnable(h, nblocks*HBLKSIZE);
 }  }
   
 # endif /* PCR_VDB */  # endif /* PCR_VDB */
   
   # ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
     int GC_incremental_protection_needs()
     {
       return GC_PROTECTS_NONE;
     }
   # endif /* !HAVE_INCREMENTAL_PROTECTION_NEEDS */
   
 /*  /*
  * Call stack save code for debugging.   * Call stack save code for debugging.
  * Should probably be in mach_dep.c, but that requires reorganization.   * Should probably be in mach_dep.c, but that requires reorganization.
  */   */
 #if defined(SPARC) && !defined(LINUX)  
 #   if defined(SUNOS4)  /* I suspect the following works for most X86 *nix variants, so         */
 #     include <machine/frame.h>  /* long as the frame pointer is explicitly stored.  In the case of gcc, */
 #   else  /* compiler flags (e.g. -fomit-frame-pointer) determine whether it is.  */
 #     if defined (DRSNX)  #if defined(I386) && defined(LINUX) && defined(SAVE_CALL_CHAIN)
 #       include <sys/sparc/frame.h>  #   include <features.h>
 #     else  
 #        if defined(OPENBSD)      struct frame {
 #          include <frame.h>          struct frame *fr_savfp;
 #        else          long    fr_savpc;
 #          include <sys/frame.h>          long    fr_arg[NARGS];  /* All the arguments go here.   */
 #        endif      };
 #     endif  #endif
 #   endif  
 #   if NARGS > 6  #if defined(SPARC)
   #  if defined(LINUX)
   #    include <features.h>
   
        struct frame {
           long    fr_local[8];
           long    fr_arg[6];
           struct frame *fr_savfp;
           long    fr_savpc;
   #       ifndef __arch64__
             char  *fr_stret;
   #       endif
           long    fr_argd[6];
           long    fr_argx[0];
        };
   #  else
   #    if defined(SUNOS4)
   #      include <machine/frame.h>
   #    else
   #      if defined (DRSNX)
   #        include <sys/sparc/frame.h>
   #      else
   #        if defined(OPENBSD) || defined(NETBSD)
   #          include <frame.h>
   #        else
   #          include <sys/frame.h>
   #        endif
   #      endif
   #    endif
   #  endif
   #  if NARGS > 6
         --> We only know how to to get the first 6 arguments          --> We only know how to to get the first 6 arguments
 #   endif  #  endif
   #endif /* SPARC */
   
 #ifdef SAVE_CALL_CHAIN  #ifdef  NEED_CALLINFO
 /* Fill in the pc and argument information for up to NFRAMES of my      */  /* Fill in the pc and argument information for up to NFRAMES of my      */
 /* callers.  Ignore my frame and my callers frame.                      */  /* callers.  Ignore my frame and my callers frame.                      */
   
 #ifdef OPENBSD  #ifdef LINUX
   # include <features.h>
   # if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2
   #   define HAVE_BUILTIN_BACKTRACE
   #   ifdef IA64
   #     define BUILTIN_BACKTRACE_BROKEN
   #   endif
   # endif
   #endif
   
   #include <execinfo.h>
   #ifdef LINUX
   #   include <unistd.h>
   #endif
   
   #endif /* NEED_CALLINFO */
   
   #ifdef SAVE_CALL_CHAIN
   
   #if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
       && defined(HAVE_BUILTIN_BACKTRACE)
   
   void GC_save_callers (info)
   struct callinfo info[NFRAMES];
   {
     void * tmp_info[NFRAMES + 1];
     int npcs, i;
   # define IGNORE_FRAMES 1
   
     /* We retrieve NFRAMES+1 pc values, but discard the first, since it   */
     /* points to our own frame.                                           */
     GC_ASSERT(sizeof(struct callinfo) == sizeof(void *));
     npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES);
     BCOPY(tmp_info+IGNORE_FRAMES, info, (npcs - IGNORE_FRAMES) * sizeof(void *));
     for (i = npcs - IGNORE_FRAMES; i < NFRAMES; ++i) info[i].ci_pc = 0;
   }
   
   #else /* No builtin backtrace; do it ourselves */
   
   #if (defined(OPENBSD) || defined(NETBSD)) && defined(SPARC)
 #  define FR_SAVFP fr_fp  #  define FR_SAVFP fr_fp
 #  define FR_SAVPC fr_pc  #  define FR_SAVPC fr_pc
 #else  #else
Line 2449  struct hblk *h;
Line 3197  struct hblk *h;
 #  define FR_SAVPC fr_savpc  #  define FR_SAVPC fr_savpc
 #endif  #endif
   
   #if defined(SPARC) && (defined(__arch64__) || defined(__sparcv9))
   #   define BIAS 2047
   #else
   #   define BIAS 0
   #endif
   
 void GC_save_callers (info)  void GC_save_callers (info)
 struct callinfo info[NFRAMES];  struct callinfo info[NFRAMES];
 {  {
   struct frame *frame;    struct frame *frame;
   struct frame *fp;    struct frame *fp;
   int nframes = 0;    int nframes = 0;
   word GC_save_regs_in_stack();  # ifdef I386
       /* We assume this is turned on only with gcc as the compiler. */
       asm("movl %%ebp,%0" : "=r"(frame));
       fp = frame;
   # else
       word GC_save_regs_in_stack();
   
   frame = (struct frame *) GC_save_regs_in_stack ();      frame = (struct frame *) GC_save_regs_in_stack ();
       fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
   #endif
   
   for (fp = frame -> FR_SAVFP; fp != 0 && nframes < NFRAMES;     for (; (!(fp HOTTER_THAN frame) && !(GC_stackbottom HOTTER_THAN (ptr_t)fp)
        fp = fp -> FR_SAVFP, nframes++) {             && (nframes < NFRAMES));
          fp = (struct frame *)((long) fp -> FR_SAVFP + BIAS), nframes++) {
       register int i;        register int i;
   
       info[nframes].ci_pc = fp->FR_SAVPC;        info[nframes].ci_pc = fp->FR_SAVPC;
       for (i = 0; i < NARGS; i++) {  #     if NARGS > 0
         info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);          for (i = 0; i < NARGS; i++) {
       }            info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
           }
   #     endif /* NARGS > 0 */
   }    }
   if (nframes < NFRAMES) info[nframes].ci_pc = 0;    if (nframes < NFRAMES) info[nframes].ci_pc = 0;
 }  }
   
   #endif /* No builtin backtrace */
   
 #endif /* SAVE_CALL_CHAIN */  #endif /* SAVE_CALL_CHAIN */
 #endif /* SPARC */  
   
   #ifdef NEED_CALLINFO
   
   /* Print info to stderr.  We do NOT hold the allocation lock */
   void GC_print_callers (info)
   struct callinfo info[NFRAMES];
   {
       register int i;
       static int reentry_count = 0;
   
       LOCK();
         ++reentry_count;
       UNLOCK();
   
   #   if NFRAMES == 1
         GC_err_printf0("\tCaller at allocation:\n");
   #   else
         GC_err_printf0("\tCall chain at allocation:\n");
   #   endif
       for (i = 0; i < NFRAMES; i++) {
           if (info[i].ci_pc == 0) break;
   #       if NARGS > 0
           {
             int j;
   
             GC_err_printf0("\t\targs: ");
             for (j = 0; j < NARGS; j++) {
               if (j != 0) GC_err_printf0(", ");
               GC_err_printf2("%d (0x%X)", ~(info[i].ci_arg[j]),
                                           ~(info[i].ci_arg[j]));
             }
             GC_err_printf0("\n");
           }
   #       endif
           if (reentry_count > 1) {
               /* We were called during an allocation during       */
               /* a previous GC_print_callers call; punt.          */
               GC_err_printf1("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
               continue;
           }
           {
   #         ifdef LINUX
               FILE *pipe;
   #         endif
   #         if defined(HAVE_BUILTIN_BACKTRACE) && \
                !defined(BUILTIN_BACKTRACE_BROKEN)
               char **sym_name =
                 backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
               char *name = sym_name[0];
               GC_bool found_it = (strchr(name, '(') != 0);
   #         else
               char buf[40];
               char *name = buf;
               GC_bool fount_it = FALSE:
               sprintf(buf, "##PC##= 0x%lx", info[i].ci_pc);
   #         endif
   #         ifdef LINUX
               if (!found_it) {
   #               define EXE_SZ 100
                   static char exe_name[EXE_SZ];
   #               define CMD_SZ 200
                   char cmd_buf[CMD_SZ];
   #               define RESULT_SZ 200
                   static char result_buf[RESULT_SZ];
                   size_t result_len;
                   static GC_bool found_exe_name = FALSE;
                   static GC_bool will_fail = FALSE;
                   int ret_code;
                   /* Unfortunately, this is the common case for the       */
                   /* main executable.                                     */
                   /* Try to get it via a hairy and expensive scheme.      */
                   /* First we get the name of the executable:             */
                   if (will_fail) goto out;
                   if (!found_exe_name) {
                     ret_code = readlink("/proc/self/exe", exe_name, EXE_SZ);
                     if (ret_code < 0 || ret_code >= EXE_SZ
                         || exe_name[0] != '/') {
                       will_fail = TRUE;   /* Dont try again. */
                       goto out;
                     }
                     exe_name[ret_code] = '\0';
                     found_exe_name = TRUE;
                   }
                   /* Then we use popen to start addr2line -e <exe> <addr> */
                   /* There are faster ways to do this, but hopefully this */
                   /* isn't time critical.                                 */
                   sprintf(cmd_buf, "/usr/bin/addr2line -e %s 0x%lx", exe_name,
                                    (unsigned long)info[i].ci_pc);
                   pipe = popen(cmd_buf, "r");
                   if (pipe < 0 || fgets(result_buf, RESULT_SZ, pipe) == 0) {
                     will_fail = TRUE;
                     goto out;
                   }
                   result_len = strlen(result_buf);
                   if (result_buf[result_len - 1] == '\n') --result_len;
                   if (result_buf[0] == '?'
                       || result_buf[result_len-2] == ':'
                          && result_buf[result_len-1] == '0')
                       goto out;
                   if (result_len < RESULT_SZ - 25) {
                     /* Add in hex address */
                       sprintf(result_buf + result_len, " [0x%lx]",
                             (unsigned long)info[i].ci_pc);
                   }
                   name = result_buf;
                   pclose(pipe);
                   out:
               }
   #         endif /* LINUX */
             GC_err_printf1("\t\t%s\n", name);
             free(sym_name);  /* May call GC_free; that's OK */
           }
       }
       LOCK();
         --reentry_count;
       UNLOCK();
   }
   
   #endif /* NEED_CALLINFO */
   
   #if defined(LINUX) && defined(__ELF__) && \
       (!defined(SMALL_CONFIG) || defined(USE_PROC_FOR_LIBRARIES))
   #ifdef GC_USE_LD_WRAP
   #   define READ __real_read
   #else
   #   define READ read
   #endif
   
   
   /* Repeatedly perform a read call until the buffer is filled or */
   /* we encounter EOF.                                            */
   ssize_t GC_repeat_read(int fd, char *buf, size_t count)
   {
       ssize_t num_read = 0;
       ssize_t result;
   
       while (num_read < count) {
           result = READ(fd, buf + num_read, count - num_read);
           if (result < 0) return result;
           if (result == 0) break;
           num_read += result;
       }
       return num_read;
   }
   #endif /* LINUX && ... */
   
   
   #if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
   
   /* Dump /proc/self/maps to GC_stderr, to enable looking up names for
      addresses in FIND_LEAK output. */
   
   void GC_print_address_map()
   {
       int f;
       int result;
       char maps_temp[32768];
       GC_err_printf0("---------- Begin address map ----------\n");
           f = open("/proc/self/maps", O_RDONLY);
           if (-1 == f) ABORT("Couldn't open /proc/self/maps");
           do {
               result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
               if (result <= 0) ABORT("Couldn't read /proc/self/maps");
               GC_err_write(maps_temp, result);
           } while (result == sizeof(maps_temp));
   
       GC_err_printf0("---------- End address map ----------\n");
   }
   
   #endif
   
   

Legend:
Removed from v.1.1.1.1  
changed lines
  Added in v.1.6

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>