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

Annotation of OpenXM_contrib/gc/os_dep.c, Revision 1.1.1.1

1.1       maekawa     1: /*
                      2:  * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
                      3:  * Copyright (c) 1996-1997 by Silicon Graphics.  All rights reserved.
                      4:  *
                      5:  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
                      6:  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
                      7:  *
                      8:  * Permission is hereby granted to use or copy this program
                      9:  * for any purpose,  provided the above notices are retained on all copies.
                     10:  * Permission to modify the code and to distribute modified code is granted,
                     11:  * provided the above notices are retained, and a notice that the code was
                     12:  * modified is included with the above copyright notice.
                     13:  */
                     14:
                     15: # include "gc_priv.h"
                     16:
                     17: # if defined(LINUX) && !defined(POWERPC)
                     18: #   include <linux/version.h>
                     19: #   if (LINUX_VERSION_CODE <= 0x10400)
                     20:       /* Ugly hack to get struct sigcontext_struct definition.  Required      */
                     21:       /* for some early 1.3.X releases.  Will hopefully go away soon. */
                     22:       /* in some later Linux releases, asm/sigcontext.h may have to   */
                     23:       /* be included instead.                                         */
                     24: #     define __KERNEL__
                     25: #     include <asm/signal.h>
                     26: #     undef __KERNEL__
                     27: #   else
                     28:       /* Kernels prior to 2.1.1 defined struct sigcontext_struct instead of */
                     29:       /* struct sigcontext.  libc6 (glibc2) uses "struct sigcontext" in     */
                     30:       /* prototypes, so we have to include the top-level sigcontext.h to    */
                     31:       /* make sure the former gets defined to be the latter if appropriate. */
                     32: #     include <features.h>
                     33: #     if 2 <= __GLIBC__
                     34: #       if 0 == __GLIBC_MINOR__
                     35:          /* glibc 2.1 no longer has sigcontext.h.  But signal.h        */
                     36:          /* has the right declaration for glibc 2.1.                   */
                     37: #         include <sigcontext.h>
                     38: #       endif /* 0 == __GLIBC_MINOR__ */
                     39: #     else /* not 2 <= __GLIBC__ */
                     40:         /* libc5 doesn't have <sigcontext.h>: go directly with the kernel   */
                     41:         /* one.  Check LINUX_VERSION_CODE to see which we should reference. */
                     42: #       include <asm/sigcontext.h>
                     43: #     endif /* 2 <= __GLIBC__ */
                     44: #   endif
                     45: # endif
                     46: # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS)
                     47: #   include <sys/types.h>
                     48: #   if !defined(MSWIN32) && !defined(SUNOS4)
                     49: #      include <unistd.h>
                     50: #   endif
                     51: # endif
                     52:
                     53: # include <stdio.h>
                     54: # include <signal.h>
                     55:
                     56: /* Blatantly OS dependent routines, except for those that are related  */
                     57: /* dynamic loading.                                                    */
                     58:
                     59: # if !defined(THREADS) && !defined(STACKBOTTOM) && defined(HEURISTIC2)
                     60: #   define NEED_FIND_LIMIT
                     61: # endif
                     62:
                     63: # if defined(IRIX_THREADS)
                     64: #   define NEED_FIND_LIMIT
                     65: # endif
                     66:
                     67: # if (defined(SUNOS4) & defined(DYNAMIC_LOADING)) && !defined(PCR)
                     68: #   define NEED_FIND_LIMIT
                     69: # endif
                     70:
                     71: # if (defined(SVR4) || defined(AUX) || defined(DGUX)) && !defined(PCR)
                     72: #   define NEED_FIND_LIMIT
                     73: # endif
                     74:
                     75: # if defined(LINUX) && (defined(POWERPC) || defined(SPARC))
                     76: #   define NEED_FIND_LIMIT
                     77: # endif
                     78:
                     79: #ifdef NEED_FIND_LIMIT
                     80: #   include <setjmp.h>
                     81: #endif
                     82:
                     83: #ifdef FREEBSD
                     84: #  include <machine/trap.h>
                     85: #endif
                     86:
                     87: #ifdef AMIGA
                     88: # include <proto/exec.h>
                     89: # include <proto/dos.h>
                     90: # include <dos/dosextens.h>
                     91: # include <workbench/startup.h>
                     92: #endif
                     93:
                     94: #ifdef MSWIN32
                     95: # define WIN32_LEAN_AND_MEAN
                     96: # define NOSERVICE
                     97: # include <windows.h>
                     98: #endif
                     99:
                    100: #ifdef MACOS
                    101: # include <Processes.h>
                    102: #endif
                    103:
                    104: #ifdef IRIX5
                    105: # include <sys/uio.h>
                    106: # include <malloc.h>   /* for locking */
                    107: #endif
                    108: #ifdef USE_MMAP
                    109: # include <sys/types.h>
                    110: # include <sys/mman.h>
                    111: # include <sys/stat.h>
                    112: # include <fcntl.h>
                    113: #endif
                    114:
                    115: #ifdef SUNOS5SIGS
                    116: # include <sys/siginfo.h>
                    117: # undef setjmp
                    118: # undef longjmp
                    119: # define setjmp(env) sigsetjmp(env, 1)
                    120: # define longjmp(env, val) siglongjmp(env, val)
                    121: # define jmp_buf sigjmp_buf
                    122: #endif
                    123:
                    124: #ifdef DJGPP
                    125:   /* Apparently necessary for djgpp 2.01.  May casuse problems with    */
                    126:   /* other versions.                                                   */
                    127:   typedef long unsigned int caddr_t;
                    128: #endif
                    129:
                    130: #ifdef PCR
                    131: # include "il/PCR_IL.h"
                    132: # include "th/PCR_ThCtl.h"
                    133: # include "mm/PCR_MM.h"
                    134: #endif
                    135:
                    136: #if !defined(NO_EXECUTE_PERMISSION)
                    137: # define OPT_PROT_EXEC PROT_EXEC
                    138: #else
                    139: # define OPT_PROT_EXEC 0
                    140: #endif
                    141:
                    142: #if defined(LINUX) && defined(POWERPC)
                    143:   ptr_t GC_data_start;
                    144:
                    145:   void GC_init_linuxppc()
                    146:   {
                    147:     extern ptr_t GC_find_limit();
                    148:     extern char **_environ;
                    149:        /* This may need to be environ, without the underscore, for     */
                    150:        /* some versions.                                               */
                    151:     GC_data_start = GC_find_limit((ptr_t)&_environ, FALSE);
                    152:   }
                    153: #endif
                    154:
                    155: #if defined(LINUX) && defined(SPARC)
                    156:   ptr_t GC_data_start;
                    157:
                    158:   void GC_init_linuxsparc()
                    159:   {
                    160:     extern ptr_t GC_find_limit();
                    161:     extern char **_environ;
                    162:       /* This may need to be environ, without the underscore, for     */
                    163:       /* some versions.                                               */
                    164:     GC_data_start = GC_find_limit((ptr_t)&_environ, FALSE);
                    165:   }
                    166: #endif
                    167:
                    168: # ifdef OS2
                    169:
                    170: # include <stddef.h>
                    171:
                    172: # if !defined(__IBMC__) && !defined(__WATCOMC__) /* e.g. EMX */
                    173:
                    174: struct exe_hdr {
                    175:     unsigned short      magic_number;
                    176:     unsigned short      padding[29];
                    177:     long                new_exe_offset;
                    178: };
                    179:
                    180: #define E_MAGIC(x)      (x).magic_number
                    181: #define EMAGIC          0x5A4D
                    182: #define E_LFANEW(x)     (x).new_exe_offset
                    183:
                    184: struct e32_exe {
                    185:     unsigned char       magic_number[2];
                    186:     unsigned char       byte_order;
                    187:     unsigned char       word_order;
                    188:     unsigned long       exe_format_level;
                    189:     unsigned short      cpu;
                    190:     unsigned short      os;
                    191:     unsigned long       padding1[13];
                    192:     unsigned long       object_table_offset;
                    193:     unsigned long       object_count;
                    194:     unsigned long       padding2[31];
                    195: };
                    196:
                    197: #define E32_MAGIC1(x)   (x).magic_number[0]
                    198: #define E32MAGIC1       'L'
                    199: #define E32_MAGIC2(x)   (x).magic_number[1]
                    200: #define E32MAGIC2       'X'
                    201: #define E32_BORDER(x)   (x).byte_order
                    202: #define E32LEBO         0
                    203: #define E32_WORDER(x)   (x).word_order
                    204: #define E32LEWO         0
                    205: #define E32_CPU(x)      (x).cpu
                    206: #define E32CPU286       1
                    207: #define E32_OBJTAB(x)   (x).object_table_offset
                    208: #define E32_OBJCNT(x)   (x).object_count
                    209:
                    210: struct o32_obj {
                    211:     unsigned long       size;
                    212:     unsigned long       base;
                    213:     unsigned long       flags;
                    214:     unsigned long       pagemap;
                    215:     unsigned long       mapsize;
                    216:     unsigned long       reserved;
                    217: };
                    218:
                    219: #define O32_FLAGS(x)    (x).flags
                    220: #define OBJREAD         0x0001L
                    221: #define OBJWRITE        0x0002L
                    222: #define OBJINVALID      0x0080L
                    223: #define O32_SIZE(x)     (x).size
                    224: #define O32_BASE(x)     (x).base
                    225:
                    226: # else  /* IBM's compiler */
                    227:
                    228: /* A kludge to get around what appears to be a header file bug */
                    229: # ifndef WORD
                    230: #   define WORD unsigned short
                    231: # endif
                    232: # ifndef DWORD
                    233: #   define DWORD unsigned long
                    234: # endif
                    235:
                    236: # define EXE386 1
                    237: # include <newexe.h>
                    238: # include <exe386.h>
                    239:
                    240: # endif  /* __IBMC__ */
                    241:
                    242: # define INCL_DOSEXCEPTIONS
                    243: # define INCL_DOSPROCESS
                    244: # define INCL_DOSERRORS
                    245: # define INCL_DOSMODULEMGR
                    246: # define INCL_DOSMEMMGR
                    247: # include <os2.h>
                    248:
                    249:
                    250: /* Disable and enable signals during nontrivial allocations    */
                    251:
                    252: void GC_disable_signals(void)
                    253: {
                    254:     ULONG nest;
                    255:
                    256:     DosEnterMustComplete(&nest);
                    257:     if (nest != 1) ABORT("nested GC_disable_signals");
                    258: }
                    259:
                    260: void GC_enable_signals(void)
                    261: {
                    262:     ULONG nest;
                    263:
                    264:     DosExitMustComplete(&nest);
                    265:     if (nest != 0) ABORT("GC_enable_signals");
                    266: }
                    267:
                    268:
                    269: # else
                    270:
                    271: #  if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \
                    272:       && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW)
                    273:
                    274: #   if defined(sigmask) && !defined(UTS4)
                    275:        /* Use the traditional BSD interface */
                    276: #      define SIGSET_T int
                    277: #      define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))
                    278: #      define SIG_FILL(set)  (set) = 0x7fffffff
                    279:          /* Setting the leading bit appears to provoke a bug in some   */
                    280:          /* longjmp implementations.  Most systems appear not to have  */
                    281:          /* a signal 32.                                               */
                    282: #      define SIGSETMASK(old, new) (old) = sigsetmask(new)
                    283: #   else
                    284:        /* Use POSIX/SYSV interface     */
                    285: #      define SIGSET_T sigset_t
                    286: #      define SIG_DEL(set, signal) sigdelset(&(set), (signal))
                    287: #      define SIG_FILL(set) sigfillset(&set)
                    288: #      define SIGSETMASK(old, new) sigprocmask(SIG_SETMASK, &(new), &(old))
                    289: #   endif
                    290:
                    291: static GC_bool mask_initialized = FALSE;
                    292:
                    293: static SIGSET_T new_mask;
                    294:
                    295: static SIGSET_T old_mask;
                    296:
                    297: static SIGSET_T dummy;
                    298:
                    299: #if defined(PRINTSTATS) && !defined(THREADS)
                    300: # define CHECK_SIGNALS
                    301:   int GC_sig_disabled = 0;
                    302: #endif
                    303:
                    304: void GC_disable_signals()
                    305: {
                    306:     if (!mask_initialized) {
                    307:        SIG_FILL(new_mask);
                    308:
                    309:        SIG_DEL(new_mask, SIGSEGV);
                    310:        SIG_DEL(new_mask, SIGILL);
                    311:        SIG_DEL(new_mask, SIGQUIT);
                    312: #      ifdef SIGBUS
                    313:            SIG_DEL(new_mask, SIGBUS);
                    314: #      endif
                    315: #      ifdef SIGIOT
                    316:            SIG_DEL(new_mask, SIGIOT);
                    317: #      endif
                    318: #      ifdef SIGEMT
                    319:            SIG_DEL(new_mask, SIGEMT);
                    320: #      endif
                    321: #      ifdef SIGTRAP
                    322:            SIG_DEL(new_mask, SIGTRAP);
                    323: #      endif
                    324:        mask_initialized = TRUE;
                    325:     }
                    326: #   ifdef CHECK_SIGNALS
                    327:        if (GC_sig_disabled != 0) ABORT("Nested disables");
                    328:        GC_sig_disabled++;
                    329: #   endif
                    330:     SIGSETMASK(old_mask,new_mask);
                    331: }
                    332:
                    333: void GC_enable_signals()
                    334: {
                    335: #   ifdef CHECK_SIGNALS
                    336:        if (GC_sig_disabled != 1) ABORT("Unmatched enable");
                    337:        GC_sig_disabled--;
                    338: #   endif
                    339:     SIGSETMASK(dummy,old_mask);
                    340: }
                    341:
                    342: #  endif  /* !PCR */
                    343:
                    344: # endif /*!OS/2 */
                    345:
                    346: /* Ivan Demakov: simplest way (to me) */
                    347: #ifdef DOS4GW
                    348:   void GC_disable_signals() { }
                    349:   void GC_enable_signals() { }
                    350: #endif
                    351:
                    352: /* Find the page size */
                    353: word GC_page_size;
                    354:
                    355: # ifdef MSWIN32
                    356:   void GC_setpagesize()
                    357:   {
                    358:     SYSTEM_INFO sysinfo;
                    359:
                    360:     GetSystemInfo(&sysinfo);
                    361:     GC_page_size = sysinfo.dwPageSize;
                    362:   }
                    363:
                    364: # else
                    365: #   if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP)
                    366:        void GC_setpagesize()
                    367:        {
                    368:            GC_page_size = GETPAGESIZE();
                    369:        }
                    370: #   else
                    371:        /* It's acceptable to fake it. */
                    372:        void GC_setpagesize()
                    373:        {
                    374:            GC_page_size = HBLKSIZE;
                    375:        }
                    376: #   endif
                    377: # endif
                    378:
                    379: /*
                    380:  * Find the base of the stack.
                    381:  * Used only in single-threaded environment.
                    382:  * With threads, GC_mark_roots needs to know how to do this.
                    383:  * Called with allocator lock held.
                    384:  */
                    385: # ifdef MSWIN32
                    386: # define is_writable(prot) ((prot) == PAGE_READWRITE \
                    387:                            || (prot) == PAGE_WRITECOPY \
                    388:                            || (prot) == PAGE_EXECUTE_READWRITE \
                    389:                            || (prot) == PAGE_EXECUTE_WRITECOPY)
                    390: /* Return the number of bytes that are writable starting at p. */
                    391: /* The pointer p is assumed to be page aligned.                        */
                    392: /* If base is not 0, *base becomes the beginning of the        */
                    393: /* allocation region containing p.                             */
                    394: word GC_get_writable_length(ptr_t p, ptr_t *base)
                    395: {
                    396:     MEMORY_BASIC_INFORMATION buf;
                    397:     word result;
                    398:     word protect;
                    399:
                    400:     result = VirtualQuery(p, &buf, sizeof(buf));
                    401:     if (result != sizeof(buf)) ABORT("Weird VirtualQuery result");
                    402:     if (base != 0) *base = (ptr_t)(buf.AllocationBase);
                    403:     protect = (buf.Protect & ~(PAGE_GUARD | PAGE_NOCACHE));
                    404:     if (!is_writable(protect)) {
                    405:         return(0);
                    406:     }
                    407:     if (buf.State != MEM_COMMIT) return(0);
                    408:     return(buf.RegionSize);
                    409: }
                    410:
                    411: ptr_t GC_get_stack_base()
                    412: {
                    413:     int dummy;
                    414:     ptr_t sp = (ptr_t)(&dummy);
                    415:     ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_page_size - 1));
                    416:     word size = GC_get_writable_length(trunc_sp, 0);
                    417:
                    418:     return(trunc_sp + size);
                    419: }
                    420:
                    421:
                    422: # else
                    423:
                    424: # ifdef OS2
                    425:
                    426: ptr_t GC_get_stack_base()
                    427: {
                    428:     PTIB ptib;
                    429:     PPIB ppib;
                    430:
                    431:     if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
                    432:        GC_err_printf0("DosGetInfoBlocks failed\n");
                    433:        ABORT("DosGetInfoBlocks failed\n");
                    434:     }
                    435:     return((ptr_t)(ptib -> tib_pstacklimit));
                    436: }
                    437:
                    438: # else
                    439:
                    440: # ifdef AMIGA
                    441:
                    442: ptr_t GC_get_stack_base()
                    443: {
                    444:     extern struct WBStartup *_WBenchMsg;
                    445:     extern long __base;
                    446:     extern long __stack;
                    447:     struct Task *task;
                    448:     struct Process *proc;
                    449:     struct CommandLineInterface *cli;
                    450:     long size;
                    451:
                    452:     if ((task = FindTask(0)) == 0) {
                    453:        GC_err_puts("Cannot find own task structure\n");
                    454:        ABORT("task missing");
                    455:     }
                    456:     proc = (struct Process *)task;
                    457:     cli = BADDR(proc->pr_CLI);
                    458:
                    459:     if (_WBenchMsg != 0 || cli == 0) {
                    460:        size = (char *)task->tc_SPUpper - (char *)task->tc_SPLower;
                    461:     } else {
                    462:        size = cli->cli_DefaultStack * 4;
                    463:     }
                    464:     return (ptr_t)(__base + GC_max(size, __stack));
                    465: }
                    466:
                    467: # else
                    468:
                    469:
                    470:
                    471: # ifdef NEED_FIND_LIMIT
                    472:   /* Some tools to implement HEURISTIC2        */
                    473: #   define MIN_PAGE_SIZE 256   /* Smallest conceivable page size, bytes */
                    474:     /* static */ jmp_buf GC_jmp_buf;
                    475:
                    476:     /*ARGSUSED*/
                    477:     void GC_fault_handler(sig)
                    478:     int sig;
                    479:     {
                    480:         longjmp(GC_jmp_buf, 1);
                    481:     }
                    482:
                    483: #   ifdef __STDC__
                    484:        typedef void (*handler)(int);
                    485: #   else
                    486:        typedef void (*handler)();
                    487: #   endif
                    488:
                    489: #   if defined(SUNOS5SIGS) || defined(IRIX5)
                    490:        static struct sigaction old_segv_act;
                    491: #      if defined(_sigargs) /* !Irix6.x */
                    492:            static struct sigaction old_bus_act;
                    493: #      endif
                    494: #   else
                    495:         static handler old_segv_handler, old_bus_handler;
                    496: #   endif
                    497:
                    498:     void GC_setup_temporary_fault_handler()
                    499:     {
                    500: #      if defined(SUNOS5SIGS) || defined(IRIX5)
                    501:          struct sigaction      act;
                    502:
                    503:          act.sa_handler        = GC_fault_handler;
                    504:           act.sa_flags          = SA_RESTART | SA_NODEFER;
                    505:           /* The presence of SA_NODEFER represents yet another gross    */
                    506:           /* hack.  Under Solaris 2.3, siglongjmp doesn't appear to     */
                    507:           /* interact correctly with -lthread.  We hide the confusion   */
                    508:           /* by making sure that signal handling doesn't affect the     */
                    509:           /* signal mask.                                               */
                    510:
                    511:          (void) sigemptyset(&act.sa_mask);
                    512: #        ifdef IRIX_THREADS
                    513:                /* Older versions have a bug related to retrieving and  */
                    514:                /* and setting a handler at the same time.              */
                    515:                (void) sigaction(SIGSEGV, 0, &old_segv_act);
                    516:                (void) sigaction(SIGSEGV, &act, 0);
                    517: #        else
                    518:                (void) sigaction(SIGSEGV, &act, &old_segv_act);
                    519: #              ifdef _sigargs  /* Irix 5.x, not 6.x */
                    520:                    /* Under 5.x, we may get SIGBUS.                    */
                    521:                    /* Pthreads doesn't exist under 5.x, so we don't    */
                    522:                    /* have to worry in the threads case.               */
                    523:                    (void) sigaction(SIGBUS, &act, &old_bus_act);
                    524: #              endif
                    525: #        endif /* IRIX_THREADS */
                    526: #      else
                    527:          old_segv_handler = signal(SIGSEGV, GC_fault_handler);
                    528: #        ifdef SIGBUS
                    529:            old_bus_handler = signal(SIGBUS, GC_fault_handler);
                    530: #        endif
                    531: #      endif
                    532:     }
                    533:
                    534:     void GC_reset_fault_handler()
                    535:     {
                    536: #       if defined(SUNOS5SIGS) || defined(IRIX5)
                    537:          (void) sigaction(SIGSEGV, &old_segv_act, 0);
                    538: #        ifdef _sigargs        /* Irix 5.x, not 6.x */
                    539:              (void) sigaction(SIGBUS, &old_bus_act, 0);
                    540: #        endif
                    541: #       else
                    542:          (void) signal(SIGSEGV, old_segv_handler);
                    543: #        ifdef SIGBUS
                    544:            (void) signal(SIGBUS, old_bus_handler);
                    545: #        endif
                    546: #       endif
                    547:     }
                    548:
                    549:     /* Return the first nonaddressible location > p (up) or    */
                    550:     /* the smallest location q s.t. [q,p] is addressible (!up).        */
                    551:     ptr_t GC_find_limit(p, up)
                    552:     ptr_t p;
                    553:     GC_bool up;
                    554:     {
                    555:         static VOLATILE ptr_t result;
                    556:                /* Needs to be static, since otherwise it may not be    */
                    557:                /* preserved across the longjmp.  Can safely be         */
                    558:                /* static since it's only called once, with the         */
                    559:                /* allocation lock held.                                */
                    560:
                    561:
                    562:        GC_setup_temporary_fault_handler();
                    563:        if (setjmp(GC_jmp_buf) == 0) {
                    564:            result = (ptr_t)(((word)(p))
                    565:                              & ~(MIN_PAGE_SIZE-1));
                    566:            for (;;) {
                    567:                if (up) {
                    568:                    result += MIN_PAGE_SIZE;
                    569:                } else {
                    570:                    result -= MIN_PAGE_SIZE;
                    571:                }
                    572:                GC_noop1((word)(*result));
                    573:            }
                    574:        }
                    575:        GC_reset_fault_handler();
                    576:        if (!up) {
                    577:            result += MIN_PAGE_SIZE;
                    578:        }
                    579:        return(result);
                    580:     }
                    581: # endif
                    582:
                    583:
                    584: ptr_t GC_get_stack_base()
                    585: {
                    586:     word dummy;
                    587:     ptr_t result;
                    588:
                    589: #   define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
                    590:
                    591: #   ifdef STACKBOTTOM
                    592:        return(STACKBOTTOM);
                    593: #   else
                    594: #      ifdef HEURISTIC1
                    595: #         ifdef STACK_GROWS_DOWN
                    596:             result = (ptr_t)((((word)(&dummy))
                    597:                               + STACKBOTTOM_ALIGNMENT_M1)
                    598:                              & ~STACKBOTTOM_ALIGNMENT_M1);
                    599: #         else
                    600:             result = (ptr_t)(((word)(&dummy))
                    601:                              & ~STACKBOTTOM_ALIGNMENT_M1);
                    602: #         endif
                    603: #      endif /* HEURISTIC1 */
                    604: #      ifdef HEURISTIC2
                    605: #          ifdef STACK_GROWS_DOWN
                    606:                result = GC_find_limit((ptr_t)(&dummy), TRUE);
                    607: #              ifdef HEURISTIC2_LIMIT
                    608:                    if (result > HEURISTIC2_LIMIT
                    609:                        && (ptr_t)(&dummy) < HEURISTIC2_LIMIT) {
                    610:                            result = HEURISTIC2_LIMIT;
                    611:                    }
                    612: #              endif
                    613: #          else
                    614:                result = GC_find_limit((ptr_t)(&dummy), FALSE);
                    615: #              ifdef HEURISTIC2_LIMIT
                    616:                    if (result < HEURISTIC2_LIMIT
                    617:                        && (ptr_t)(&dummy) > HEURISTIC2_LIMIT) {
                    618:                            result = HEURISTIC2_LIMIT;
                    619:                    }
                    620: #              endif
                    621: #          endif
                    622:
                    623: #      endif /* HEURISTIC2 */
                    624: #      ifdef STACK_GROWS_DOWN
                    625:            if (result == 0) result = (ptr_t)(signed_word)(-sizeof(ptr_t));
                    626: #      endif
                    627:        return(result);
                    628: #   endif /* STACKBOTTOM */
                    629: }
                    630:
                    631: # endif /* ! AMIGA */
                    632: # endif /* ! OS2 */
                    633: # endif /* ! MSWIN32 */
                    634:
                    635: /*
                    636:  * Register static data segment(s) as roots.
                    637:  * If more data segments are added later then they need to be registered
                    638:  * add that point (as we do with SunOS dynamic loading),
                    639:  * or GC_mark_roots needs to check for them (as we do with PCR).
                    640:  * Called with allocator lock held.
                    641:  */
                    642:
                    643: # ifdef OS2
                    644:
                    645: void GC_register_data_segments()
                    646: {
                    647:     PTIB ptib;
                    648:     PPIB ppib;
                    649:     HMODULE module_handle;
                    650: #   define PBUFSIZ 512
                    651:     UCHAR path[PBUFSIZ];
                    652:     FILE * myexefile;
                    653:     struct exe_hdr hdrdos;     /* MSDOS header.        */
                    654:     struct e32_exe hdr386;     /* Real header for my executable */
                    655:     struct o32_obj seg;        /* Currrent segment */
                    656:     int nsegs;
                    657:
                    658:
                    659:     if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
                    660:        GC_err_printf0("DosGetInfoBlocks failed\n");
                    661:        ABORT("DosGetInfoBlocks failed\n");
                    662:     }
                    663:     module_handle = ppib -> pib_hmte;
                    664:     if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) {
                    665:        GC_err_printf0("DosQueryModuleName failed\n");
                    666:        ABORT("DosGetInfoBlocks failed\n");
                    667:     }
                    668:     myexefile = fopen(path, "rb");
                    669:     if (myexefile == 0) {
                    670:         GC_err_puts("Couldn't open executable ");
                    671:         GC_err_puts(path); GC_err_puts("\n");
                    672:         ABORT("Failed to open executable\n");
                    673:     }
                    674:     if (fread((char *)(&hdrdos), 1, sizeof hdrdos, myexefile) < sizeof hdrdos) {
                    675:         GC_err_puts("Couldn't read MSDOS header from ");
                    676:         GC_err_puts(path); GC_err_puts("\n");
                    677:         ABORT("Couldn't read MSDOS header");
                    678:     }
                    679:     if (E_MAGIC(hdrdos) != EMAGIC) {
                    680:         GC_err_puts("Executable has wrong DOS magic number: ");
                    681:         GC_err_puts(path); GC_err_puts("\n");
                    682:         ABORT("Bad DOS magic number");
                    683:     }
                    684:     if (fseek(myexefile, E_LFANEW(hdrdos), SEEK_SET) != 0) {
                    685:         GC_err_puts("Seek to new header failed in ");
                    686:         GC_err_puts(path); GC_err_puts("\n");
                    687:         ABORT("Bad DOS magic number");
                    688:     }
                    689:     if (fread((char *)(&hdr386), 1, sizeof hdr386, myexefile) < sizeof hdr386) {
                    690:         GC_err_puts("Couldn't read MSDOS header from ");
                    691:         GC_err_puts(path); GC_err_puts("\n");
                    692:         ABORT("Couldn't read OS/2 header");
                    693:     }
                    694:     if (E32_MAGIC1(hdr386) != E32MAGIC1 || E32_MAGIC2(hdr386) != E32MAGIC2) {
                    695:         GC_err_puts("Executable has wrong OS/2 magic number:");
                    696:         GC_err_puts(path); GC_err_puts("\n");
                    697:         ABORT("Bad OS/2 magic number");
                    698:     }
                    699:     if ( E32_BORDER(hdr386) != E32LEBO || E32_WORDER(hdr386) != E32LEWO) {
                    700:         GC_err_puts("Executable %s has wrong byte order: ");
                    701:         GC_err_puts(path); GC_err_puts("\n");
                    702:         ABORT("Bad byte order");
                    703:     }
                    704:     if ( E32_CPU(hdr386) == E32CPU286) {
                    705:         GC_err_puts("GC can't handle 80286 executables: ");
                    706:         GC_err_puts(path); GC_err_puts("\n");
                    707:         EXIT();
                    708:     }
                    709:     if (fseek(myexefile, E_LFANEW(hdrdos) + E32_OBJTAB(hdr386),
                    710:              SEEK_SET) != 0) {
                    711:         GC_err_puts("Seek to object table failed: ");
                    712:         GC_err_puts(path); GC_err_puts("\n");
                    713:         ABORT("Seek to object table failed");
                    714:     }
                    715:     for (nsegs = E32_OBJCNT(hdr386); nsegs > 0; nsegs--) {
                    716:       int flags;
                    717:       if (fread((char *)(&seg), 1, sizeof seg, myexefile) < sizeof seg) {
                    718:         GC_err_puts("Couldn't read obj table entry from ");
                    719:         GC_err_puts(path); GC_err_puts("\n");
                    720:         ABORT("Couldn't read obj table entry");
                    721:       }
                    722:       flags = O32_FLAGS(seg);
                    723:       if (!(flags & OBJWRITE)) continue;
                    724:       if (!(flags & OBJREAD)) continue;
                    725:       if (flags & OBJINVALID) {
                    726:           GC_err_printf0("Object with invalid pages?\n");
                    727:           continue;
                    728:       }
                    729:       GC_add_roots_inner(O32_BASE(seg), O32_BASE(seg)+O32_SIZE(seg), FALSE);
                    730:     }
                    731: }
                    732:
                    733: # else
                    734:
                    735: # ifdef MSWIN32
                    736:   /* Unfortunately, we have to handle win32s very differently from NT,         */
                    737:   /* Since VirtualQuery has very different semantics.  In particular,  */
                    738:   /* under win32s a VirtualQuery call on an unmapped page returns an   */
                    739:   /* invalid result.  Under GC_register_data_segments is a noop and    */
                    740:   /* all real work is done by GC_register_dynamic_libraries.  Under    */
                    741:   /* win32s, we cannot find the data segments associated with dll's.   */
                    742:   /* We rgister the main data segment here.                            */
                    743:   GC_bool GC_win32s = FALSE;   /* We're running under win32s.  */
                    744:
                    745:   GC_bool GC_is_win32s()
                    746:   {
                    747:       DWORD v = GetVersion();
                    748:
                    749:       /* Check that this is not NT, and Windows major version <= 3     */
                    750:       return ((v & 0x80000000) && (v & 0xff) <= 3);
                    751:   }
                    752:
                    753:   void GC_init_win32()
                    754:   {
                    755:       GC_win32s = GC_is_win32s();
                    756:   }
                    757:
                    758:   /* Return the smallest address a such that VirtualQuery              */
                    759:   /* returns correct results for all addresses between a and start.    */
                    760:   /* Assumes VirtualQuery returns correct information for start.       */
                    761:   ptr_t GC_least_described_address(ptr_t start)
                    762:   {
                    763:     MEMORY_BASIC_INFORMATION buf;
                    764:     SYSTEM_INFO sysinfo;
                    765:     DWORD result;
                    766:     LPVOID limit;
                    767:     ptr_t p;
                    768:     LPVOID q;
                    769:
                    770:     GetSystemInfo(&sysinfo);
                    771:     limit = sysinfo.lpMinimumApplicationAddress;
                    772:     p = (ptr_t)((word)start & ~(GC_page_size - 1));
                    773:     for (;;) {
                    774:        q = (LPVOID)(p - GC_page_size);
                    775:        if ((ptr_t)q > (ptr_t)p /* underflow */ || q < limit) break;
                    776:        result = VirtualQuery(q, &buf, sizeof(buf));
                    777:        if (result != sizeof(buf) || buf.AllocationBase == 0) break;
                    778:        p = (ptr_t)(buf.AllocationBase);
                    779:     }
                    780:     return(p);
                    781:   }
                    782:
                    783:   /* Is p the start of either the malloc heap, or of one of our */
                    784:   /* heap sections?                                            */
                    785:   GC_bool GC_is_heap_base (ptr_t p)
                    786:   {
                    787:
                    788:      register unsigned i;
                    789:
                    790: #    ifndef REDIRECT_MALLOC
                    791:        static ptr_t malloc_heap_pointer = 0;
                    792:
                    793:        if (0 == malloc_heap_pointer) {
                    794:          MEMORY_BASIC_INFORMATION buf;
                    795:          register DWORD result = VirtualQuery(malloc(1), &buf, sizeof(buf));
                    796:
                    797:          if (result != sizeof(buf)) {
                    798:              ABORT("Weird VirtualQuery result");
                    799:          }
                    800:          malloc_heap_pointer = (ptr_t)(buf.AllocationBase);
                    801:        }
                    802:        if (p == malloc_heap_pointer) return(TRUE);
                    803: #    endif
                    804:      for (i = 0; i < GC_n_heap_bases; i++) {
                    805:          if (GC_heap_bases[i] == p) return(TRUE);
                    806:      }
                    807:      return(FALSE);
                    808:   }
                    809:
                    810:   void GC_register_root_section(ptr_t static_root)
                    811:   {
                    812:       MEMORY_BASIC_INFORMATION buf;
                    813:       SYSTEM_INFO sysinfo;
                    814:       DWORD result;
                    815:       DWORD protect;
                    816:       LPVOID p;
                    817:       char * base;
                    818:       char * limit, * new_limit;
                    819:
                    820:       if (!GC_win32s) return;
                    821:       p = base = limit = GC_least_described_address(static_root);
                    822:       GetSystemInfo(&sysinfo);
                    823:       while (p < sysinfo.lpMaximumApplicationAddress) {
                    824:         result = VirtualQuery(p, &buf, sizeof(buf));
                    825:         if (result != sizeof(buf) || buf.AllocationBase == 0
                    826:             || GC_is_heap_base(buf.AllocationBase)) break;
                    827:         new_limit = (char *)p + buf.RegionSize;
                    828:         protect = buf.Protect;
                    829:         if (buf.State == MEM_COMMIT
                    830:             && is_writable(protect)) {
                    831:             if ((char *)p == limit) {
                    832:                 limit = new_limit;
                    833:             } else {
                    834:                 if (base != limit) GC_add_roots_inner(base, limit, FALSE);
                    835:                 base = p;
                    836:                 limit = new_limit;
                    837:             }
                    838:         }
                    839:         if (p > (LPVOID)new_limit /* overflow */) break;
                    840:         p = (LPVOID)new_limit;
                    841:       }
                    842:       if (base != limit) GC_add_roots_inner(base, limit, FALSE);
                    843:   }
                    844:
                    845:   void GC_register_data_segments()
                    846:   {
                    847:       static char dummy;
                    848:
                    849:       GC_register_root_section((ptr_t)(&dummy));
                    850:   }
                    851: # else
                    852: # ifdef AMIGA
                    853:
                    854:   void GC_register_data_segments()
                    855:   {
                    856:     extern struct WBStartup *_WBenchMsg;
                    857:     struct Process     *proc;
                    858:     struct CommandLineInterface *cli;
                    859:     BPTR myseglist;
                    860:     ULONG *data;
                    861:
                    862:     if ( _WBenchMsg != 0 ) {
                    863:        if ((myseglist = _WBenchMsg->sm_Segment) == 0) {
                    864:            GC_err_puts("No seglist from workbench\n");
                    865:            return;
                    866:        }
                    867:     } else {
                    868:        if ((proc = (struct Process *)FindTask(0)) == 0) {
                    869:            GC_err_puts("Cannot find process structure\n");
                    870:            return;
                    871:        }
                    872:        if ((cli = BADDR(proc->pr_CLI)) == 0) {
                    873:            GC_err_puts("No CLI\n");
                    874:            return;
                    875:        }
                    876:        if ((myseglist = cli->cli_Module) == 0) {
                    877:            GC_err_puts("No seglist from CLI\n");
                    878:            return;
                    879:        }
                    880:     }
                    881:
                    882:     for (data = (ULONG *)BADDR(myseglist); data != 0;
                    883:          data = (ULONG *)BADDR(data[0])) {
                    884: #        ifdef AMIGA_SKIP_SEG
                    885:            if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||
                    886:            ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {
                    887: #       else
                    888:           {
                    889: #       endif /* AMIGA_SKIP_SEG */
                    890:           GC_add_roots_inner((char *)&data[1],
                    891:                             ((char *)&data[1]) + data[-1], FALSE);
                    892:          }
                    893:     }
                    894:   }
                    895:
                    896:
                    897: # else
                    898:
                    899: # if (defined(SVR4) || defined(AUX) || defined(DGUX)) && !defined(PCR)
                    900: char * GC_SysVGetDataStart(max_page_size, etext_addr)
                    901: int max_page_size;
                    902: int * etext_addr;
                    903: {
                    904:     word text_end = ((word)(etext_addr) + sizeof(word) - 1)
                    905:                    & ~(sizeof(word) - 1);
                    906:        /* etext rounded to word boundary       */
                    907:     word next_page = ((text_end + (word)max_page_size - 1)
                    908:                      & ~((word)max_page_size - 1));
                    909:     word page_offset = (text_end & ((word)max_page_size - 1));
                    910:     VOLATILE char * result = (char *)(next_page + page_offset);
                    911:     /* Note that this isnt equivalent to just adding           */
                    912:     /* max_page_size to &etext if &etext is at a page boundary */
                    913:
                    914:     GC_setup_temporary_fault_handler();
                    915:     if (setjmp(GC_jmp_buf) == 0) {
                    916:        /* Try writing to the address.  */
                    917:        *result = *result;
                    918:         GC_reset_fault_handler();
                    919:     } else {
                    920:         GC_reset_fault_handler();
                    921:        /* We got here via a longjmp.  The address is not readable.     */
                    922:        /* This is known to happen under Solaris 2.4 + gcc, which place */
                    923:        /* string constants in the text segment, but after etext.       */
                    924:        /* Use plan B.  Note that we now know there is a gap between    */
                    925:        /* text and data segments, so plan A bought us something.       */
                    926:        result = (char *)GC_find_limit((ptr_t)(DATAEND) - MIN_PAGE_SIZE, FALSE);
                    927:     }
                    928:     return((char *)result);
                    929: }
                    930: # endif
                    931:
                    932:
                    933: void GC_register_data_segments()
                    934: {
                    935: #   if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS)
                    936: #     if defined(REDIRECT_MALLOC) && defined(SOLARIS_THREADS)
                    937:        /* As of Solaris 2.3, the Solaris threads implementation        */
                    938:        /* allocates the data structure for the initial thread with     */
                    939:        /* sbrk at process startup.  It needs to be scanned, so that    */
                    940:        /* we don't lose some malloc allocated data structures          */
                    941:        /* hanging from it.  We're on thin ice here ...                 */
                    942:         extern caddr_t sbrk();
                    943:
                    944:        GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);
                    945: #     else
                    946:        GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE);
                    947: #     endif
                    948: #   endif
                    949: #   if !defined(PCR) && defined(NEXT)
                    950:       GC_add_roots_inner(DATASTART, (char *) get_end(), FALSE);
                    951: #   endif
                    952: #   if defined(MACOS)
                    953:     {
                    954: #   if defined(THINK_C)
                    955:        extern void* GC_MacGetDataStart(void);
                    956:        /* globals begin above stack and end at a5. */
                    957:        GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
                    958:                           (ptr_t)LMGetCurrentA5(), FALSE);
                    959: #   else
                    960: #     if defined(__MWERKS__)
                    961: #       if !__POWERPC__
                    962:          extern void* GC_MacGetDataStart(void);
                    963:          /* MATTHEW: Function to handle Far Globals (CW Pro 3) */
                    964: #         if __option(far_data)
                    965:          extern void* GC_MacGetDataEnd(void);
                    966: #         endif
                    967:          /* globals begin above stack and end at a5. */
                    968:          GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
                    969:                             (ptr_t)LMGetCurrentA5(), FALSE);
                    970:          /* MATTHEW: Handle Far Globals */
                    971: #         if __option(far_data)
                    972:       /* Far globals follow he QD globals: */
                    973:          GC_add_roots_inner((ptr_t)LMGetCurrentA5(),
                    974:                             (ptr_t)GC_MacGetDataEnd(), FALSE);
                    975: #         endif
                    976: #       else
                    977:          extern char __data_start__[], __data_end__[];
                    978:          GC_add_roots_inner((ptr_t)&__data_start__,
                    979:                             (ptr_t)&__data_end__, FALSE);
                    980: #       endif /* __POWERPC__ */
                    981: #     endif /* __MWERKS__ */
                    982: #   endif /* !THINK_C */
                    983:     }
                    984: #   endif /* MACOS */
                    985:
                    986:     /* Dynamic libraries are added at every collection, since they may  */
                    987:     /* change.                                                         */
                    988: }
                    989:
                    990: # endif  /* ! AMIGA */
                    991: # endif  /* ! MSWIN32 */
                    992: # endif  /* ! OS2 */
                    993:
                    994: /*
                    995:  * Auxiliary routines for obtaining memory from OS.
                    996:  */
                    997:
                    998: # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
                    999:        && !defined(MSWIN32) && !defined(MACOS) && !defined(DOS4GW)
                   1000:
                   1001: # ifdef SUNOS4
                   1002:     extern caddr_t sbrk();
                   1003: # endif
                   1004: # ifdef __STDC__
                   1005: #   define SBRK_ARG_T ptrdiff_t
                   1006: # else
                   1007: #   define SBRK_ARG_T int
                   1008: # endif
                   1009:
                   1010: # ifdef RS6000
                   1011: /* The compiler seems to generate speculative reads one past the end of        */
                   1012: /* an allocated object.  Hence we need to make sure that the page      */
                   1013: /* following the last heap page is also mapped.                                */
                   1014: ptr_t GC_unix_get_mem(bytes)
                   1015: word bytes;
                   1016: {
                   1017:     caddr_t cur_brk = (caddr_t)sbrk(0);
                   1018:     caddr_t result;
                   1019:     SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
                   1020:     static caddr_t my_brk_val = 0;
                   1021:
                   1022:     if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */
                   1023:     if (lsbs != 0) {
                   1024:         if((caddr_t)(sbrk(GC_page_size - lsbs)) == (caddr_t)(-1)) return(0);
                   1025:     }
                   1026:     if (cur_brk == my_brk_val) {
                   1027:        /* Use the extra block we allocated last time. */
                   1028:         result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
                   1029:         if (result == (caddr_t)(-1)) return(0);
                   1030:         result -= GC_page_size;
                   1031:     } else {
                   1032:         result = (ptr_t)sbrk(GC_page_size + (SBRK_ARG_T)bytes);
                   1033:         if (result == (caddr_t)(-1)) return(0);
                   1034:     }
                   1035:     my_brk_val = result + bytes + GC_page_size;        /* Always page aligned */
                   1036:     return((ptr_t)result);
                   1037: }
                   1038:
                   1039: #else  /* Not RS6000 */
                   1040:
                   1041: #if defined(USE_MMAP)
                   1042: /* Tested only under IRIX5 and Solaris 2 */
                   1043:
                   1044: #ifdef USE_MMAP_FIXED
                   1045: #   define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
                   1046:        /* Seems to yield better performance on Solaris 2, but can      */
                   1047:        /* be unreliable if something is already mapped at the address. */
                   1048: #else
                   1049: #   define GC_MMAP_FLAGS MAP_PRIVATE
                   1050: #endif
                   1051:
                   1052: ptr_t GC_unix_get_mem(bytes)
                   1053: word bytes;
                   1054: {
                   1055:     static GC_bool initialized = FALSE;
                   1056:     static int fd;
                   1057:     void *result;
                   1058:     static ptr_t last_addr = HEAP_START;
                   1059:
                   1060:     if (!initialized) {
                   1061:        fd = open("/dev/zero", O_RDONLY);
                   1062:        initialized = TRUE;
                   1063:     }
                   1064:     if (bytes & (GC_page_size -1)) ABORT("Bad GET_MEM arg");
                   1065:     result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
                   1066:                  GC_MMAP_FLAGS, fd, 0/* offset */);
                   1067:     if (result == MAP_FAILED) return(0);
                   1068:     last_addr = (ptr_t)result + bytes + GC_page_size - 1;
                   1069:     last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
                   1070:     return((ptr_t)result);
                   1071: }
                   1072:
                   1073: #else /* Not RS6000, not USE_MMAP */
                   1074: ptr_t GC_unix_get_mem(bytes)
                   1075: word bytes;
                   1076: {
                   1077:   ptr_t result;
                   1078: # ifdef IRIX5
                   1079:     /* Bare sbrk isn't thread safe.  Play by malloc rules.     */
                   1080:     /* The equivalent may be needed on other systems as well.  */
                   1081:     __LOCK_MALLOC();
                   1082: # endif
                   1083:   {
                   1084:     ptr_t cur_brk = (ptr_t)sbrk(0);
                   1085:     SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
                   1086:
                   1087:     if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */
                   1088:     if (lsbs != 0) {
                   1089:         if((ptr_t)sbrk(GC_page_size - lsbs) == (ptr_t)(-1)) return(0);
                   1090:     }
                   1091:     result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
                   1092:     if (result == (ptr_t)(-1)) result = 0;
                   1093:   }
                   1094: # ifdef IRIX5
                   1095:     __UNLOCK_MALLOC();
                   1096: # endif
                   1097:   return(result);
                   1098: }
                   1099:
                   1100: #endif /* Not USE_MMAP */
                   1101: #endif /* Not RS6000 */
                   1102:
                   1103: # endif /* UN*X */
                   1104:
                   1105: # ifdef OS2
                   1106:
                   1107: void * os2_alloc(size_t bytes)
                   1108: {
                   1109:     void * result;
                   1110:
                   1111:     if (DosAllocMem(&result, bytes, PAG_EXECUTE | PAG_READ |
                   1112:                                    PAG_WRITE | PAG_COMMIT)
                   1113:                    != NO_ERROR) {
                   1114:        return(0);
                   1115:     }
                   1116:     if (result == 0) return(os2_alloc(bytes));
                   1117:     return(result);
                   1118: }
                   1119:
                   1120: # endif /* OS2 */
                   1121:
                   1122:
                   1123: # ifdef MSWIN32
                   1124: word GC_n_heap_bases = 0;
                   1125:
                   1126: ptr_t GC_win32_get_mem(bytes)
                   1127: word bytes;
                   1128: {
                   1129:     ptr_t result;
                   1130:
                   1131:     if (GC_win32s) {
                   1132:        /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE.    */
                   1133:        /* There are also unconfirmed rumors of other           */
                   1134:        /* problems, so we dodge the issue.                     */
                   1135:         result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);
                   1136:         result = (ptr_t)(((word)result + HBLKSIZE) & ~(HBLKSIZE-1));
                   1137:     } else {
                   1138:         result = (ptr_t) VirtualAlloc(NULL, bytes,
                   1139:                                      MEM_COMMIT | MEM_RESERVE,
                   1140:                                      PAGE_EXECUTE_READWRITE);
                   1141:     }
                   1142:     if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
                   1143:        /* If I read the documentation correctly, this can      */
                   1144:        /* only happen if HBLKSIZE > 64k or not a power of 2.   */
                   1145:     if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
                   1146:     GC_heap_bases[GC_n_heap_bases++] = result;
                   1147:     return(result);
                   1148: }
                   1149:
                   1150: void GC_win32_free_heap ()
                   1151: {
                   1152:     if (GC_win32s) {
                   1153:        while (GC_n_heap_bases > 0) {
                   1154:            GlobalFree (GC_heap_bases[--GC_n_heap_bases]);
                   1155:            GC_heap_bases[GC_n_heap_bases] = 0;
                   1156:        }
                   1157:     }
                   1158: }
                   1159:
                   1160:
                   1161: # endif
                   1162:
                   1163: /* Routine for pushing any additional roots.  In THREADS       */
                   1164: /* environment, this is also responsible for marking from      */
                   1165: /* thread stacks.  In the SRC_M3 case, it also handles         */
                   1166: /* global variables.                                           */
                   1167: #ifndef THREADS
                   1168: void (*GC_push_other_roots)() = 0;
                   1169: #else /* THREADS */
                   1170:
                   1171: # ifdef PCR
                   1172: PCR_ERes GC_push_thread_stack(PCR_Th_T *t, PCR_Any dummy)
                   1173: {
                   1174:     struct PCR_ThCtl_TInfoRep info;
                   1175:     PCR_ERes result;
                   1176:
                   1177:     info.ti_stkLow = info.ti_stkHi = 0;
                   1178:     result = PCR_ThCtl_GetInfo(t, &info);
                   1179:     GC_push_all_stack((ptr_t)(info.ti_stkLow), (ptr_t)(info.ti_stkHi));
                   1180:     return(result);
                   1181: }
                   1182:
                   1183: /* Push the contents of an old object. We treat this as stack  */
                   1184: /* data only becasue that makes it robust against mark stack   */
                   1185: /* overflow.                                                   */
                   1186: PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any data)
                   1187: {
                   1188:     GC_push_all_stack((ptr_t)p, (ptr_t)p + size);
                   1189:     return(PCR_ERes_okay);
                   1190: }
                   1191:
                   1192:
                   1193: void GC_default_push_other_roots()
                   1194: {
                   1195:     /* Traverse data allocated by previous memory managers.            */
                   1196:        {
                   1197:          extern struct PCR_MM_ProcsRep * GC_old_allocator;
                   1198:
                   1199:          if ((*(GC_old_allocator->mmp_enumerate))(PCR_Bool_false,
                   1200:                                                   GC_push_old_obj, 0)
                   1201:              != PCR_ERes_okay) {
                   1202:              ABORT("Old object enumeration failed");
                   1203:          }
                   1204:        }
                   1205:     /* Traverse all thread stacks. */
                   1206:        if (PCR_ERes_IsErr(
                   1207:                 PCR_ThCtl_ApplyToAllOtherThreads(GC_push_thread_stack,0))
                   1208:               || PCR_ERes_IsErr(GC_push_thread_stack(PCR_Th_CurrThread(), 0))) {
                   1209:               ABORT("Thread stack marking failed\n");
                   1210:        }
                   1211: }
                   1212:
                   1213: # endif /* PCR */
                   1214:
                   1215: # ifdef SRC_M3
                   1216:
                   1217: # ifdef ALL_INTERIOR_POINTERS
                   1218:     --> misconfigured
                   1219: # endif
                   1220:
                   1221:
                   1222: extern void ThreadF__ProcessStacks();
                   1223:
                   1224: void GC_push_thread_stack(start, stop)
                   1225: word start, stop;
                   1226: {
                   1227:    GC_push_all_stack((ptr_t)start, (ptr_t)stop + sizeof(word));
                   1228: }
                   1229:
                   1230: /* Push routine with M3 specific calling convention. */
                   1231: GC_m3_push_root(dummy1, p, dummy2, dummy3)
                   1232: word *p;
                   1233: ptr_t dummy1, dummy2;
                   1234: int dummy3;
                   1235: {
                   1236:     word q = *p;
                   1237:
                   1238:     if ((ptr_t)(q) >= GC_least_plausible_heap_addr
                   1239:         && (ptr_t)(q) < GC_greatest_plausible_heap_addr) {
                   1240:         GC_push_one_checked(q,FALSE);
                   1241:     }
                   1242: }
                   1243:
                   1244: /* M3 set equivalent to RTHeap.TracedRefTypes */
                   1245: typedef struct { int elts[1]; }  RefTypeSet;
                   1246: RefTypeSet GC_TracedRefTypes = {{0x1}};
                   1247:
                   1248: /* From finalize.c */
                   1249: extern void GC_push_finalizer_structures();
                   1250:
                   1251: /* From stubborn.c: */
                   1252: # ifdef STUBBORN_ALLOC
                   1253:     extern GC_PTR * GC_changing_list_start;
                   1254: # endif
                   1255:
                   1256:
                   1257: void GC_default_push_other_roots()
                   1258: {
                   1259:     /* Use the M3 provided routine for finding static roots.   */
                   1260:     /* This is a bit dubious, since it presumes no C roots.    */
                   1261:     /* We handle the collector roots explicitly.               */
                   1262:        {
                   1263: #       ifdef STUBBORN_ALLOC
                   1264:            GC_push_one(GC_changing_list_start);
                   1265: #       endif
                   1266:         GC_push_finalizer_structures();
                   1267:         RTMain__GlobalMapProc(GC_m3_push_root, 0, GC_TracedRefTypes);
                   1268:        }
                   1269:        if (GC_words_allocd > 0) {
                   1270:            ThreadF__ProcessStacks(GC_push_thread_stack);
                   1271:        }
                   1272:        /* Otherwise this isn't absolutely necessary, and we have       */
                   1273:        /* startup ordering problems.                                   */
                   1274: }
                   1275:
                   1276: # endif /* SRC_M3 */
                   1277:
                   1278: # if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \
                   1279:      || defined(IRIX_THREADS) || defined(LINUX_THREADS) \
                   1280:      || defined(IRIX_PCR_THREADS)
                   1281:
                   1282: extern void GC_push_all_stacks();
                   1283:
                   1284: void GC_default_push_other_roots()
                   1285: {
                   1286:     GC_push_all_stacks();
                   1287: }
                   1288:
                   1289: # endif /* SOLARIS_THREADS || ... */
                   1290:
                   1291: void (*GC_push_other_roots)() = GC_default_push_other_roots;
                   1292:
                   1293: #endif
                   1294:
                   1295: /*
                   1296:  * Routines for accessing dirty  bits on virtual pages.
                   1297:  * We plan to eventaually implement four strategies for doing so:
                   1298:  * DEFAULT_VDB:        A simple dummy implementation that treats every page
                   1299:  *             as possibly dirty.  This makes incremental collection
                   1300:  *             useless, but the implementation is still correct.
                   1301:  * PCR_VDB:    Use PPCRs virtual dirty bit facility.
                   1302:  * PROC_VDB:   Use the /proc facility for reading dirty bits.  Only
                   1303:  *             works under some SVR4 variants.  Even then, it may be
                   1304:  *             too slow to be entirely satisfactory.  Requires reading
                   1305:  *             dirty bits for entire address space.  Implementations tend
                   1306:  *             to assume that the client is a (slow) debugger.
                   1307:  * MPROTECT_VDB:Protect pages and then catch the faults to keep track of
                   1308:  *             dirtied pages.  The implementation (and implementability)
                   1309:  *             is highly system dependent.  This usually fails when system
                   1310:  *             calls write to a protected page.  We prevent the read system
                   1311:  *             call from doing so.  It is the clients responsibility to
                   1312:  *             make sure that other system calls are similarly protected
                   1313:  *             or write only to the stack.
                   1314:  */
                   1315:
                   1316: GC_bool GC_dirty_maintained = FALSE;
                   1317:
                   1318: # ifdef DEFAULT_VDB
                   1319:
                   1320: /* All of the following assume the allocation lock is held, and        */
                   1321: /* signals are disabled.                                       */
                   1322:
                   1323: /* The client asserts that unallocated pages in the heap are never     */
                   1324: /* written.                                                            */
                   1325:
                   1326: /* Initialize virtual dirty bit implementation.                        */
                   1327: void GC_dirty_init()
                   1328: {
                   1329:     GC_dirty_maintained = TRUE;
                   1330: }
                   1331:
                   1332: /* Retrieve system dirty bits for heap to a local buffer.      */
                   1333: /* Restore the systems notion of which pages are dirty.                */
                   1334: void GC_read_dirty()
                   1335: {}
                   1336:
                   1337: /* Is the HBLKSIZE sized page at h marked dirty in the local buffer?   */
                   1338: /* If the actual page size is different, this returns TRUE if any      */
                   1339: /* of the pages overlapping h are dirty.  This routine may err on the  */
                   1340: /* side of labelling pages as dirty (and this implementation does).    */
                   1341: /*ARGSUSED*/
                   1342: GC_bool GC_page_was_dirty(h)
                   1343: struct hblk *h;
                   1344: {
                   1345:     return(TRUE);
                   1346: }
                   1347:
                   1348: /*
                   1349:  * The following two routines are typically less crucial.  They matter
                   1350:  * most with large dynamic libraries, or if we can't accurately identify
                   1351:  * stacks, e.g. under Solaris 2.X.  Otherwise the following default
                   1352:  * versions are adequate.
                   1353:  */
                   1354:
                   1355: /* Could any valid GC heap pointer ever have been written to this page?        */
                   1356: /*ARGSUSED*/
                   1357: GC_bool GC_page_was_ever_dirty(h)
                   1358: struct hblk *h;
                   1359: {
                   1360:     return(TRUE);
                   1361: }
                   1362:
                   1363: /* Reset the n pages starting at h to "was never dirty" status.        */
                   1364: void GC_is_fresh(h, n)
                   1365: struct hblk *h;
                   1366: word n;
                   1367: {
                   1368: }
                   1369:
                   1370: /* A call hints that h is about to be written. */
                   1371: /* May speed up some dirty bit implementations.        */
                   1372: /*ARGSUSED*/
                   1373: void GC_write_hint(h)
                   1374: struct hblk *h;
                   1375: {
                   1376: }
                   1377:
                   1378: # endif /* DEFAULT_VDB */
                   1379:
                   1380:
                   1381: # ifdef MPROTECT_VDB
                   1382:
                   1383: /*
                   1384:  * See DEFAULT_VDB for interface descriptions.
                   1385:  */
                   1386:
                   1387: /*
                   1388:  * This implementation maintains dirty bits itself by catching write
                   1389:  * faults and keeping track of them.  We assume nobody else catches
                   1390:  * SIGBUS or SIGSEGV.  We assume no write faults occur in system calls
                   1391:  * except as a result of a read system call.  This means clients must
                   1392:  * either ensure that system calls do not touch the heap, or must
                   1393:  * provide their own wrappers analogous to the one for read.
                   1394:  * We assume the page size is a multiple of HBLKSIZE.
                   1395:  * This implementation is currently SunOS 4.X and IRIX 5.X specific, though we
                   1396:  * tried to use portable code where easily possible.  It is known
                   1397:  * not to work under a number of other systems.
                   1398:  */
                   1399:
                   1400: # ifndef MSWIN32
                   1401:
                   1402: #   include <sys/mman.h>
                   1403: #   include <signal.h>
                   1404: #   include <sys/syscall.h>
                   1405:
                   1406: #   define PROTECT(addr, len) \
                   1407:          if (mprotect((caddr_t)(addr), (int)(len), \
                   1408:                       PROT_READ | OPT_PROT_EXEC) < 0) { \
                   1409:            ABORT("mprotect failed"); \
                   1410:          }
                   1411: #   define UNPROTECT(addr, len) \
                   1412:          if (mprotect((caddr_t)(addr), (int)(len), \
                   1413:                       PROT_WRITE | PROT_READ | OPT_PROT_EXEC ) < 0) { \
                   1414:            ABORT("un-mprotect failed"); \
                   1415:          }
                   1416:
                   1417: # else
                   1418:
                   1419: #   include <signal.h>
                   1420:
                   1421:     static DWORD protect_junk;
                   1422: #   define PROTECT(addr, len) \
                   1423:          if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READ, \
                   1424:                              &protect_junk)) { \
                   1425:            DWORD last_error = GetLastError(); \
                   1426:            GC_printf1("Last error code: %lx\n", last_error); \
                   1427:            ABORT("VirtualProtect failed"); \
                   1428:          }
                   1429: #   define UNPROTECT(addr, len) \
                   1430:          if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READWRITE, \
                   1431:                              &protect_junk)) { \
                   1432:            ABORT("un-VirtualProtect failed"); \
                   1433:          }
                   1434:
                   1435: # endif
                   1436:
                   1437: #if defined(SUNOS4) || defined(FREEBSD)
                   1438:     typedef void (* SIG_PF)();
                   1439: #endif
                   1440: #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX)
                   1441:     typedef void (* SIG_PF)(int);
                   1442: #endif
                   1443: #if defined(MSWIN32)
                   1444:     typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
                   1445: #   undef SIG_DFL
                   1446: #   define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER) (-1)
                   1447: #endif
                   1448:
                   1449: #if defined(IRIX5) || defined(OSF1)
                   1450:     typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
                   1451: #endif
                   1452: #if defined(SUNOS5SIGS)
                   1453:     typedef void (* REAL_SIG_PF)(int, struct siginfo *, void *);
                   1454: #endif
                   1455: #if defined(LINUX)
                   1456: #   include <linux/version.h>
                   1457: #   if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA)
                   1458:       typedef struct sigcontext s_c;
                   1459: #   else
                   1460:       typedef struct sigcontext_struct s_c;
                   1461: #   endif
                   1462: #   ifdef ALPHA
                   1463:     typedef void (* REAL_SIG_PF)(int, int, s_c *);
                   1464:     /* Retrieve fault address from sigcontext structure by decoding    */
                   1465:     /* instruction.                                                    */
                   1466:     char * get_fault_addr(s_c *sc) {
                   1467:         unsigned instr;
                   1468:        word faultaddr;
                   1469:
                   1470:        instr = *((unsigned *)(sc->sc_pc));
                   1471:        faultaddr = sc->sc_regs[(instr >> 16) & 0x1f];
                   1472:        faultaddr += (word) (((int)instr << 16) >> 16);
                   1473:        return (char *)faultaddr;
                   1474:     }
                   1475: #   else /* !ALPHA */
                   1476:     typedef void (* REAL_SIG_PF)(int, s_c);
                   1477: #   endif /* !ALPHA */
                   1478: # endif
                   1479:
                   1480: SIG_PF GC_old_bus_handler;
                   1481: SIG_PF GC_old_segv_handler;    /* Also old MSWIN32 ACCESS_VIOLATION filter */
                   1482:
                   1483: /*ARGSUSED*/
                   1484: # if defined (SUNOS4) || defined(FREEBSD)
                   1485:     void GC_write_fault_handler(sig, code, scp, addr)
                   1486:     int sig, code;
                   1487:     struct sigcontext *scp;
                   1488:     char * addr;
                   1489: #   ifdef SUNOS4
                   1490: #     define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
                   1491: #     define CODE_OK (FC_CODE(code) == FC_PROT \
                   1492:                    || (FC_CODE(code) == FC_OBJERR \
                   1493:                       && FC_ERRNO(code) == FC_PROT))
                   1494: #   endif
                   1495: #   ifdef FREEBSD
                   1496: #     define SIG_OK (sig == SIGBUS)
                   1497: #     define CODE_OK (code == BUS_PAGE_FAULT)
                   1498: #   endif
                   1499: # endif
                   1500: # if defined(IRIX5) || defined(OSF1)
                   1501: #   include <errno.h>
                   1502:     void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
                   1503: #   define SIG_OK (sig == SIGSEGV)
                   1504: #   ifdef OSF1
                   1505: #     define CODE_OK (code == 2 /* experimentally determined */)
                   1506: #   endif
                   1507: #   ifdef IRIX5
                   1508: #     define CODE_OK (code == EACCES)
                   1509: #   endif
                   1510: # endif
                   1511: # if defined(LINUX)
                   1512: #   ifdef ALPHA
                   1513:       void GC_write_fault_handler(int sig, int code, s_c * sc)
                   1514: #   else
                   1515:       void GC_write_fault_handler(int sig, s_c sc)
                   1516: #   endif
                   1517: #   define SIG_OK (sig == SIGSEGV)
                   1518: #   define CODE_OK TRUE
                   1519:        /* Empirically c.trapno == 14, but is that useful?      */
                   1520:        /* We assume Intel architecture, so alignment           */
                   1521:        /* faults are not possible.                             */
                   1522: # endif
                   1523: # if defined(SUNOS5SIGS)
                   1524:     void GC_write_fault_handler(int sig, struct siginfo *scp, void * context)
                   1525: #   define SIG_OK (sig == SIGSEGV)
                   1526: #   define CODE_OK (scp -> si_code == SEGV_ACCERR)
                   1527: # endif
                   1528: # if defined(MSWIN32)
                   1529:     LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
                   1530: #   define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \
                   1531:                        EXCEPTION_ACCESS_VIOLATION)
                   1532: #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
                   1533:                        /* Write fault */
                   1534: # endif
                   1535: {
                   1536:     register unsigned i;
                   1537: #   ifdef IRIX5
                   1538:        char * addr = (char *) (size_t) (scp -> sc_badvaddr);
                   1539: #   endif
                   1540: #   if defined(OSF1) && defined(ALPHA)
                   1541:        char * addr = (char *) (scp -> sc_traparg_a0);
                   1542: #   endif
                   1543: #   ifdef SUNOS5SIGS
                   1544:        char * addr = (char *) (scp -> si_addr);
                   1545: #   endif
                   1546: #   ifdef LINUX
                   1547: #     ifdef I386
                   1548:        char * addr = (char *) (sc.cr2);
                   1549: #     else
                   1550: #      if defined(M68K)
                   1551:           char * addr = NULL;
                   1552:
                   1553:          struct sigcontext *scp = (struct sigcontext *)(&sc);
                   1554:
                   1555:          int format = (scp->sc_formatvec >> 12) & 0xf;
                   1556:          unsigned long *framedata = (unsigned long *)(scp + 1);
                   1557:          unsigned long ea;
                   1558:
                   1559:          if (format == 0xa || format == 0xb) {
                   1560:                /* 68020/030 */
                   1561:                ea = framedata[2];
                   1562:          } else if (format == 7) {
                   1563:                /* 68040 */
                   1564:                ea = framedata[3];
                   1565:          } else if (format == 4) {
                   1566:                /* 68060 */
                   1567:                ea = framedata[0];
                   1568:                if (framedata[1] & 0x08000000) {
                   1569:                        /* correct addr on misaligned access */
                   1570:                        ea = (ea+4095)&(~4095);
                   1571:                }
                   1572:          }
                   1573:          addr = (char *)ea;
                   1574: #      else
                   1575: #        ifdef ALPHA
                   1576:             char * addr = get_fault_addr(sc);
                   1577: #        else
                   1578:                --> architecture not supported
                   1579: #        endif
                   1580: #      endif
                   1581: #     endif
                   1582: #   endif
                   1583: #   if defined(MSWIN32)
                   1584:        char * addr = (char *) (exc_info -> ExceptionRecord
                   1585:                                -> ExceptionInformation[1]);
                   1586: #      define sig SIGSEGV
                   1587: #   endif
                   1588:
                   1589:     if (SIG_OK && CODE_OK) {
                   1590:         register struct hblk * h =
                   1591:                        (struct hblk *)((word)addr & ~(GC_page_size-1));
                   1592:         GC_bool in_allocd_block;
                   1593:
                   1594: #      ifdef SUNOS5SIGS
                   1595:            /* Address is only within the correct physical page.        */
                   1596:            in_allocd_block = FALSE;
                   1597:             for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
                   1598:               if (HDR(h+i) != 0) {
                   1599:                 in_allocd_block = TRUE;
                   1600:               }
                   1601:             }
                   1602: #      else
                   1603:            in_allocd_block = (HDR(addr) != 0);
                   1604: #      endif
                   1605:         if (!in_allocd_block) {
                   1606:            /* Heap blocks now begin and end on page boundaries */
                   1607:             SIG_PF old_handler;
                   1608:
                   1609:             if (sig == SIGSEGV) {
                   1610:                old_handler = GC_old_segv_handler;
                   1611:             } else {
                   1612:                 old_handler = GC_old_bus_handler;
                   1613:             }
                   1614:             if (old_handler == SIG_DFL) {
                   1615: #              ifndef MSWIN32
                   1616:                    GC_err_printf1("Segfault at 0x%lx\n", addr);
                   1617:                     ABORT("Unexpected bus error or segmentation fault");
                   1618: #              else
                   1619:                    return(EXCEPTION_CONTINUE_SEARCH);
                   1620: #              endif
                   1621:             } else {
                   1622: #              if defined (SUNOS4) || defined(FREEBSD)
                   1623:                    (*old_handler) (sig, code, scp, addr);
                   1624:                    return;
                   1625: #              endif
                   1626: #              if defined (SUNOS5SIGS)
                   1627:                    (*(REAL_SIG_PF)old_handler) (sig, scp, context);
                   1628:                    return;
                   1629: #              endif
                   1630: #              if defined (LINUX)
                   1631: #                  ifdef ALPHA
                   1632:                        (*(REAL_SIG_PF)old_handler) (sig, code, sc);
                   1633: #                  else
                   1634:                        (*(REAL_SIG_PF)old_handler) (sig, sc);
                   1635: #                  endif
                   1636:                    return;
                   1637: #              endif
                   1638: #              if defined (IRIX5) || defined(OSF1)
                   1639:                    (*(REAL_SIG_PF)old_handler) (sig, code, scp);
                   1640:                    return;
                   1641: #              endif
                   1642: #              ifdef MSWIN32
                   1643:                    return((*old_handler)(exc_info));
                   1644: #              endif
                   1645:             }
                   1646:         }
                   1647:         for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
                   1648:             register int index = PHT_HASH(h+i);
                   1649:
                   1650:             set_pht_entry_from_index(GC_dirty_pages, index);
                   1651:         }
                   1652:         UNPROTECT(h, GC_page_size);
                   1653: #      if defined(OSF1) || defined(LINUX)
                   1654:            /* These reset the signal handler each time by default. */
                   1655:            signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);
                   1656: #      endif
                   1657:        /* The write may not take place before dirty bits are read.     */
                   1658:        /* But then we'll fault again ...                               */
                   1659: #      ifdef MSWIN32
                   1660:            return(EXCEPTION_CONTINUE_EXECUTION);
                   1661: #      else
                   1662:            return;
                   1663: #      endif
                   1664:     }
                   1665: #ifdef MSWIN32
                   1666:     return EXCEPTION_CONTINUE_SEARCH;
                   1667: #else
                   1668:     GC_err_printf1("Segfault at 0x%lx\n", addr);
                   1669:     ABORT("Unexpected bus error or segmentation fault");
                   1670: #endif
                   1671: }
                   1672:
                   1673: /*
                   1674:  * We hold the allocation lock.  We expect block h to be written
                   1675:  * shortly.
                   1676:  */
                   1677: void GC_write_hint(h)
                   1678: struct hblk *h;
                   1679: {
                   1680:     register struct hblk * h_trunc;
                   1681:     register unsigned i;
                   1682:     register GC_bool found_clean;
                   1683:
                   1684:     if (!GC_dirty_maintained) return;
                   1685:     h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));
                   1686:     found_clean = FALSE;
                   1687:     for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
                   1688:         register int index = PHT_HASH(h_trunc+i);
                   1689:
                   1690:         if (!get_pht_entry_from_index(GC_dirty_pages, index)) {
                   1691:             found_clean = TRUE;
                   1692:             set_pht_entry_from_index(GC_dirty_pages, index);
                   1693:         }
                   1694:     }
                   1695:     if (found_clean) {
                   1696:        UNPROTECT(h_trunc, GC_page_size);
                   1697:     }
                   1698: }
                   1699:
                   1700: void GC_dirty_init()
                   1701: {
                   1702: #if defined(SUNOS5SIGS) || defined(IRIX5)
                   1703:     struct sigaction   act, oldact;
                   1704: #   ifdef IRIX5
                   1705:        act.sa_flags    = SA_RESTART;
                   1706:         act.sa_handler  = GC_write_fault_handler;
                   1707: #   else
                   1708:        act.sa_flags    = SA_RESTART | SA_SIGINFO;
                   1709:         act.sa_sigaction = GC_write_fault_handler;
                   1710: #   endif
                   1711:     (void)sigemptyset(&act.sa_mask);
                   1712: #endif
                   1713: #   ifdef PRINTSTATS
                   1714:        GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
                   1715: #   endif
                   1716:     GC_dirty_maintained = TRUE;
                   1717:     if (GC_page_size % HBLKSIZE != 0) {
                   1718:         GC_err_printf0("Page size not multiple of HBLKSIZE\n");
                   1719:         ABORT("Page size not multiple of HBLKSIZE");
                   1720:     }
                   1721: #   if defined(SUNOS4) || defined(FREEBSD)
                   1722:       GC_old_bus_handler = signal(SIGBUS, GC_write_fault_handler);
                   1723:       if (GC_old_bus_handler == SIG_IGN) {
                   1724:         GC_err_printf0("Previously ignored bus error!?");
                   1725:         GC_old_bus_handler = SIG_DFL;
                   1726:       }
                   1727:       if (GC_old_bus_handler != SIG_DFL) {
                   1728: #      ifdef PRINTSTATS
                   1729:           GC_err_printf0("Replaced other SIGBUS handler\n");
                   1730: #      endif
                   1731:       }
                   1732: #   endif
                   1733: #   if defined(OSF1) || defined(SUNOS4) || defined(LINUX)
                   1734:       GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler);
                   1735:       if (GC_old_segv_handler == SIG_IGN) {
                   1736:         GC_err_printf0("Previously ignored segmentation violation!?");
                   1737:         GC_old_segv_handler = SIG_DFL;
                   1738:       }
                   1739:       if (GC_old_segv_handler != SIG_DFL) {
                   1740: #      ifdef PRINTSTATS
                   1741:           GC_err_printf0("Replaced other SIGSEGV handler\n");
                   1742: #      endif
                   1743:       }
                   1744: #   endif
                   1745: #   if defined(SUNOS5SIGS) || defined(IRIX5)
                   1746: #     if defined(IRIX_THREADS) || defined(IRIX_PCR_THREADS)
                   1747:        sigaction(SIGSEGV, 0, &oldact);
                   1748:        sigaction(SIGSEGV, &act, 0);
                   1749: #     else
                   1750:        sigaction(SIGSEGV, &act, &oldact);
                   1751: #     endif
                   1752: #     if defined(_sigargs)
                   1753:        /* This is Irix 5.x, not 6.x.  Irix 5.x does not have   */
                   1754:        /* sa_sigaction.                                        */
                   1755:        GC_old_segv_handler = oldact.sa_handler;
                   1756: #     else /* Irix 6.x or SUNOS5SIGS */
                   1757:         if (oldact.sa_flags & SA_SIGINFO) {
                   1758:           GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction);
                   1759:         } else {
                   1760:           GC_old_segv_handler = oldact.sa_handler;
                   1761:         }
                   1762: #     endif
                   1763:       if (GC_old_segv_handler == SIG_IGN) {
                   1764:             GC_err_printf0("Previously ignored segmentation violation!?");
                   1765:             GC_old_segv_handler = SIG_DFL;
                   1766:       }
                   1767:       if (GC_old_segv_handler != SIG_DFL) {
                   1768: #       ifdef PRINTSTATS
                   1769:          GC_err_printf0("Replaced other SIGSEGV handler\n");
                   1770: #       endif
                   1771:       }
                   1772: #    endif
                   1773: #   if defined(MSWIN32)
                   1774:       GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
                   1775:       if (GC_old_segv_handler != NULL) {
                   1776: #      ifdef PRINTSTATS
                   1777:           GC_err_printf0("Replaced other UnhandledExceptionFilter\n");
                   1778: #      endif
                   1779:       } else {
                   1780:           GC_old_segv_handler = SIG_DFL;
                   1781:       }
                   1782: #   endif
                   1783: }
                   1784:
                   1785:
                   1786:
                   1787: void GC_protect_heap()
                   1788: {
                   1789:     ptr_t start;
                   1790:     word len;
                   1791:     unsigned i;
                   1792:
                   1793:     for (i = 0; i < GC_n_heap_sects; i++) {
                   1794:         start = GC_heap_sects[i].hs_start;
                   1795:         len = GC_heap_sects[i].hs_bytes;
                   1796:         PROTECT(start, len);
                   1797:     }
                   1798: }
                   1799:
                   1800: /* We assume that either the world is stopped or its OK to lose dirty  */
                   1801: /* bits while this is happenning (as in GC_enable_incremental).                */
                   1802: void GC_read_dirty()
                   1803: {
                   1804:     BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
                   1805:           (sizeof GC_dirty_pages));
                   1806:     BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
                   1807:     GC_protect_heap();
                   1808: }
                   1809:
                   1810: GC_bool GC_page_was_dirty(h)
                   1811: struct hblk * h;
                   1812: {
                   1813:     register word index = PHT_HASH(h);
                   1814:
                   1815:     return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
                   1816: }
                   1817:
                   1818: /*
                   1819:  * Acquiring the allocation lock here is dangerous, since this
                   1820:  * can be called from within GC_call_with_alloc_lock, and the cord
                   1821:  * package does so.  On systems that allow nested lock acquisition, this
                   1822:  * happens to work.
                   1823:  * On other systems, SET_LOCK_HOLDER and friends must be suitably defined.
                   1824:  */
                   1825:
                   1826: void GC_begin_syscall()
                   1827: {
                   1828:     if (!I_HOLD_LOCK()) LOCK();
                   1829: }
                   1830:
                   1831: void GC_end_syscall()
                   1832: {
                   1833:     if (!I_HOLD_LOCK()) UNLOCK();
                   1834: }
                   1835:
                   1836: void GC_unprotect_range(addr, len)
                   1837: ptr_t addr;
                   1838: word len;
                   1839: {
                   1840:     struct hblk * start_block;
                   1841:     struct hblk * end_block;
                   1842:     register struct hblk *h;
                   1843:     ptr_t obj_start;
                   1844:
                   1845:     if (!GC_incremental) return;
                   1846:     obj_start = GC_base(addr);
                   1847:     if (obj_start == 0) return;
                   1848:     if (GC_base(addr + len - 1) != obj_start) {
                   1849:         ABORT("GC_unprotect_range(range bigger than object)");
                   1850:     }
                   1851:     start_block = (struct hblk *)((word)addr & ~(GC_page_size - 1));
                   1852:     end_block = (struct hblk *)((word)(addr + len - 1) & ~(GC_page_size - 1));
                   1853:     end_block += GC_page_size/HBLKSIZE - 1;
                   1854:     for (h = start_block; h <= end_block; h++) {
                   1855:         register word index = PHT_HASH(h);
                   1856:
                   1857:         set_pht_entry_from_index(GC_dirty_pages, index);
                   1858:     }
                   1859:     UNPROTECT(start_block,
                   1860:              ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
                   1861: }
                   1862:
                   1863: #ifndef MSWIN32
                   1864: /* Replacement for UNIX system call.    */
                   1865: /* Other calls that write to the heap   */
                   1866: /* should be handled similarly.                 */
                   1867: # if defined(__STDC__) && !defined(SUNOS4)
                   1868: #   include <unistd.h>
                   1869:     ssize_t read(int fd, void *buf, size_t nbyte)
                   1870: # else
                   1871: #   ifndef LINT
                   1872:       int read(fd, buf, nbyte)
                   1873: #   else
                   1874:       int GC_read(fd, buf, nbyte)
                   1875: #   endif
                   1876:     int fd;
                   1877:     char *buf;
                   1878:     int nbyte;
                   1879: # endif
                   1880: {
                   1881:     int result;
                   1882:
                   1883:     GC_begin_syscall();
                   1884:     GC_unprotect_range(buf, (word)nbyte);
                   1885: #   ifdef IRIX5
                   1886:        /* Indirect system call may not always be easily available.     */
                   1887:        /* We could call _read, but that would interfere with the       */
                   1888:        /* libpthread interception of read.                             */
                   1889:        {
                   1890:            struct iovec iov;
                   1891:
                   1892:            iov.iov_base = buf;
                   1893:            iov.iov_len = nbyte;
                   1894:            result = readv(fd, &iov, 1);
                   1895:        }
                   1896: #   else
                   1897:        result = syscall(SYS_read, fd, buf, nbyte);
                   1898: #   endif
                   1899:     GC_end_syscall();
                   1900:     return(result);
                   1901: }
                   1902: #endif /* !MSWIN32 */
                   1903:
                   1904: /*ARGSUSED*/
                   1905: GC_bool GC_page_was_ever_dirty(h)
                   1906: struct hblk *h;
                   1907: {
                   1908:     return(TRUE);
                   1909: }
                   1910:
                   1911: /* Reset the n pages starting at h to "was never dirty" status.        */
                   1912: /*ARGSUSED*/
                   1913: void GC_is_fresh(h, n)
                   1914: struct hblk *h;
                   1915: word n;
                   1916: {
                   1917: }
                   1918:
                   1919: # endif /* MPROTECT_VDB */
                   1920:
                   1921: # ifdef PROC_VDB
                   1922:
                   1923: /*
                   1924:  * See DEFAULT_VDB for interface descriptions.
                   1925:  */
                   1926:
                   1927: /*
                   1928:  * This implementaion assumes a Solaris 2.X like /proc pseudo-file-system
                   1929:  * from which we can read page modified bits.  This facility is far from
                   1930:  * optimal (e.g. we would like to get the info for only some of the
                   1931:  * address space), but it avoids intercepting system calls.
                   1932:  */
                   1933:
                   1934: #include <errno.h>
                   1935: #include <sys/types.h>
                   1936: #include <sys/signal.h>
                   1937: #include <sys/fault.h>
                   1938: #include <sys/syscall.h>
                   1939: #include <sys/procfs.h>
                   1940: #include <sys/stat.h>
                   1941: #include <fcntl.h>
                   1942:
                   1943: #define INITIAL_BUF_SZ 4096
                   1944: word GC_proc_buf_size = INITIAL_BUF_SZ;
                   1945: char *GC_proc_buf;
                   1946:
                   1947: #ifdef SOLARIS_THREADS
                   1948: /* We don't have exact sp values for threads.  So we count on  */
                   1949: /* occasionally declaring stack pages to be fresh.  Thus we    */
                   1950: /* need a real implementation of GC_is_fresh.  We can't clear  */
                   1951: /* entries in GC_written_pages, since that would declare all   */
                   1952: /* pages with the given hash address to be fresh.              */
                   1953: #   define MAX_FRESH_PAGES 8*1024      /* Must be power of 2 */
                   1954:     struct hblk ** GC_fresh_pages;     /* A direct mapped cache.       */
                   1955:                                        /* Collisions are dropped.      */
                   1956:
                   1957: #   define FRESH_PAGE_SLOT(h) (divHBLKSZ((word)(h)) & (MAX_FRESH_PAGES-1))
                   1958: #   define ADD_FRESH_PAGE(h) \
                   1959:        GC_fresh_pages[FRESH_PAGE_SLOT(h)] = (h)
                   1960: #   define PAGE_IS_FRESH(h) \
                   1961:        (GC_fresh_pages[FRESH_PAGE_SLOT(h)] == (h) && (h) != 0)
                   1962: #endif
                   1963:
                   1964: /* Add all pages in pht2 to pht1 */
                   1965: void GC_or_pages(pht1, pht2)
                   1966: page_hash_table pht1, pht2;
                   1967: {
                   1968:     register int i;
                   1969:
                   1970:     for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
                   1971: }
                   1972:
                   1973: int GC_proc_fd;
                   1974:
                   1975: void GC_dirty_init()
                   1976: {
                   1977:     int fd;
                   1978:     char buf[30];
                   1979:
                   1980:     GC_dirty_maintained = TRUE;
                   1981:     if (GC_words_allocd != 0 || GC_words_allocd_before_gc != 0) {
                   1982:        register int i;
                   1983:
                   1984:         for (i = 0; i < PHT_SIZE; i++) GC_written_pages[i] = (word)(-1);
                   1985: #       ifdef PRINTSTATS
                   1986:            GC_printf1("Allocated words:%lu:all pages may have been written\n",
                   1987:                       (unsigned long)
                   1988:                                (GC_words_allocd + GC_words_allocd_before_gc));
                   1989: #      endif
                   1990:     }
                   1991:     sprintf(buf, "/proc/%d", getpid());
                   1992:     fd = open(buf, O_RDONLY);
                   1993:     if (fd < 0) {
                   1994:        ABORT("/proc open failed");
                   1995:     }
                   1996:     GC_proc_fd = syscall(SYS_ioctl, fd, PIOCOPENPD, 0);
                   1997:     close(fd);
                   1998:     if (GC_proc_fd < 0) {
                   1999:        ABORT("/proc ioctl failed");
                   2000:     }
                   2001:     GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
                   2002: #   ifdef SOLARIS_THREADS
                   2003:        GC_fresh_pages = (struct hblk **)
                   2004:          GC_scratch_alloc(MAX_FRESH_PAGES * sizeof (struct hblk *));
                   2005:        if (GC_fresh_pages == 0) {
                   2006:            GC_err_printf0("No space for fresh pages\n");
                   2007:            EXIT();
                   2008:        }
                   2009:        BZERO(GC_fresh_pages, MAX_FRESH_PAGES * sizeof (struct hblk *));
                   2010: #   endif
                   2011: }
                   2012:
                   2013: /* Ignore write hints. They don't help us here.        */
                   2014: /*ARGSUSED*/
                   2015: void GC_write_hint(h)
                   2016: struct hblk *h;
                   2017: {
                   2018: }
                   2019:
                   2020: #ifdef SOLARIS_THREADS
                   2021: #   define READ(fd,buf,nbytes) syscall(SYS_read, fd, buf, nbytes)
                   2022: #else
                   2023: #   define READ(fd,buf,nbytes) read(fd, buf, nbytes)
                   2024: #endif
                   2025:
                   2026: void GC_read_dirty()
                   2027: {
                   2028:     unsigned long ps, np;
                   2029:     int nmaps;
                   2030:     ptr_t vaddr;
                   2031:     struct prasmap * map;
                   2032:     char * bufp;
                   2033:     ptr_t current_addr, limit;
                   2034:     int i;
                   2035: int dummy;
                   2036:
                   2037:     BZERO(GC_grungy_pages, (sizeof GC_grungy_pages));
                   2038:
                   2039:     bufp = GC_proc_buf;
                   2040:     if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
                   2041: #      ifdef PRINTSTATS
                   2042:             GC_printf1("/proc read failed: GC_proc_buf_size = %lu\n",
                   2043:                       GC_proc_buf_size);
                   2044: #      endif
                   2045:         {
                   2046:             /* Retry with larger buffer. */
                   2047:             word new_size = 2 * GC_proc_buf_size;
                   2048:             char * new_buf = GC_scratch_alloc(new_size);
                   2049:
                   2050:             if (new_buf != 0) {
                   2051:                 GC_proc_buf = bufp = new_buf;
                   2052:                 GC_proc_buf_size = new_size;
                   2053:             }
                   2054:             if (syscall(SYS_read, GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
                   2055:                 WARN("Insufficient space for /proc read\n", 0);
                   2056:                 /* Punt:       */
                   2057:                memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
                   2058:                memset(GC_written_pages, 0xff, sizeof(page_hash_table));
                   2059: #              ifdef SOLARIS_THREADS
                   2060:                    BZERO(GC_fresh_pages,
                   2061:                          MAX_FRESH_PAGES * sizeof (struct hblk *));
                   2062: #              endif
                   2063:                return;
                   2064:             }
                   2065:         }
                   2066:     }
                   2067:     /* Copy dirty bits into GC_grungy_pages */
                   2068:        nmaps = ((struct prpageheader *)bufp) -> pr_nmap;
                   2069:        /* printf( "nmaps = %d, PG_REFERENCED = %d, PG_MODIFIED = %d\n",
                   2070:                     nmaps, PG_REFERENCED, PG_MODIFIED); */
                   2071:        bufp = bufp + sizeof(struct prpageheader);
                   2072:        for (i = 0; i < nmaps; i++) {
                   2073:            map = (struct prasmap *)bufp;
                   2074:            vaddr = (ptr_t)(map -> pr_vaddr);
                   2075:            ps = map -> pr_pagesize;
                   2076:            np = map -> pr_npage;
                   2077:            /* printf("vaddr = 0x%X, ps = 0x%X, np = 0x%X\n", vaddr, ps, np); */
                   2078:            limit = vaddr + ps * np;
                   2079:            bufp += sizeof (struct prasmap);
                   2080:            for (current_addr = vaddr;
                   2081:                 current_addr < limit; current_addr += ps){
                   2082:                if ((*bufp++) & PG_MODIFIED) {
                   2083:                    register struct hblk * h = (struct hblk *) current_addr;
                   2084:
                   2085:                    while ((ptr_t)h < current_addr + ps) {
                   2086:                        register word index = PHT_HASH(h);
                   2087:
                   2088:                        set_pht_entry_from_index(GC_grungy_pages, index);
                   2089: #                      ifdef SOLARIS_THREADS
                   2090:                          {
                   2091:                            register int slot = FRESH_PAGE_SLOT(h);
                   2092:
                   2093:                            if (GC_fresh_pages[slot] == h) {
                   2094:                                GC_fresh_pages[slot] = 0;
                   2095:                            }
                   2096:                          }
                   2097: #                      endif
                   2098:                        h++;
                   2099:                    }
                   2100:                }
                   2101:            }
                   2102:            bufp += sizeof(long) - 1;
                   2103:            bufp = (char *)((unsigned long)bufp & ~(sizeof(long)-1));
                   2104:        }
                   2105:     /* Update GC_written_pages. */
                   2106:         GC_or_pages(GC_written_pages, GC_grungy_pages);
                   2107: #   ifdef SOLARIS_THREADS
                   2108:       /* Make sure that old stacks are considered completely clean     */
                   2109:       /* unless written again.                                         */
                   2110:        GC_old_stacks_are_fresh();
                   2111: #   endif
                   2112: }
                   2113:
                   2114: #undef READ
                   2115:
                   2116: GC_bool GC_page_was_dirty(h)
                   2117: struct hblk *h;
                   2118: {
                   2119:     register word index = PHT_HASH(h);
                   2120:     register GC_bool result;
                   2121:
                   2122:     result = get_pht_entry_from_index(GC_grungy_pages, index);
                   2123: #   ifdef SOLARIS_THREADS
                   2124:        if (result && PAGE_IS_FRESH(h)) result = FALSE;
                   2125:        /* This happens only if page was declared fresh since   */
                   2126:        /* the read_dirty call, e.g. because it's in an unused  */
                   2127:        /* thread stack.  It's OK to treat it as clean, in      */
                   2128:        /* that case.  And it's consistent with                 */
                   2129:        /* GC_page_was_ever_dirty.                              */
                   2130: #   endif
                   2131:     return(result);
                   2132: }
                   2133:
                   2134: GC_bool GC_page_was_ever_dirty(h)
                   2135: struct hblk *h;
                   2136: {
                   2137:     register word index = PHT_HASH(h);
                   2138:     register GC_bool result;
                   2139:
                   2140:     result = get_pht_entry_from_index(GC_written_pages, index);
                   2141: #   ifdef SOLARIS_THREADS
                   2142:        if (result && PAGE_IS_FRESH(h)) result = FALSE;
                   2143: #   endif
                   2144:     return(result);
                   2145: }
                   2146:
                   2147: /* Caller holds allocation lock.       */
                   2148: void GC_is_fresh(h, n)
                   2149: struct hblk *h;
                   2150: word n;
                   2151: {
                   2152:
                   2153:     register word index;
                   2154:
                   2155: #   ifdef SOLARIS_THREADS
                   2156:       register word i;
                   2157:
                   2158:       if (GC_fresh_pages != 0) {
                   2159:         for (i = 0; i < n; i++) {
                   2160:           ADD_FRESH_PAGE(h + i);
                   2161:         }
                   2162:       }
                   2163: #   endif
                   2164: }
                   2165:
                   2166: # endif /* PROC_VDB */
                   2167:
                   2168:
                   2169: # ifdef PCR_VDB
                   2170:
                   2171: # include "vd/PCR_VD.h"
                   2172:
                   2173: # define NPAGES (32*1024)      /* 128 MB */
                   2174:
                   2175: PCR_VD_DB  GC_grungy_bits[NPAGES];
                   2176:
                   2177: ptr_t GC_vd_base;      /* Address corresponding to GC_grungy_bits[0]   */
                   2178:                        /* HBLKSIZE aligned.                            */
                   2179:
                   2180: void GC_dirty_init()
                   2181: {
                   2182:     GC_dirty_maintained = TRUE;
                   2183:     /* For the time being, we assume the heap generally grows up */
                   2184:     GC_vd_base = GC_heap_sects[0].hs_start;
                   2185:     if (GC_vd_base == 0) {
                   2186:        ABORT("Bad initial heap segment");
                   2187:     }
                   2188:     if (PCR_VD_Start(HBLKSIZE, GC_vd_base, NPAGES*HBLKSIZE)
                   2189:        != PCR_ERes_okay) {
                   2190:        ABORT("dirty bit initialization failed");
                   2191:     }
                   2192: }
                   2193:
                   2194: void GC_read_dirty()
                   2195: {
                   2196:     /* lazily enable dirty bits on newly added heap sects */
                   2197:     {
                   2198:         static int onhs = 0;
                   2199:         int nhs = GC_n_heap_sects;
                   2200:         for( ; onhs < nhs; onhs++ ) {
                   2201:             PCR_VD_WriteProtectEnable(
                   2202:                     GC_heap_sects[onhs].hs_start,
                   2203:                     GC_heap_sects[onhs].hs_bytes );
                   2204:         }
                   2205:     }
                   2206:
                   2207:
                   2208:     if (PCR_VD_Clear(GC_vd_base, NPAGES*HBLKSIZE, GC_grungy_bits)
                   2209:         != PCR_ERes_okay) {
                   2210:        ABORT("dirty bit read failed");
                   2211:     }
                   2212: }
                   2213:
                   2214: GC_bool GC_page_was_dirty(h)
                   2215: struct hblk *h;
                   2216: {
                   2217:     if((ptr_t)h < GC_vd_base || (ptr_t)h >= GC_vd_base + NPAGES*HBLKSIZE) {
                   2218:        return(TRUE);
                   2219:     }
                   2220:     return(GC_grungy_bits[h - (struct hblk *)GC_vd_base] & PCR_VD_DB_dirtyBit);
                   2221: }
                   2222:
                   2223: /*ARGSUSED*/
                   2224: void GC_write_hint(h)
                   2225: struct hblk *h;
                   2226: {
                   2227:     PCR_VD_WriteProtectDisable(h, HBLKSIZE);
                   2228:     PCR_VD_WriteProtectEnable(h, HBLKSIZE);
                   2229: }
                   2230:
                   2231: # endif /* PCR_VDB */
                   2232:
                   2233: /*
                   2234:  * Call stack save code for debugging.
                   2235:  * Should probably be in mach_dep.c, but that requires reorganization.
                   2236:  */
                   2237: #if defined(SPARC) && !defined(LINUX)
                   2238: #   if defined(SUNOS4)
                   2239: #     include <machine/frame.h>
                   2240: #   else
                   2241: #     if defined (DRSNX)
                   2242: #      include <sys/sparc/frame.h>
                   2243: #     else
                   2244: #       include <sys/frame.h>
                   2245: #     endif
                   2246: #   endif
                   2247: #   if NARGS > 6
                   2248:        --> We only know how to to get the first 6 arguments
                   2249: #   endif
                   2250:
                   2251: #ifdef SAVE_CALL_CHAIN
                   2252: /* Fill in the pc and argument information for up to NFRAMES of my     */
                   2253: /* callers.  Ignore my frame and my callers frame.                     */
                   2254: void GC_save_callers (info)
                   2255: struct callinfo info[NFRAMES];
                   2256: {
                   2257:   struct frame *frame;
                   2258:   struct frame *fp;
                   2259:   int nframes = 0;
                   2260:   word GC_save_regs_in_stack();
                   2261:
                   2262:   frame = (struct frame *) GC_save_regs_in_stack ();
                   2263:
                   2264:   for (fp = frame -> fr_savfp; fp != 0 && nframes < NFRAMES;
                   2265:        fp = fp -> fr_savfp, nframes++) {
                   2266:       register int i;
                   2267:
                   2268:       info[nframes].ci_pc = fp->fr_savpc;
                   2269:       for (i = 0; i < NARGS; i++) {
                   2270:        info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
                   2271:       }
                   2272:   }
                   2273:   if (nframes < NFRAMES) info[nframes].ci_pc = 0;
                   2274: }
                   2275:
                   2276: #endif /* SAVE_CALL_CHAIN */
                   2277: #endif /* SPARC */
                   2278:
                   2279:
                   2280:

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