aboutsummaryrefslogtreecommitdiffstats
path: root/src/alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/alloc.c')
-rw-r--r--src/alloc.c310
1 files changed, 295 insertions, 15 deletions
diff --git a/src/alloc.c b/src/alloc.c
index e783ba581e0..2a539920f22 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -31,6 +31,10 @@ Boston, MA 02111-1307, USA. */
31 31
32#include <signal.h> 32#include <signal.h>
33 33
34#ifdef HAVE_GTK_AND_PTHREAD
35#include <pthread.h>
36#endif
37
34/* This file is part of the core Lisp implementation, and thus must 38/* This file is part of the core Lisp implementation, and thus must
35 deal with the real data structures. If the Lisp implementation is 39 deal with the real data structures. If the Lisp implementation is
36 replaced, this file likely will not be used. */ 40 replaced, this file likely will not be used. */
@@ -85,6 +89,52 @@ extern __malloc_size_t __malloc_extra_blocks;
85 89
86#endif /* not DOUG_LEA_MALLOC */ 90#endif /* not DOUG_LEA_MALLOC */
87 91
92#if ! defined (SYSTEM_MALLOC) && defined (HAVE_GTK_AND_PTHREAD)
93
94/* When GTK uses the file chooser dialog, different backends can be loaded
95 dynamically. One such a backend is the Gnome VFS backend that gets loaded
96 if you run Gnome. That backend creates several threads and also allocates
97 memory with malloc.
98
99 If Emacs sets malloc hooks (! SYSTEM_MALLOC) and the emacs_blocked_*
100 functions below are called from malloc, there is a chance that one
101 of these threads preempts the Emacs main thread and the hook variables
102 end up in a inconsistent state. So we have a mutex to prevent that (note
103 that the backend handles concurrent access to malloc within its own threads
104 but Emacs code running in the main thread is not included in that control).
105
106 When UNBLOCK_INPUT is called, revoke_input_signal may be called. If this
107 happens in one of the backend threads we will have two threads that tries
108 to run Emacs code at once, and the code is not prepared for that.
109 To prevent that, we only call BLOCK/UNBLOCK from the main thread. */
110
111static pthread_mutex_t alloc_mutex;
112pthread_t main_thread;
113
114#define BLOCK_INPUT_ALLOC \
115 do \
116 { \
117 pthread_mutex_lock (&alloc_mutex); \
118 if (pthread_self () == main_thread) \
119 BLOCK_INPUT; \
120 } \
121 while (0)
122#define UNBLOCK_INPUT_ALLOC \
123 do \
124 { \
125 if (pthread_self () == main_thread) \
126 UNBLOCK_INPUT; \
127 pthread_mutex_unlock (&alloc_mutex); \
128 } \
129 while (0)
130
131#else /* SYSTEM_MALLOC || not HAVE_GTK_AND_PTHREAD */
132
133#define BLOCK_INPUT_ALLOC BLOCK_INPUT
134#define UNBLOCK_INPUT_ALLOC UNBLOCK_INPUT
135
136#endif /* SYSTEM_MALLOC || not HAVE_GTK_AND_PTHREAD */
137
88/* Value of _bytes_used, when spare_memory was freed. */ 138/* Value of _bytes_used, when spare_memory was freed. */
89 139
90static __malloc_size_t bytes_used_when_full; 140static __malloc_size_t bytes_used_when_full;
@@ -516,6 +566,140 @@ buffer_memory_full ()
516} 566}
517 567
518 568
569#ifdef XMALLOC_OVERRUN_CHECK
570
571/* Check for overrun in malloc'ed buffers by wrapping a 16 byte header
572 and a 16 byte trailer around each block.
573
574 The header consists of 12 fixed bytes + a 4 byte integer contaning the
575 original block size, while the trailer consists of 16 fixed bytes.
576
577 The header is used to detect whether this block has been allocated
578 through these functions -- as it seems that some low-level libc
579 functions may bypass the malloc hooks.
580*/
581
582
583#define XMALLOC_OVERRUN_CHECK_SIZE 16
584
585static char xmalloc_overrun_check_header[XMALLOC_OVERRUN_CHECK_SIZE-4] =
586 { 0x9a, 0x9b, 0xae, 0xaf,
587 0xbf, 0xbe, 0xce, 0xcf,
588 0xea, 0xeb, 0xec, 0xed };
589
590static char xmalloc_overrun_check_trailer[XMALLOC_OVERRUN_CHECK_SIZE] =
591 { 0xaa, 0xab, 0xac, 0xad,
592 0xba, 0xbb, 0xbc, 0xbd,
593 0xca, 0xcb, 0xcc, 0xcd,
594 0xda, 0xdb, 0xdc, 0xdd };
595
596/* Macros to insert and extract the block size in the header. */
597
598#define XMALLOC_PUT_SIZE(ptr, size) \
599 (ptr[-1] = (size & 0xff), \
600 ptr[-2] = ((size >> 8) & 0xff), \
601 ptr[-3] = ((size >> 16) & 0xff), \
602 ptr[-4] = ((size >> 24) & 0xff))
603
604#define XMALLOC_GET_SIZE(ptr) \
605 (size_t)((unsigned)(ptr[-1]) | \
606 ((unsigned)(ptr[-2]) << 8) | \
607 ((unsigned)(ptr[-3]) << 16) | \
608 ((unsigned)(ptr[-4]) << 24))
609
610
611/* Like malloc, but wraps allocated block with header and trailer. */
612
613POINTER_TYPE *
614overrun_check_malloc (size)
615 size_t size;
616{
617 register unsigned char *val;
618
619 val = (unsigned char *) malloc (size + XMALLOC_OVERRUN_CHECK_SIZE*2);
620 if (val)
621 {
622 bcopy (xmalloc_overrun_check_header, val, XMALLOC_OVERRUN_CHECK_SIZE - 4);
623 val += XMALLOC_OVERRUN_CHECK_SIZE;
624 XMALLOC_PUT_SIZE(val, size);
625 bcopy (xmalloc_overrun_check_trailer, val + size, XMALLOC_OVERRUN_CHECK_SIZE);
626 }
627 return (POINTER_TYPE *)val;
628}
629
630
631/* Like realloc, but checks old block for overrun, and wraps new block
632 with header and trailer. */
633
634POINTER_TYPE *
635overrun_check_realloc (block, size)
636 POINTER_TYPE *block;
637 size_t size;
638{
639 register unsigned char *val = (unsigned char *)block;
640
641 if (val
642 && bcmp (xmalloc_overrun_check_header,
643 val - XMALLOC_OVERRUN_CHECK_SIZE,
644 XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0)
645 {
646 size_t osize = XMALLOC_GET_SIZE (val);
647 if (bcmp (xmalloc_overrun_check_trailer,
648 val + osize,
649 XMALLOC_OVERRUN_CHECK_SIZE))
650 abort ();
651 bzero (val + osize, XMALLOC_OVERRUN_CHECK_SIZE);
652 val -= XMALLOC_OVERRUN_CHECK_SIZE;
653 bzero (val, XMALLOC_OVERRUN_CHECK_SIZE);
654 }
655
656 val = (unsigned char *) realloc ((POINTER_TYPE *)val, size + XMALLOC_OVERRUN_CHECK_SIZE*2);
657
658 if (val)
659 {
660 bcopy (xmalloc_overrun_check_header, val, XMALLOC_OVERRUN_CHECK_SIZE - 4);
661 val += XMALLOC_OVERRUN_CHECK_SIZE;
662 XMALLOC_PUT_SIZE(val, size);
663 bcopy (xmalloc_overrun_check_trailer, val + size, XMALLOC_OVERRUN_CHECK_SIZE);
664 }
665 return (POINTER_TYPE *)val;
666}
667
668/* Like free, but checks block for overrun. */
669
670void
671overrun_check_free (block)
672 POINTER_TYPE *block;
673{
674 unsigned char *val = (unsigned char *)block;
675
676 if (val
677 && bcmp (xmalloc_overrun_check_header,
678 val - XMALLOC_OVERRUN_CHECK_SIZE,
679 XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0)
680 {
681 size_t osize = XMALLOC_GET_SIZE (val);
682 if (bcmp (xmalloc_overrun_check_trailer,
683 val + osize,
684 XMALLOC_OVERRUN_CHECK_SIZE))
685 abort ();
686 bzero (val + osize, XMALLOC_OVERRUN_CHECK_SIZE);
687 val -= XMALLOC_OVERRUN_CHECK_SIZE;
688 bzero (val, XMALLOC_OVERRUN_CHECK_SIZE);
689 }
690
691 free (val);
692}
693
694#undef malloc
695#undef realloc
696#undef free
697#define malloc overrun_check_malloc
698#define realloc overrun_check_realloc
699#define free overrun_check_free
700#endif
701
702
519/* Like malloc but check for no memory and block interrupt input.. */ 703/* Like malloc but check for no memory and block interrupt input.. */
520 704
521POINTER_TYPE * 705POINTER_TYPE *
@@ -602,7 +786,9 @@ safe_alloca_unwind (arg)
602 number of bytes to allocate, TYPE describes the intended use of the 786 number of bytes to allocate, TYPE describes the intended use of the
603 allcated memory block (for strings, for conses, ...). */ 787 allcated memory block (for strings, for conses, ...). */
604 788
789#ifndef USE_LSB_TAG
605static void *lisp_malloc_loser; 790static void *lisp_malloc_loser;
791#endif
606 792
607static POINTER_TYPE * 793static POINTER_TYPE *
608lisp_malloc (nbytes, type) 794lisp_malloc (nbytes, type)
@@ -932,7 +1118,7 @@ static void
932emacs_blocked_free (ptr) 1118emacs_blocked_free (ptr)
933 void *ptr; 1119 void *ptr;
934{ 1120{
935 BLOCK_INPUT; 1121 BLOCK_INPUT_ALLOC;
936 1122
937#ifdef GC_MALLOC_CHECK 1123#ifdef GC_MALLOC_CHECK
938 if (ptr) 1124 if (ptr)
@@ -970,7 +1156,7 @@ emacs_blocked_free (ptr)
970 spare_memory = (char *) malloc ((size_t) SPARE_MEMORY); 1156 spare_memory = (char *) malloc ((size_t) SPARE_MEMORY);
971 1157
972 __free_hook = emacs_blocked_free; 1158 __free_hook = emacs_blocked_free;
973 UNBLOCK_INPUT; 1159 UNBLOCK_INPUT_ALLOC;
974} 1160}
975 1161
976 1162
@@ -996,7 +1182,7 @@ emacs_blocked_malloc (size)
996{ 1182{
997 void *value; 1183 void *value;
998 1184
999 BLOCK_INPUT; 1185 BLOCK_INPUT_ALLOC;
1000 __malloc_hook = old_malloc_hook; 1186 __malloc_hook = old_malloc_hook;
1001#ifdef DOUG_LEA_MALLOC 1187#ifdef DOUG_LEA_MALLOC
1002 mallopt (M_TOP_PAD, malloc_hysteresis * 4096); 1188 mallopt (M_TOP_PAD, malloc_hysteresis * 4096);
@@ -1028,7 +1214,7 @@ emacs_blocked_malloc (size)
1028#endif /* GC_MALLOC_CHECK */ 1214#endif /* GC_MALLOC_CHECK */
1029 1215
1030 __malloc_hook = emacs_blocked_malloc; 1216 __malloc_hook = emacs_blocked_malloc;
1031 UNBLOCK_INPUT; 1217 UNBLOCK_INPUT_ALLOC;
1032 1218
1033 /* fprintf (stderr, "%p malloc\n", value); */ 1219 /* fprintf (stderr, "%p malloc\n", value); */
1034 return value; 1220 return value;
@@ -1044,7 +1230,7 @@ emacs_blocked_realloc (ptr, size)
1044{ 1230{
1045 void *value; 1231 void *value;
1046 1232
1047 BLOCK_INPUT; 1233 BLOCK_INPUT_ALLOC;
1048 __realloc_hook = old_realloc_hook; 1234 __realloc_hook = old_realloc_hook;
1049 1235
1050#ifdef GC_MALLOC_CHECK 1236#ifdef GC_MALLOC_CHECK
@@ -1089,17 +1275,45 @@ emacs_blocked_realloc (ptr, size)
1089#endif /* GC_MALLOC_CHECK */ 1275#endif /* GC_MALLOC_CHECK */
1090 1276
1091 __realloc_hook = emacs_blocked_realloc; 1277 __realloc_hook = emacs_blocked_realloc;
1092 UNBLOCK_INPUT; 1278 UNBLOCK_INPUT_ALLOC;
1093 1279
1094 return value; 1280 return value;
1095} 1281}
1096 1282
1097 1283
1284#ifdef HAVE_GTK_AND_PTHREAD
1285/* Called from Fdump_emacs so that when the dumped Emacs starts, it has a
1286 normal malloc. Some thread implementations need this as they call
1287 malloc before main. The pthread_self call in BLOCK_INPUT_ALLOC then
1288 calls malloc because it is the first call, and we have an endless loop. */
1289
1290void
1291reset_malloc_hooks ()
1292{
1293 __free_hook = 0;
1294 __malloc_hook = 0;
1295 __realloc_hook = 0;
1296}
1297#endif /* HAVE_GTK_AND_PTHREAD */
1298
1299
1098/* Called from main to set up malloc to use our hooks. */ 1300/* Called from main to set up malloc to use our hooks. */
1099 1301
1100void 1302void
1101uninterrupt_malloc () 1303uninterrupt_malloc ()
1102{ 1304{
1305#ifdef HAVE_GTK_AND_PTHREAD
1306 pthread_mutexattr_t attr;
1307
1308 /* GLIBC has a faster way to do this, but lets keep it portable.
1309 This is according to the Single UNIX Specification. */
1310 pthread_mutexattr_init (&attr);
1311 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
1312 pthread_mutex_init (&alloc_mutex, &attr);
1313
1314 main_thread = pthread_self ();
1315#endif /* HAVE_GTK_AND_PTHREAD */
1316
1103 if (__free_hook != emacs_blocked_free) 1317 if (__free_hook != emacs_blocked_free)
1104 old_free_hook = __free_hook; 1318 old_free_hook = __free_hook;
1105 __free_hook = emacs_blocked_free; 1319 __free_hook = emacs_blocked_free;
@@ -1428,6 +1642,21 @@ static int total_string_size;
1428 1642
1429#endif /* not GC_CHECK_STRING_BYTES */ 1643#endif /* not GC_CHECK_STRING_BYTES */
1430 1644
1645
1646#ifdef GC_CHECK_STRING_OVERRUN
1647
1648/* We check for overrun in string data blocks by appending a small
1649 "cookie" after each allocated string data block, and check for the
1650 presense of this cookie during GC. */
1651
1652#define GC_STRING_OVERRUN_COOKIE_SIZE 4
1653static char string_overrun_cookie[GC_STRING_OVERRUN_COOKIE_SIZE] =
1654 { 0xde, 0xad, 0xbe, 0xef };
1655
1656#else
1657#define GC_STRING_OVERRUN_COOKIE_SIZE 0
1658#endif
1659
1431/* Value is the size of an sdata structure large enough to hold NBYTES 1660/* Value is the size of an sdata structure large enough to hold NBYTES
1432 bytes of string data. The value returned includes a terminating 1661 bytes of string data. The value returned includes a terminating
1433 NUL byte, the size of the sdata structure, and padding. */ 1662 NUL byte, the size of the sdata structure, and padding. */
@@ -1451,6 +1680,10 @@ static int total_string_size;
1451 1680
1452#endif /* not GC_CHECK_STRING_BYTES */ 1681#endif /* not GC_CHECK_STRING_BYTES */
1453 1682
1683/* Extra bytes to allocate for each string. */
1684
1685#define GC_STRING_EXTRA (GC_STRING_OVERRUN_COOKIE_SIZE)
1686
1454/* Initialize string allocation. Called from init_alloc_once. */ 1687/* Initialize string allocation. Called from init_alloc_once. */
1455 1688
1456void 1689void
@@ -1515,7 +1748,7 @@ check_sblock (b)
1515 nbytes = SDATA_NBYTES (from); 1748 nbytes = SDATA_NBYTES (from);
1516 1749
1517 nbytes = SDATA_SIZE (nbytes); 1750 nbytes = SDATA_SIZE (nbytes);
1518 from_end = (struct sdata *) ((char *) from + nbytes); 1751 from_end = (struct sdata *) ((char *) from + nbytes + GC_STRING_EXTRA);
1519 } 1752 }
1520} 1753}
1521 1754
@@ -1548,6 +1781,28 @@ check_string_bytes (all_p)
1548 1781
1549#endif /* GC_CHECK_STRING_BYTES */ 1782#endif /* GC_CHECK_STRING_BYTES */
1550 1783
1784#ifdef GC_CHECK_STRING_FREE_LIST
1785
1786/* Walk through the string free list looking for bogus next pointers.
1787 This may catch buffer overrun from a previous string. */
1788
1789static void
1790check_string_free_list ()
1791{
1792 struct Lisp_String *s;
1793
1794 /* Pop a Lisp_String off the free-list. */
1795 s = string_free_list;
1796 while (s != NULL)
1797 {
1798 if ((unsigned)s < 1024)
1799 abort();
1800 s = NEXT_FREE_LISP_STRING (s);
1801 }
1802}
1803#else
1804#define check_string_free_list()
1805#endif
1551 1806
1552/* Return a new Lisp_String. */ 1807/* Return a new Lisp_String. */
1553 1808
@@ -1579,6 +1834,8 @@ allocate_string ()
1579 total_free_strings += STRING_BLOCK_SIZE; 1834 total_free_strings += STRING_BLOCK_SIZE;
1580 } 1835 }
1581 1836
1837 check_string_free_list ();
1838
1582 /* Pop a Lisp_String off the free-list. */ 1839 /* Pop a Lisp_String off the free-list. */
1583 s = string_free_list; 1840 s = string_free_list;
1584 string_free_list = NEXT_FREE_LISP_STRING (s); 1841 string_free_list = NEXT_FREE_LISP_STRING (s);
@@ -1648,7 +1905,7 @@ allocate_string_data (s, nchars, nbytes)
1648 mallopt (M_MMAP_MAX, 0); 1905 mallopt (M_MMAP_MAX, 0);
1649#endif 1906#endif
1650 1907
1651 b = (struct sblock *) lisp_malloc (size, MEM_TYPE_NON_LISP); 1908 b = (struct sblock *) lisp_malloc (size + GC_STRING_EXTRA, MEM_TYPE_NON_LISP);
1652 1909
1653#ifdef DOUG_LEA_MALLOC 1910#ifdef DOUG_LEA_MALLOC
1654 /* Back to a reasonable maximum of mmap'ed areas. */ 1911 /* Back to a reasonable maximum of mmap'ed areas. */
@@ -1663,7 +1920,7 @@ allocate_string_data (s, nchars, nbytes)
1663 else if (current_sblock == NULL 1920 else if (current_sblock == NULL
1664 || (((char *) current_sblock + SBLOCK_SIZE 1921 || (((char *) current_sblock + SBLOCK_SIZE
1665 - (char *) current_sblock->next_free) 1922 - (char *) current_sblock->next_free)
1666 < needed)) 1923 < (needed + GC_STRING_EXTRA)))
1667 { 1924 {
1668 /* Not enough room in the current sblock. */ 1925 /* Not enough room in the current sblock. */
1669 b = (struct sblock *) lisp_malloc (SBLOCK_SIZE, MEM_TYPE_NON_LISP); 1926 b = (struct sblock *) lisp_malloc (SBLOCK_SIZE, MEM_TYPE_NON_LISP);
@@ -1692,7 +1949,11 @@ allocate_string_data (s, nchars, nbytes)
1692 s->size = nchars; 1949 s->size = nchars;
1693 s->size_byte = nbytes; 1950 s->size_byte = nbytes;
1694 s->data[nbytes] = '\0'; 1951 s->data[nbytes] = '\0';
1695 b->next_free = (struct sdata *) ((char *) data + needed); 1952#ifdef GC_CHECK_STRING_OVERRUN
1953 bcopy (string_overrun_cookie, (char *) data + needed,
1954 GC_STRING_OVERRUN_COOKIE_SIZE);
1955#endif
1956 b->next_free = (struct sdata *) ((char *) data + needed + GC_STRING_EXTRA);
1696 1957
1697 /* If S had already data assigned, mark that as free by setting its 1958 /* If S had already data assigned, mark that as free by setting its
1698 string back-pointer to null, and recording the size of the data 1959 string back-pointer to null, and recording the size of the data
@@ -1797,9 +2058,13 @@ sweep_strings ()
1797 } 2058 }
1798 } 2059 }
1799 2060
2061 check_string_free_list ();
2062
1800 string_blocks = live_blocks; 2063 string_blocks = live_blocks;
1801 free_large_strings (); 2064 free_large_strings ();
1802 compact_small_strings (); 2065 compact_small_strings ();
2066
2067 check_string_free_list ();
1803} 2068}
1804 2069
1805 2070
@@ -1871,28 +2136,38 @@ compact_small_strings ()
1871 else 2136 else
1872 nbytes = SDATA_NBYTES (from); 2137 nbytes = SDATA_NBYTES (from);
1873 2138
2139 if (nbytes > LARGE_STRING_BYTES)
2140 abort ();
2141
1874 nbytes = SDATA_SIZE (nbytes); 2142 nbytes = SDATA_SIZE (nbytes);
1875 from_end = (struct sdata *) ((char *) from + nbytes); 2143 from_end = (struct sdata *) ((char *) from + nbytes + GC_STRING_EXTRA);
2144
2145#ifdef GC_CHECK_STRING_OVERRUN
2146 if (bcmp (string_overrun_cookie,
2147 ((char *) from_end) - GC_STRING_OVERRUN_COOKIE_SIZE,
2148 GC_STRING_OVERRUN_COOKIE_SIZE))
2149 abort ();
2150#endif
1876 2151
1877 /* FROM->string non-null means it's alive. Copy its data. */ 2152 /* FROM->string non-null means it's alive. Copy its data. */
1878 if (from->string) 2153 if (from->string)
1879 { 2154 {
1880 /* If TB is full, proceed with the next sblock. */ 2155 /* If TB is full, proceed with the next sblock. */
1881 to_end = (struct sdata *) ((char *) to + nbytes); 2156 to_end = (struct sdata *) ((char *) to + nbytes + GC_STRING_EXTRA);
1882 if (to_end > tb_end) 2157 if (to_end > tb_end)
1883 { 2158 {
1884 tb->next_free = to; 2159 tb->next_free = to;
1885 tb = tb->next; 2160 tb = tb->next;
1886 tb_end = (struct sdata *) ((char *) tb + SBLOCK_SIZE); 2161 tb_end = (struct sdata *) ((char *) tb + SBLOCK_SIZE);
1887 to = &tb->first_data; 2162 to = &tb->first_data;
1888 to_end = (struct sdata *) ((char *) to + nbytes); 2163 to_end = (struct sdata *) ((char *) to + nbytes + GC_STRING_EXTRA);
1889 } 2164 }
1890 2165
1891 /* Copy, and update the string's `data' pointer. */ 2166 /* Copy, and update the string's `data' pointer. */
1892 if (from != to) 2167 if (from != to)
1893 { 2168 {
1894 xassert (tb != b || to <= from); 2169 xassert (tb != b || to <= from);
1895 safe_bcopy ((char *) from, (char *) to, nbytes); 2170 safe_bcopy ((char *) from, (char *) to, nbytes + GC_STRING_EXTRA);
1896 to->string->data = SDATA_DATA (to); 2171 to->string->data = SDATA_DATA (to);
1897 } 2172 }
1898 2173
@@ -2402,9 +2677,9 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0,
2402void 2677void
2403check_cons_list () 2678check_cons_list ()
2404{ 2679{
2680#ifdef GC_CHECK_CONS_LIST
2405 struct Lisp_Cons *tail = cons_free_list; 2681 struct Lisp_Cons *tail = cons_free_list;
2406 2682
2407#if 0
2408 while (tail) 2683 while (tail)
2409 tail = *(struct Lisp_Cons **)&tail->cdr; 2684 tail = *(struct Lisp_Cons **)&tail->cdr;
2410#endif 2685#endif
@@ -4056,6 +4331,11 @@ mark_stack ()
4056#endif 4331#endif
4057 for (i = 0; i < sizeof (Lisp_Object); i += GC_LISP_OBJECT_ALIGNMENT) 4332 for (i = 0; i < sizeof (Lisp_Object); i += GC_LISP_OBJECT_ALIGNMENT)
4058 mark_memory ((char *) stack_base + i, end); 4333 mark_memory ((char *) stack_base + i, end);
4334 /* Allow for marking a secondary stack, like the register stack on the
4335 ia64. */
4336#ifdef GC_MARK_SECONDARY_STACK
4337 GC_MARK_SECONDARY_STACK ();
4338#endif
4059 4339
4060#if GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS 4340#if GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS
4061 check_gcpros (); 4341 check_gcpros ();