/* Storage allocation and gc for GNU Emacs Lisp interpreter.
- Copyright (C) 1985, 86, 88, 93, 94, 95, 97, 98, 1999, 2000
+ Copyright (C) 1985, 86, 88, 93, 94, 95, 97, 98, 1999, 2000, 2001
Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <signal.h>
+/* GC_MALLOC_CHECK defined means perform validity checks of malloc'd
+ memory. Can do this only if using gmalloc.c. */
+
+#if defined SYSTEM_MALLOC || defined DOUG_LEA_MALLOC
+#undef GC_MALLOC_CHECK
+#endif
+
/* This file is part of the core Lisp implementation, and thus must
deal with the real data structures. If the Lisp implementation is
replaced, this file likely will not be used. */
#undef HIDE_LISP_IMPLEMENTATION
#include "lisp.h"
+#include "process.h"
#include "intervals.h"
#include "puresize.h"
#include "buffer.h"
#include "window.h"
+#include "keyboard.h"
#include "frame.h"
#include "blockinput.h"
-#include "keyboard.h"
#include "charset.h"
#include "syssignal.h"
#include <setjmp.h>
-extern char *sbrk ();
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#else
+extern POINTER_TYPE *sbrk ();
+#endif
#ifdef DOUG_LEA_MALLOC
#include <malloc.h>
+/* malloc.h #defines this as size_t, at least in glibc2. */
+#ifndef __malloc_size_t
#define __malloc_size_t int
+#endif
/* Specify maximum number of areas to mmap. It would be nice to use a
value that explicitly means "no limit". */
/* The following come from gmalloc.c. */
-#if defined (STDC_HEADERS)
-#include <stddef.h>
#define __malloc_size_t size_t
-#else
-#define __malloc_size_t unsigned int
-#endif
extern __malloc_size_t _bytes_used;
-extern int __malloc_extra_blocks;
+extern __malloc_size_t __malloc_extra_blocks;
#endif /* not DOUG_LEA_MALLOC */
/* Mark, unmark, query mark bit of a Lisp string. S must be a pointer
to a struct Lisp_String. */
-#define MARK_STRING(S) XMARK ((S)->size)
-#define UNMARK_STRING(S) XUNMARK ((S)->size)
-#define STRING_MARKED_P(S) XMARKBIT ((S)->size)
+#define MARK_STRING(S) ((S)->size |= MARKBIT)
+#define UNMARK_STRING(S) ((S)->size &= ~MARKBIT)
+#define STRING_MARKED_P(S) ((S)->size & MARKBIT)
/* Value is the number of bytes/chars of S, a pointer to a struct
Lisp_String. This must be used instead of STRING_BYTES (S) or
static int malloc_hysteresis;
-/* Nonzero when malloc is called for allocating Lisp object space.
- Currently set but not used. */
-
-int allocating_for_lisp;
-
/* Non-nil means defun should do purecopy on the function definition. */
Lisp_Object Vpurify_flag;
/* Index in pure at which next pure object will be allocated.. */
-int pureptr;
+int pure_bytes_used;
/* If nonzero, this is a warning delivered by malloc and not yet
displayed. */
MEM_TYPE_MISC,
MEM_TYPE_SYMBOL,
MEM_TYPE_FLOAT,
- MEM_TYPE_VECTOR
+ /* Keep the following vector-like types together, with
+ MEM_TYPE_WINDOW being the last, and MEM_TYPE_VECTOR the
+ first. Or change the code of live_vector_p, for instance. */
+ MEM_TYPE_VECTOR,
+ MEM_TYPE_PROCESS,
+ MEM_TYPE_HASH_TABLE,
+ MEM_TYPE_FRAME,
+ MEM_TYPE_WINDOW
};
-#if GC_MARK_STACK
+#if GC_MARK_STACK || defined GC_MALLOC_CHECK
#if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
#include <stdio.h> /* For fprintf. */
Lisp_Object Vdead;
-struct mem_node;
-static void *lisp_malloc P_ ((int, enum mem_type));
+#ifdef GC_MALLOC_CHECK
+
+enum mem_type allocated_mem_type;
+int dont_register_blocks;
+
+#endif /* GC_MALLOC_CHECK */
+
+/* A node in the red-black tree describing allocated memory containing
+ Lisp data. Each such block is recorded with its start and end
+ address when it is allocated, and removed from the tree when it
+ is freed.
+
+ A red-black tree is a balanced binary tree with the following
+ properties:
+
+ 1. Every node is either red or black.
+ 2. Every leaf is black.
+ 3. If a node is red, then both of its children are black.
+ 4. Every simple path from a node to a descendant leaf contains
+ the same number of black nodes.
+ 5. The root is always black.
+
+ When nodes are inserted into the tree, or deleted from the tree,
+ the tree is "fixed" so that these properties are always true.
+
+ A red-black tree with N internal nodes has height at most 2
+ log(N+1). Searches, insertions and deletions are done in O(log N).
+ Please see a text book about data structures for a detailed
+ description of red-black trees. Any book worth its salt should
+ describe them. */
+
+struct mem_node
+{
+ struct mem_node *left, *right, *parent;
+
+ /* Start and end of allocated region. */
+ void *start, *end;
+
+ /* Node color. */
+ enum {MEM_BLACK, MEM_RED} color;
+
+ /* Memory type. */
+ enum mem_type type;
+};
+
+/* Base address of stack. Set in main. */
+
+Lisp_Object *stack_base;
+
+/* Root of the tree describing allocated Lisp memory. */
+
+static struct mem_node *mem_root;
+
+/* Lowest and highest known address in the heap. */
+
+static void *min_heap_address, *max_heap_address;
+
+/* Sentinel node of the tree. */
+
+static struct mem_node mem_z;
+#define MEM_NIL &mem_z
+
+static POINTER_TYPE *lisp_malloc P_ ((size_t, enum mem_type));
+static struct Lisp_Vector *allocate_vectorlike P_ ((EMACS_INT, enum mem_type));
+static void lisp_free P_ ((POINTER_TYPE *));
static void mark_stack P_ ((void));
static void init_stack P_ ((Lisp_Object *));
static int live_vector_p P_ ((struct mem_node *, void *));
static void check_gcpros P_ ((void));
#endif
-#endif /* GC_MARK_STACK != 0 */
+#endif /* GC_MARK_STACK || GC_MALLOC_CHECK */
+
+/* Recording what needs to be marked for gc. */
+
+struct gcpro *gcprolist;
+
+/* Addresses of staticpro'd variables. */
+
+#define NSTATICS 1024
+Lisp_Object *staticvec[NSTATICS] = {0};
+
+/* Index of next unused slot in staticvec. */
+
+int staticidx = 0;
+
+static POINTER_TYPE *pure_alloc P_ ((size_t, int));
+
+
+/* Value is SZ rounded up to the next multiple of ALIGNMENT.
+ ALIGNMENT must be a power of 2. */
+
+#define ALIGN(SZ, ALIGNMENT) \
+ (((SZ) + (ALIGNMENT) - 1) & ~((ALIGNMENT) - 1))
+
\f
/************************************************************************
/* Like malloc but check for no memory and block interrupt input.. */
-long *
+POINTER_TYPE *
xmalloc (size)
- int size;
+ size_t size;
{
- register long *val;
+ register POINTER_TYPE *val;
BLOCK_INPUT;
- val = (long *) malloc (size);
+ val = (POINTER_TYPE *) malloc (size);
UNBLOCK_INPUT;
if (!val && size)
/* Like realloc but check for no memory and block interrupt input.. */
-long *
+POINTER_TYPE *
xrealloc (block, size)
- long *block;
- int size;
+ POINTER_TYPE *block;
+ size_t size;
{
- register long *val;
+ register POINTER_TYPE *val;
BLOCK_INPUT;
/* We must call malloc explicitly when BLOCK is 0, since some
reallocs don't do this. */
if (! block)
- val = (long *) malloc (size);
+ val = (POINTER_TYPE *) malloc (size);
else
- val = (long *) realloc (block, size);
+ val = (POINTER_TYPE *) realloc (block, size);
UNBLOCK_INPUT;
if (!val && size) memory_full ();
void
xfree (block)
- long *block;
+ POINTER_TYPE *block;
{
BLOCK_INPUT;
free (block);
}
+/* Like strdup, but uses xmalloc. */
+
+char *
+xstrdup (s)
+ char *s;
+{
+ size_t len = strlen (s) + 1;
+ char *p = (char *) xmalloc (len);
+ bcopy (s, p, len);
+ return p;
+}
+
+
/* Like malloc but used for allocating Lisp data. NBYTES is the
number of bytes to allocate, TYPE describes the intended use of the
allcated memory block (for strings, for conses, ...). */
-static void *
+static POINTER_TYPE *
lisp_malloc (nbytes, type)
- int nbytes;
+ size_t nbytes;
enum mem_type type;
{
register void *val;
BLOCK_INPUT;
- allocating_for_lisp++;
- val = (void *) malloc (nbytes);
- allocating_for_lisp--;
- UNBLOCK_INPUT;
- if (!val && nbytes)
- memory_full ();
+#ifdef GC_MALLOC_CHECK
+ allocated_mem_type = type;
+#endif
-#if GC_MARK_STACK
- if (type != MEM_TYPE_NON_LISP)
+ val = (void *) malloc (nbytes);
+
+#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
+ if (val && type != MEM_TYPE_NON_LISP)
mem_insert (val, (char *) val + nbytes, type);
#endif
-
+
+ UNBLOCK_INPUT;
+ if (!val && nbytes)
+ memory_full ();
return val;
}
/* Free BLOCK. This must be called to free memory allocated with a
call to lisp_malloc. */
-void
+static void
lisp_free (block)
- long *block;
+ POINTER_TYPE *block;
{
BLOCK_INPUT;
- allocating_for_lisp++;
free (block);
-#if GC_MARK_STACK
+#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
mem_delete (mem_find (block));
#endif
- allocating_for_lisp--;
UNBLOCK_INPUT;
}
GNU malloc. */
#ifndef SYSTEM_MALLOC
-
-extern void * (*__malloc_hook) ();
+#ifndef DOUG_LEA_MALLOC
+extern void * (*__malloc_hook) P_ ((size_t));
+extern void * (*__realloc_hook) P_ ((void *, size_t));
+extern void (*__free_hook) P_ ((void *));
+/* Else declared in malloc.h, perhaps with an extra arg. */
+#endif /* DOUG_LEA_MALLOC */
static void * (*old_malloc_hook) ();
-extern void * (*__realloc_hook) ();
static void * (*old_realloc_hook) ();
-extern void (*__free_hook) ();
static void (*old_free_hook) ();
/* This function is used as the hook for free to call. */
void *ptr;
{
BLOCK_INPUT;
+
+#ifdef GC_MALLOC_CHECK
+ if (ptr)
+ {
+ struct mem_node *m;
+
+ m = mem_find (ptr);
+ if (m == MEM_NIL || m->start != ptr)
+ {
+ fprintf (stderr,
+ "Freeing `%p' which wasn't allocated with malloc\n", ptr);
+ abort ();
+ }
+ else
+ {
+ /* fprintf (stderr, "free %p...%p (%p)\n", m->start, m->end, ptr); */
+ mem_delete (m);
+ }
+ }
+#endif /* GC_MALLOC_CHECK */
+
__free_hook = old_free_hook;
free (ptr);
+
/* If we released our reserve (due to running out of memory),
and we have a fair amount free once again,
try to set aside another reserve in case we run out once more. */
is substantially larger than the block size malloc uses. */
&& (bytes_used_when_full
> BYTES_USED + max (malloc_hysteresis, 4) * SPARE_MEMORY))
- spare_memory = (char *) malloc (SPARE_MEMORY);
+ spare_memory = (char *) malloc ((size_t) SPARE_MEMORY);
__free_hook = emacs_blocked_free;
UNBLOCK_INPUT;
refill_memory_reserve ()
{
if (spare_memory == 0)
- spare_memory = (char *) malloc (SPARE_MEMORY);
+ spare_memory = (char *) malloc ((size_t) SPARE_MEMORY);
}
static void *
emacs_blocked_malloc (size)
- unsigned size;
+ size_t size;
{
void *value;
#else
__malloc_extra_blocks = malloc_hysteresis;
#endif
+
value = (void *) malloc (size);
+
+#ifdef GC_MALLOC_CHECK
+ {
+ struct mem_node *m = mem_find (value);
+ if (m != MEM_NIL)
+ {
+ fprintf (stderr, "Malloc returned %p which is already in use\n",
+ value);
+ fprintf (stderr, "Region in use is %p...%p, %u bytes, type %d\n",
+ m->start, m->end, (char *) m->end - (char *) m->start,
+ m->type);
+ abort ();
+ }
+
+ if (!dont_register_blocks)
+ {
+ mem_insert (value, (char *) value + max (1, size), allocated_mem_type);
+ allocated_mem_type = MEM_TYPE_NON_LISP;
+ }
+ }
+#endif /* GC_MALLOC_CHECK */
+
__malloc_hook = emacs_blocked_malloc;
UNBLOCK_INPUT;
+ /* fprintf (stderr, "%p malloc\n", value); */
return value;
}
static void *
emacs_blocked_realloc (ptr, size)
void *ptr;
- unsigned size;
+ size_t size;
{
void *value;
BLOCK_INPUT;
__realloc_hook = old_realloc_hook;
+
+#ifdef GC_MALLOC_CHECK
+ if (ptr)
+ {
+ struct mem_node *m = mem_find (ptr);
+ if (m == MEM_NIL || m->start != ptr)
+ {
+ fprintf (stderr,
+ "Realloc of %p which wasn't allocated with malloc\n",
+ ptr);
+ abort ();
+ }
+
+ mem_delete (m);
+ }
+
+ /* fprintf (stderr, "%p -> realloc\n", ptr); */
+
+ /* Prevent malloc from registering blocks. */
+ dont_register_blocks = 1;
+#endif /* GC_MALLOC_CHECK */
+
value = (void *) realloc (ptr, size);
+
+#ifdef GC_MALLOC_CHECK
+ dont_register_blocks = 0;
+
+ {
+ struct mem_node *m = mem_find (value);
+ if (m != MEM_NIL)
+ {
+ fprintf (stderr, "Realloc returns memory that is already in use\n");
+ abort ();
+ }
+
+ /* Can't handle zero size regions in the red-black tree. */
+ mem_insert (value, (char *) value + max (size, 1), MEM_TYPE_NON_LISP);
+ }
+
+ /* fprintf (stderr, "%p <- realloc\n", value); */
+#endif /* GC_MALLOC_CHECK */
+
__realloc_hook = emacs_blocked_realloc;
UNBLOCK_INPUT;
} \
} while (0)
-
+\f
+/* Number support. If NO_UNION_TYPE isn't in effect, we
+ can't create number objects in macros. */
+#ifndef make_number
+Lisp_Object
+make_number (n)
+ int n;
+{
+ Lisp_Object obj;
+ obj.s.val = n;
+ obj.s.type = Lisp_Int;
+ return obj;
+}
+#endif
\f
/***********************************************************************
String Allocation
contents. */
struct Lisp_String *string;
+#ifdef GC_CHECK_STRING_BYTES
+
+ EMACS_INT nbytes;
+ unsigned char data[1];
+
+#define SDATA_NBYTES(S) (S)->nbytes
+#define SDATA_DATA(S) (S)->data
+
+#else /* not GC_CHECK_STRING_BYTES */
+
union
{
/* When STRING in non-null. */
/* When STRING is null. */
EMACS_INT nbytes;
} u;
+
+
+#define SDATA_NBYTES(S) (S)->u.nbytes
+#define SDATA_DATA(S) (S)->u.data
+
+#endif /* not GC_CHECK_STRING_BYTES */
};
+
/* Structure describing a block of memory which is sub-allocated to
obtain string data memory for strings. Blocks for small strings
are of fixed size SBLOCK_SIZE. Blocks for large strings are made
a pointer to the `u.data' member of its sdata structure; the
structure starts at a constant offset in front of that. */
+#ifdef GC_CHECK_STRING_BYTES
+
+#define SDATA_OF_STRING(S) \
+ ((struct sdata *) ((S)->data - sizeof (struct Lisp_String *) \
+ - sizeof (EMACS_INT)))
+
+#else /* not GC_CHECK_STRING_BYTES */
+
#define SDATA_OF_STRING(S) \
((struct sdata *) ((S)->data - sizeof (struct Lisp_String *)))
+#endif /* not GC_CHECK_STRING_BYTES */
+
/* Value is the size of an sdata structure large enough to hold NBYTES
bytes of string data. The value returned includes a terminating
NUL byte, the size of the sdata structure, and padding. */
+#ifdef GC_CHECK_STRING_BYTES
+
#define SDATA_SIZE(NBYTES) \
((sizeof (struct Lisp_String *) \
+ (NBYTES) + 1 \
+ + sizeof (EMACS_INT) \
+ sizeof (EMACS_INT) - 1) \
& ~(sizeof (EMACS_INT) - 1))
+#else /* not GC_CHECK_STRING_BYTES */
+
+#define SDATA_SIZE(NBYTES) \
+ ((sizeof (struct Lisp_String *) \
+ + (NBYTES) + 1 \
+ + sizeof (EMACS_INT) - 1) \
+ & ~(sizeof (EMACS_INT) - 1))
+
+#endif /* not GC_CHECK_STRING_BYTES */
/* Initialize string allocation. Called from init_alloc_once. */
}
+#ifdef GC_CHECK_STRING_BYTES
+
+static int check_string_bytes_count;
+
+void check_string_bytes P_ ((int));
+void check_sblock P_ ((struct sblock *));
+
+#define CHECK_STRING_BYTES(S) STRING_BYTES (S)
+
+
+/* Like GC_STRING_BYTES, but with debugging check. */
+
+int
+string_bytes (s)
+ struct Lisp_String *s;
+{
+ int nbytes = (s->size_byte < 0 ? s->size : s->size_byte) & ~MARKBIT;
+ if (!PURE_POINTER_P (s)
+ && s->data
+ && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
+ abort ();
+ return nbytes;
+}
+
+/* Check validity Lisp strings' string_bytes member in B. */
+
+void
+check_sblock (b)
+ struct sblock *b;
+{
+ struct sdata *from, *end, *from_end;
+
+ end = b->next_free;
+
+ for (from = &b->first_data; from < end; from = from_end)
+ {
+ /* Compute the next FROM here because copying below may
+ overwrite data we need to compute it. */
+ int nbytes;
+
+ /* Check that the string size recorded in the string is the
+ same as the one recorded in the sdata structure. */
+ if (from->string)
+ CHECK_STRING_BYTES (from->string);
+
+ if (from->string)
+ nbytes = GC_STRING_BYTES (from->string);
+ else
+ nbytes = SDATA_NBYTES (from);
+
+ nbytes = SDATA_SIZE (nbytes);
+ from_end = (struct sdata *) ((char *) from + nbytes);
+ }
+}
+
+
+/* Check validity of Lisp strings' string_bytes member. ALL_P
+ non-zero means check all strings, otherwise check only most
+ recently allocated strings. Used for hunting a bug. */
+
+void
+check_string_bytes (all_p)
+ int all_p;
+{
+ if (all_p)
+ {
+ struct sblock *b;
+
+ for (b = large_sblocks; b; b = b->next)
+ {
+ struct Lisp_String *s = b->first_data.string;
+ if (s)
+ CHECK_STRING_BYTES (s);
+ }
+
+ for (b = oldest_sblock; b; b = b->next)
+ check_sblock (b);
+ }
+ else
+ check_sblock (current_sblock);
+}
+
+#endif /* GC_CHECK_STRING_BYTES */
+
+
/* Return a new Lisp_String. */
static struct Lisp_String *
++strings_consed;
consing_since_gc += sizeof *s;
+#ifdef GC_CHECK_STRING_BYTES
+ if (!noninteractive
+#ifdef macintosh
+ && current_sblock
+#endif
+ )
+ {
+ if (++check_string_bytes_count == 200)
+ {
+ check_string_bytes_count = 0;
+ check_string_bytes (1);
+ }
+ else
+ check_string_bytes (0);
+ }
+#endif /* GC_CHECK_STRING_BYTES */
+
return s;
}
struct Lisp_String *s;
int nchars, nbytes;
{
- struct sdata *data;
+ struct sdata *data, *old_data;
struct sblock *b;
- int needed;
+ int needed, old_nbytes;
/* Determine the number of bytes needed to store NBYTES bytes
of string data. */
if (nbytes > LARGE_STRING_BYTES)
{
- int size = sizeof *b - sizeof (struct sdata) + needed;
+ size_t size = sizeof *b - sizeof (struct sdata) + needed;
#ifdef DOUG_LEA_MALLOC
- /* Prevent mmap'ing the chunk (which is potentially very large). */
+ /* Prevent mmap'ing the chunk. Lisp data may not be mmap'ed
+ because mapped region contents are not preserved in
+ a dumped Emacs. */
mallopt (M_MMAP_MAX, 0);
#endif
}
else
b = current_sblock;
-
- /* If S had already data assigned, mark that as free by setting
- its string back-pointer to null, and recording the size of
- the data in it.. */
- if (s->data)
- {
- data = SDATA_OF_STRING (s);
- data->u.nbytes = GC_STRING_BYTES (s);
- data->string = NULL;
- }
+
+ old_data = s->data ? SDATA_OF_STRING (s) : NULL;
+ old_nbytes = GC_STRING_BYTES (s);
data = b->next_free;
data->string = s;
- s->data = data->u.data;
+ s->data = SDATA_DATA (data);
+#ifdef GC_CHECK_STRING_BYTES
+ SDATA_NBYTES (data) = nbytes;
+#endif
s->size = nchars;
s->size_byte = nbytes;
s->data[nbytes] = '\0';
b->next_free = (struct sdata *) ((char *) data + needed);
+ /* If S had already data assigned, mark that as free by setting its
+ string back-pointer to null, and recording the size of the data
+ in it. */
+ if (old_data)
+ {
+ SDATA_NBYTES (old_data) = old_nbytes;
+ old_data->string = NULL;
+ }
+
consing_since_gc += needed;
}
/* Save the size of S in its sdata so that we know
how large that is. Reset the sdata's string
back-pointer so that we know it's free. */
+#ifdef GC_CHECK_STRING_BYTES
+ if (GC_STRING_BYTES (s) != SDATA_NBYTES (data))
+ abort ();
+#else
data->u.nbytes = GC_STRING_BYTES (s);
+#endif
data->string = NULL;
/* Reset the strings's `data' member so that we
overwrite data we need to compute it. */
int nbytes;
+#ifdef GC_CHECK_STRING_BYTES
+ /* Check that the string size recorded in the string is the
+ same as the one recorded in the sdata structure. */
+ if (from->string
+ && GC_STRING_BYTES (from->string) != SDATA_NBYTES (from))
+ abort ();
+#endif /* GC_CHECK_STRING_BYTES */
+
if (from->string)
nbytes = GC_STRING_BYTES (from->string);
else
- nbytes = from->u.nbytes;
+ nbytes = SDATA_NBYTES (from);
nbytes = SDATA_SIZE (nbytes);
from_end = (struct sdata *) ((char *) from + nbytes);
/* Copy, and update the string's `data' pointer. */
if (from != to)
{
- bcopy (from, to, nbytes);
- to->string->data = to->u.data;
+ xassert (tb != b || to <= from);
+ safe_bcopy ((char *) from, (char *) to, nbytes);
+ to->string->data = SDATA_DATA (to);
}
/* Advance past the sdata we copied to. */
}
else
{
- unsigned char str[4];
+ unsigned char str[MAX_MULTIBYTE_LENGTH];
int len = CHAR_STRING (c, str);
nbytes = len * XINT (length);
int nbytes;
{
register Lisp_Object val;
- int nchars = chars_in_text (contents, nbytes);
- val = make_uninit_multibyte_string (nchars, nbytes);
- bcopy (contents, XSTRING (val)->data, nbytes);
- if (STRING_BYTES (XSTRING (val)) == XSTRING (val)->size)
- SET_STRING_BYTES (XSTRING (val), -1);
+ int nchars, multibyte_nbytes;
+
+ parse_str_as_multibyte (contents, nbytes, &nchars, &multibyte_nbytes);
+ if (nbytes == nchars || nbytes != multibyte_nbytes)
+ /* CONTENTS contains no multibyte sequences or contains an invalid
+ multibyte sequence. We must make unibyte string. */
+ val = make_unibyte_string (contents, nbytes);
+ else
+ val = make_multibyte_string (contents, nchars, nbytes);
return val;
}
size = XFASTINT (length);
val = Qnil;
- while (size-- > 0)
- val = Fcons (init, val);
+ while (size > 0)
+ {
+ val = Fcons (init, val);
+ --size;
+
+ if (size > 0)
+ {
+ val = Fcons (init, val);
+ --size;
+
+ if (size > 0)
+ {
+ val = Fcons (init, val);
+ --size;
+
+ if (size > 0)
+ {
+ val = Fcons (init, val);
+ --size;
+
+ if (size > 0)
+ {
+ val = Fcons (init, val);
+ --size;
+ }
+ }
+ }
+ }
+
+ QUIT;
+ }
+
return val;
}
Vector Allocation
***********************************************************************/
-/* Singly-linked list of all vectors. */
+/* Singly-linked list of all vectors. */
+
+struct Lisp_Vector *all_vectors;
+
+/* Total number of vector-like objects now in use. */
+
+int n_vectors;
+
+
+/* Value is a pointer to a newly allocated Lisp_Vector structure
+ with room for LEN Lisp_Objects. */
+
+static struct Lisp_Vector *
+allocate_vectorlike (len, type)
+ EMACS_INT len;
+ enum mem_type type;
+{
+ struct Lisp_Vector *p;
+ size_t nbytes;
+
+#ifdef DOUG_LEA_MALLOC
+ /* Prevent mmap'ing the chunk. Lisp data may not be mmap'ed
+ because mapped region contents are not preserved in
+ a dumped Emacs. */
+ mallopt (M_MMAP_MAX, 0);
+#endif
+
+ nbytes = sizeof *p + (len - 1) * sizeof p->contents[0];
+ p = (struct Lisp_Vector *) lisp_malloc (nbytes, type);
+
+#ifdef DOUG_LEA_MALLOC
+ /* Back to a reasonable maximum of mmap'ed areas. */
+ mallopt (M_MMAP_MAX, MMAP_MAX_AREAS);
+#endif
+
+ VALIDATE_LISP_STORAGE (p, 0);
+ consing_since_gc += nbytes;
+ vector_cells_consed += len;
+
+ p->next = all_vectors;
+ all_vectors = p;
+ ++n_vectors;
+ return p;
+}
+
+
+/* Allocate a vector with NSLOTS slots. */
+
+struct Lisp_Vector *
+allocate_vector (nslots)
+ EMACS_INT nslots;
+{
+ struct Lisp_Vector *v = allocate_vectorlike (nslots, MEM_TYPE_VECTOR);
+ v->size = nslots;
+ return v;
+}
+
+
+/* Allocate other vector-like structures. */
+
+struct Lisp_Hash_Table *
+allocate_hash_table ()
+{
+ EMACS_INT len = VECSIZE (struct Lisp_Hash_Table);
+ struct Lisp_Vector *v = allocate_vectorlike (len, MEM_TYPE_HASH_TABLE);
+ EMACS_INT i;
+
+ v->size = len;
+ for (i = 0; i < len; ++i)
+ v->contents[i] = Qnil;
+
+ return (struct Lisp_Hash_Table *) v;
+}
+
+
+struct window *
+allocate_window ()
+{
+ EMACS_INT len = VECSIZE (struct window);
+ struct Lisp_Vector *v = allocate_vectorlike (len, MEM_TYPE_WINDOW);
+ EMACS_INT i;
+
+ for (i = 0; i < len; ++i)
+ v->contents[i] = Qnil;
+ v->size = len;
+
+ return (struct window *) v;
+}
-struct Lisp_Vector *all_vectors;
-/* Total number of vector-like objects now in use. */
+struct frame *
+allocate_frame ()
+{
+ EMACS_INT len = VECSIZE (struct frame);
+ struct Lisp_Vector *v = allocate_vectorlike (len, MEM_TYPE_FRAME);
+ EMACS_INT i;
+
+ for (i = 0; i < len; ++i)
+ v->contents[i] = make_number (0);
+ v->size = len;
+ return (struct frame *) v;
+}
-int n_vectors;
+struct Lisp_Process *
+allocate_process ()
+{
+ EMACS_INT len = VECSIZE (struct Lisp_Process);
+ struct Lisp_Vector *v = allocate_vectorlike (len, MEM_TYPE_PROCESS);
+ EMACS_INT i;
+
+ for (i = 0; i < len; ++i)
+ v->contents[i] = Qnil;
+ v->size = len;
+
+ return (struct Lisp_Process *) v;
+}
-/* Value is a pointer to a newly allocated Lisp_Vector structure
- with room for LEN Lisp_Objects. */
struct Lisp_Vector *
-allocate_vectorlike (len)
+allocate_other_vector (len)
EMACS_INT len;
{
- struct Lisp_Vector *p;
- int nbytes;
-
-#ifdef DOUG_LEA_MALLOC
- /* Prevent mmap'ing the chunk (which is potentially very large).. */
- mallopt (M_MMAP_MAX, 0);
-#endif
-
- nbytes = sizeof *p + (len - 1) * sizeof p->contents[0];
- p = (struct Lisp_Vector *) lisp_malloc (nbytes, MEM_TYPE_VECTOR);
+ struct Lisp_Vector *v = allocate_vectorlike (len, MEM_TYPE_VECTOR);
+ EMACS_INT i;
-#ifdef DOUG_LEA_MALLOC
- /* Back to a reasonable maximum of mmap'ed areas. */
- mallopt (M_MMAP_MAX, MMAP_MAX_AREAS);
-#endif
+ for (i = 0; i < len; ++i)
+ v->contents[i] = Qnil;
+ v->size = len;
- VALIDATE_LISP_STORAGE (p, 0);
- consing_since_gc += nbytes;
- vector_cells_consed += len;
-
- p->next = all_vectors;
- all_vectors = p;
- ++n_vectors;
- return p;
+ return v;
}
CHECK_NATNUM (length, 0);
sizei = XFASTINT (length);
- p = allocate_vectorlike (sizei);
- p->size = sizei;
+ p = allocate_vector (sizei);
for (index = 0; index < sizei; index++)
p->contents[index] = init;
val = make_pure_vector ((EMACS_INT) nargs);
else
val = Fmake_vector (len, Qnil);
+
+ if (STRINGP (args[1]) && STRING_MULTIBYTE (args[1]))
+ /* BYTECODE-STRING must have been produced by Emacs 20.2 or the
+ earlier because they produced a raw 8-bit string for byte-code
+ and now such a byte-code string is loaded as multibyte while
+ raw 8-bit characters converted to multibyte form. Thus, now we
+ must convert them back to the original unibyte form. */
+ args[1] = Fstring_as_unibyte (args[1]);
+
p = XVECTOR (val);
for (index = 0; index < nargs; index++)
{
C Stack Marking
************************************************************************/
-#if GC_MARK_STACK
-
-
-/* Base address of stack. Set in main. */
-
-Lisp_Object *stack_base;
-
-/* A node in the red-black tree describing allocated memory containing
- Lisp data. Each such block is recorded with its start and end
- address when it is allocated, and removed from the tree when it
- is freed.
-
- A red-black tree is a balanced binary tree with the following
- properties:
-
- 1. Every node is either red or black.
- 2. Every leaf is black.
- 3. If a node is red, then both of its children are black.
- 4. Every simple path from a node to a descendant leaf contains
- the same number of black nodes.
- 5. The root is always black.
-
- When nodes are inserted into the tree, or deleted from the tree,
- the tree is "fixed" so that these properties are always true.
-
- A red-black tree with N internal nodes has height at most 2
- log(N+1). Searches, insertions and deletions are done in O(log N).
- Please see a text book about data structures for a detailed
- description of red-black trees. Any book worth its salt should
- describe them. */
-
-struct mem_node
-{
- struct mem_node *left, *right, *parent;
-
- /* Start and end of allocated region. */
- void *start, *end;
-
- /* Node color. */
- enum {MEM_BLACK, MEM_RED} color;
-
- /* Memory type. */
- enum mem_type type;
-};
-
-/* Root of the tree describing allocated Lisp memory. */
-
-static struct mem_node *mem_root;
-
-/* Sentinel node of the tree. */
-
-static struct mem_node mem_z;
-#define MEM_NIL &mem_z
-
+#if GC_MARK_STACK || defined GC_MALLOC_CHECK
/* Initialize this part of alloc.c. */
{
struct mem_node *p;
+ if (start < min_heap_address || start > max_heap_address)
+ return MEM_NIL;
+
/* Make the search always successful to speed up the loop below. */
mem_z.start = start;
mem_z.end = (char *) start + 1;
{
struct mem_node *c, *parent, *x;
+ if (start < min_heap_address)
+ min_heap_address = start;
+ if (end > max_heap_address)
+ max_heap_address = end;
+
/* See where in the tree a node for START belongs. In this
particular application, it shouldn't happen that a node is already
present. For debugging purposes, let's check that. */
#endif /* GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS */
/* Create a new node. */
+#ifdef GC_MALLOC_CHECK
+ x = (struct mem_node *) _malloc_internal (sizeof *x);
+ if (x == NULL)
+ abort ();
+#else
x = (struct mem_node *) xmalloc (sizeof *x);
+#endif
x->start = start;
x->end = end;
x->type = type;
/* Re-establish red-black tree properties. */
mem_insert_fixup (x);
+
return x;
}
if (y->color == MEM_BLACK)
mem_delete_fixup (x);
+
+#ifdef GC_MALLOC_CHECK
+ _free_internal (y);
+#else
xfree (y);
+#endif
}
/* P must point to the start of a Lisp_String structure, and it
must not be on the free-list. */
- return (offset % sizeof b->strings[0] == 0
+ return (offset >= 0
+ && offset % sizeof b->strings[0] == 0
&& ((struct Lisp_String *) p)->data != NULL);
}
else
/* P must point to the start of a Lisp_Cons, not be
one of the unused cells in the current cons block,
and not be on the free-list. */
- return (offset % sizeof b->conses[0] == 0
+ return (offset >= 0
+ && offset % sizeof b->conses[0] == 0
&& (b != cons_block
|| offset / sizeof b->conses[0] < cons_block_index)
&& !EQ (((struct Lisp_Cons *) p)->car, Vdead));
/* P must point to the start of a Lisp_Symbol, not be
one of the unused cells in the current symbol block,
and not be on the free-list. */
- return (offset % sizeof b->symbols[0] == 0
+ return (offset >= 0
+ && offset % sizeof b->symbols[0] == 0
&& (b != symbol_block
|| offset / sizeof b->symbols[0] < symbol_block_index)
&& !EQ (((struct Lisp_Symbol *) p)->function, Vdead));
/* P must point to the start of a Lisp_Float, not be
one of the unused cells in the current float block,
and not be on the free-list. */
- return (offset % sizeof b->floats[0] == 0
+ return (offset >= 0
+ && offset % sizeof b->floats[0] == 0
&& (b != float_block
|| offset / sizeof b->floats[0] < float_block_index)
&& !EQ (((struct Lisp_Float *) p)->type, Vdead));
/* P must point to the start of a Lisp_Misc, not be
one of the unused cells in the current misc block,
and not be on the free-list. */
- return (offset % sizeof b->markers[0] == 0
+ return (offset >= 0
+ && offset % sizeof b->markers[0] == 0
&& (b != marker_block
|| offset / sizeof b->markers[0] < marker_block_index)
&& ((union Lisp_Misc *) p)->u_marker.type != Lisp_Misc_Free);
struct mem_node *m;
void *p;
{
- return m->type == MEM_TYPE_VECTOR && p == m->start;
+ return (p == m->start
+ && m->type >= MEM_TYPE_VECTOR
+ && m->type <= MEM_TYPE_WINDOW);
}
&& !NILP (((struct buffer *) p)->name));
}
+#endif /* GC_MARK_STACK || defined GC_MALLOC_CHECK */
+
+#if GC_MARK_STACK
#if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
}
}
break;
+
+ case Lisp_Int:
+ case Lisp_Type_Limit:
+ break;
}
if (mark_p)
}
}
}
+
+
+/* If P points to Lisp data, mark that as live if it isn't already
+ marked. */
+
+static INLINE void
+mark_maybe_pointer (p)
+ void *p;
+{
+ struct mem_node *m;
+
+ /* Quickly rule out some values which can't point to Lisp data. We
+ assume that Lisp data is aligned on even addresses. */
+ if ((EMACS_INT) p & 1)
+ return;
+
+ m = mem_find (p);
+ if (m != MEM_NIL)
+ {
+ Lisp_Object obj = Qnil;
+
+ switch (m->type)
+ {
+ case MEM_TYPE_NON_LISP:
+ /* Nothing to do; not a pointer to Lisp memory. */
+ break;
+
+ case MEM_TYPE_BUFFER:
+ if (live_buffer_p (m, p)
+ && !XMARKBIT (((struct buffer *) p)->name))
+ XSETVECTOR (obj, p);
+ break;
+
+ case MEM_TYPE_CONS:
+ if (live_cons_p (m, p)
+ && !XMARKBIT (((struct Lisp_Cons *) p)->car))
+ XSETCONS (obj, p);
+ break;
+
+ case MEM_TYPE_STRING:
+ if (live_string_p (m, p)
+ && !STRING_MARKED_P ((struct Lisp_String *) p))
+ XSETSTRING (obj, p);
+ break;
+
+ case MEM_TYPE_MISC:
+ if (live_misc_p (m, p))
+ {
+ Lisp_Object tem;
+ XSETMISC (tem, p);
+
+ switch (XMISCTYPE (tem))
+ {
+ case Lisp_Misc_Marker:
+ if (!XMARKBIT (XMARKER (tem)->chain))
+ obj = tem;
+ break;
+
+ case Lisp_Misc_Buffer_Local_Value:
+ case Lisp_Misc_Some_Buffer_Local_Value:
+ if (!XMARKBIT (XBUFFER_LOCAL_VALUE (tem)->realvalue))
+ obj = tem;
+ break;
+
+ case Lisp_Misc_Overlay:
+ if (!XMARKBIT (XOVERLAY (tem)->plist))
+ obj = tem;
+ break;
+ }
+ }
+ break;
+
+ case MEM_TYPE_SYMBOL:
+ if (live_symbol_p (m, p)
+ && !XMARKBIT (((struct Lisp_Symbol *) p)->plist))
+ XSETSYMBOL (obj, p);
+ break;
+
+ case MEM_TYPE_FLOAT:
+ if (live_float_p (m, p)
+ && !XMARKBIT (((struct Lisp_Float *) p)->type))
+ XSETFLOAT (obj, p);
+ break;
-/* Mark Lisp objects in the address range START..END. */
+ case MEM_TYPE_VECTOR:
+ case MEM_TYPE_PROCESS:
+ case MEM_TYPE_HASH_TABLE:
+ case MEM_TYPE_FRAME:
+ case MEM_TYPE_WINDOW:
+ if (live_vector_p (m, p))
+ {
+ Lisp_Object tem;
+ XSETVECTOR (tem, p);
+ if (!GC_SUBRP (tem)
+ && !(XVECTOR (tem)->size & ARRAY_MARK_FLAG))
+ obj = tem;
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (!GC_NILP (obj))
+ mark_object (&obj);
+ }
+}
+
+
+/* Mark Lisp objects referenced from the address range START..END. */
static void
mark_memory (start, end)
void *start, *end;
{
Lisp_Object *p;
+ void **pp;
#if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
nzombies = 0;
start = end;
end = tem;
}
-
+
+ /* Mark Lisp_Objects. */
for (p = (Lisp_Object *) start; (void *) p < end; ++p)
mark_maybe_object (*p);
+
+ /* Mark Lisp data pointed to. This is necessary because, in some
+ situations, the C compiler optimizes Lisp objects away, so that
+ only a pointer to them remains. Example:
+
+ DEFUN ("testme", Ftestme, Stestme, 0, 0, 0, "")
+ ()
+ {
+ Lisp_Object obj = build_string ("test");
+ struct Lisp_String *s = XSTRING (obj);
+ Fgarbage_collect ();
+ fprintf (stderr, "test `%s'\n", s->data);
+ return Qnil;
+ }
+
+ Here, `obj' isn't really used, and the compiler optimizes it
+ away. The only reference to the life string is through the
+ pointer `s'. */
+
+ for (pp = (void **) start; (void *) pp < end; ++pp)
+ mark_maybe_pointer (*pp);
}
mark_stack ()
{
jmp_buf j;
- int stack_grows_down_p = (char *) &j > (char *) stack_base;
+ volatile int stack_grows_down_p = (char *) &j > (char *) stack_base;
void *end;
/* This trick flushes the register windows so that all the state of
Pure Storage Management
***********************************************************************/
+/* Allocate room for SIZE bytes from pure Lisp storage and return a
+ pointer to it. TYPE is the Lisp type for which the memory is
+ allocated. TYPE < 0 means it's not used for a Lisp object.
+
+ If store_pure_type_info is set and TYPE is >= 0, the type of
+ the allocated object is recorded in pure_types. */
+
+static POINTER_TYPE *
+pure_alloc (size, type)
+ size_t size;
+ int type;
+{
+ size_t nbytes;
+ POINTER_TYPE *result;
+ char *beg = PUREBEG;
+
+ /* Give Lisp_Floats an extra alignment. */
+ if (type == Lisp_Float)
+ {
+ size_t alignment;
+#if defined __GNUC__ && __GNUC__ >= 2
+ alignment = __alignof (struct Lisp_Float);
+#else
+ alignment = sizeof (struct Lisp_Float);
+#endif
+ pure_bytes_used = ALIGN (pure_bytes_used, alignment);
+ }
+
+ nbytes = ALIGN (size, sizeof (EMACS_INT));
+ if (pure_bytes_used + nbytes > PURESIZE)
+ error ("Pure Lisp storage exhausted");
+
+ result = (POINTER_TYPE *) (beg + pure_bytes_used);
+ pure_bytes_used += nbytes;
+ return result;
+}
+
+
/* Return a string allocated in pure space. DATA is a buffer holding
NCHARS characters, and NBYTES bytes of string data. MULTIBYTE
non-zero means make the result string multibyte.
{
Lisp_Object string;
struct Lisp_String *s;
- int string_size, data_size;
-
-#define PAD(SZ) (((SZ) + sizeof (EMACS_INT) - 1) & ~(sizeof (EMACS_INT) - 1))
- string_size = PAD (sizeof (struct Lisp_String));
- data_size = PAD (nbytes + 1);
-
-#undef PAD
-
- if (pureptr + string_size + data_size > PURESIZE)
- error ("Pure Lisp storage exhausted");
-
- s = (struct Lisp_String *) (PUREBEG + pureptr);
- pureptr += string_size;
- s->data = (unsigned char *) (PUREBEG + pureptr);
- pureptr += data_size;
-
+ s = (struct Lisp_String *) pure_alloc (sizeof *s, Lisp_String);
+ s->data = (unsigned char *) pure_alloc (nbytes + 1, -1);
s->size = nchars;
s->size_byte = multibyte ? nbytes : -1;
bcopy (data, s->data, nbytes);
s->data[nbytes] = '\0';
s->intervals = NULL_INTERVAL;
-
XSETSTRING (string, s);
return string;
}
Lisp_Object car, cdr;
{
register Lisp_Object new;
+ struct Lisp_Cons *p;
- if (pureptr + sizeof (struct Lisp_Cons) > PURESIZE)
- error ("Pure Lisp storage exhausted");
- XSETCONS (new, PUREBEG + pureptr);
- pureptr += sizeof (struct Lisp_Cons);
+ p = (struct Lisp_Cons *) pure_alloc (sizeof *p, Lisp_Cons);
+ XSETCONS (new, p);
XCAR (new) = Fpurecopy (car);
XCDR (new) = Fpurecopy (cdr);
return new;
double num;
{
register Lisp_Object new;
+ struct Lisp_Float *p;
- /* Make sure that PUREBEG + pureptr is aligned on at least a sizeof
- (double) boundary. Some architectures (like the sparc) require
- this, and I suspect that floats are rare enough that it's no
- tragedy for those that do. */
- {
- int alignment;
- char *p = PUREBEG + pureptr;
-
-#ifdef __GNUC__
-#if __GNUC__ >= 2
- alignment = __alignof (struct Lisp_Float);
-#else
- alignment = sizeof (struct Lisp_Float);
-#endif
-#else
- alignment = sizeof (struct Lisp_Float);
-#endif
- p = (char *) (((unsigned long) p + alignment - 1) & - alignment);
- pureptr = p - PUREBEG;
- }
-
- if (pureptr + sizeof (struct Lisp_Float) > PURESIZE)
- error ("Pure Lisp storage exhausted");
- XSETFLOAT (new, PUREBEG + pureptr);
- pureptr += sizeof (struct Lisp_Float);
+ p = (struct Lisp_Float *) pure_alloc (sizeof *p, Lisp_Float);
+ XSETFLOAT (new, p);
XFLOAT_DATA (new) = num;
- XSETFASTINT (XFLOAT (new)->type, 0); /* bug chasing -wsr */
return new;
}
make_pure_vector (len)
EMACS_INT len;
{
- register Lisp_Object new;
- register EMACS_INT size = (sizeof (struct Lisp_Vector)
- + (len - 1) * sizeof (Lisp_Object));
-
- if (pureptr + size > PURESIZE)
- error ("Pure Lisp storage exhausted");
+ Lisp_Object new;
+ struct Lisp_Vector *p;
+ size_t size = sizeof *p + (len - 1) * sizeof (Lisp_Object);
- XSETVECTOR (new, PUREBEG + pureptr);
- pureptr += size;
+ p = (struct Lisp_Vector *) pure_alloc (size, Lisp_Vectorlike);
+ XSETVECTOR (new, p);
XVECTOR (new)->size = len;
return new;
}
if (NILP (Vpurify_flag))
return obj;
- if ((PNTR_COMPARISON_TYPE) XPNTR (obj) < (PNTR_COMPARISON_TYPE) ((char *) pure + PURESIZE)
- && (PNTR_COMPARISON_TYPE) XPNTR (obj) >= (PNTR_COMPARISON_TYPE) pure)
+ if (PURE_POINTER_P (XPNTR (obj)))
return obj;
if (CONSP (obj))
}
else if (MARKERP (obj))
error ("Attempt to copy a marker to pure storage");
- else
- return obj;
+
+ return obj;
}
Protection from GC
***********************************************************************/
-/* Recording what needs to be marked for gc. */
-
-struct gcpro *gcprolist;
-
-/* Addresses of staticpro'd variables. */
-
-#define NSTATICS 1024
-Lisp_Object *staticvec[NSTATICS] = {0};
-
-/* Index of next unused slot in staticvec. */
-
-int staticidx = 0;
-
-
/* Put an entry in staticvec, pointing at the variable with address
VARADDRESS. */
Returns info on amount of space in use:\n\
((USED-CONSES . FREE-CONSES) (USED-SYMS . FREE-SYMS)\n\
(USED-MARKERS . FREE-MARKERS) USED-STRING-CHARS USED-VECTOR-SLOTS\n\
- (USED-FLOATS . FREE-FLOATS) (USED-INTERVALS . FREE-INTERVALS\n\
+ (USED-FLOATS . FREE-FLOATS) (USED-INTERVALS . FREE-INTERVALS)\n\
(USED-STRINGS . FREE-STRINGS))\n\
Garbage collection happens automatically if you cons more than\n\
`gc-cons-threshold' bytes of Lisp data since previous garbage collection.")
char stack_top_variable;
register int i;
int message_p;
- Lisp_Object total[7];
+ Lisp_Object total[8];
+ int count = BINDING_STACK_SIZE ();
/* In case user calls debug_print during GC,
don't let that cause a recursive GC. */
/* Save what's currently displayed in the echo area. */
message_p = push_message ();
+ record_unwind_protect (push_message_unwind, Qnil);
/* Save a copy of the contents of the stack, for debugging. */
#if MAX_SAVE_STACK > 0
for (i = 0; i < tail->nvars; i++)
if (!XMARKBIT (tail->var[i]))
{
- mark_object (&tail->var[i]);
+ /* Explicit casting prevents compiler warning about
+ discarding the `volatile' qualifier. */
+ mark_object ((Lisp_Object *)&tail->var[i]);
XMARK (tail->var[i]);
}
#endif
message1_nolog ("Garbage collecting...done");
}
- pop_message ();
+ unbind_to (count, Qnil);
total[0] = Fcons (make_number (total_conses),
make_number (total_free_conses));
make_number (total_free_symbols));
total[2] = Fcons (make_number (total_markers),
make_number (total_free_markers));
- total[3] = Fcons (make_number (total_string_size),
- make_number (total_vector_size));
- total[4] = Fcons (make_number (total_floats),
+ total[3] = make_number (total_string_size);
+ total[4] = make_number (total_vector_size);
+ total[5] = Fcons (make_number (total_floats),
make_number (total_free_floats));
- total[5] = Fcons (make_number (total_intervals),
+ total[6] = Fcons (make_number (total_intervals),
make_number (total_free_intervals));
- total[6] = Fcons (make_number (total_strings),
+ total[7] = Fcons (make_number (total_strings),
make_number (total_free_strings));
#if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
}
#endif
- return Flist (7, total);
+ return Flist (sizeof total / sizeof *total, total);
}
{
Lisp_Object *objptr = argptr;
register Lisp_Object obj;
+#ifdef GC_CHECK_MARKED_OBJECTS
+ void *po;
+ struct mem_node *m;
+#endif
loop:
obj = *objptr;
loop2:
XUNMARK (obj);
- if (PURE_POINTER_P ((PNTR_COMPARISON_TYPE) XPNTR (obj)))
+ if (PURE_POINTER_P (XPNTR (obj)))
return;
last_marked[last_marked_index++] = objptr;
if (last_marked_index == LAST_MARKED_SIZE)
last_marked_index = 0;
+ /* Perform some sanity checks on the objects marked here. Abort if
+ we encounter an object we know is bogus. This increases GC time
+ by ~80%, and requires compilation with GC_MARK_STACK != 0. */
+#ifdef GC_CHECK_MARKED_OBJECTS
+
+ po = (void *) XPNTR (obj);
+
+ /* Check that the object pointed to by PO is known to be a Lisp
+ structure allocated from the heap. */
+#define CHECK_ALLOCATED() \
+ do { \
+ m = mem_find (po); \
+ if (m == MEM_NIL) \
+ abort (); \
+ } while (0)
+
+ /* Check that the object pointed to by PO is live, using predicate
+ function LIVEP. */
+#define CHECK_LIVE(LIVEP) \
+ do { \
+ if (!LIVEP (m, po)) \
+ abort (); \
+ } while (0)
+
+ /* Check both of the above conditions. */
+#define CHECK_ALLOCATED_AND_LIVE(LIVEP) \
+ do { \
+ CHECK_ALLOCATED (); \
+ CHECK_LIVE (LIVEP); \
+ } while (0) \
+
+#else /* not GC_CHECK_MARKED_OBJECTS */
+
+#define CHECK_ALLOCATED() (void) 0
+#define CHECK_LIVE(LIVEP) (void) 0
+#define CHECK_ALLOCATED_AND_LIVE(LIVEP) (void) 0
+
+#endif /* not GC_CHECK_MARKED_OBJECTS */
+
switch (SWITCH_ENUM_CAST (XGCTYPE (obj)))
{
case Lisp_String:
{
register struct Lisp_String *ptr = XSTRING (obj);
+ CHECK_ALLOCATED_AND_LIVE (live_string_p);
MARK_INTERVAL_TREE (ptr->intervals);
MARK_STRING (ptr);
+#ifdef GC_CHECK_STRING_BYTES
+ /* Check that the string size recorded in the string is the
+ same as the one recorded in the sdata structure. */
+ CHECK_STRING_BYTES (ptr);
+#endif /* GC_CHECK_STRING_BYTES */
}
break;
case Lisp_Vectorlike:
+#ifdef GC_CHECK_MARKED_OBJECTS
+ m = mem_find (po);
+ if (m == MEM_NIL && !GC_SUBRP (obj)
+ && po != &buffer_defaults
+ && po != &buffer_local_symbols)
+ abort ();
+#endif /* GC_CHECK_MARKED_OBJECTS */
+
if (GC_BUFFERP (obj))
{
if (!XMARKBIT (XBUFFER (obj)->name))
- mark_buffer (obj);
+ {
+#ifdef GC_CHECK_MARKED_OBJECTS
+ if (po != &buffer_defaults && po != &buffer_local_symbols)
+ {
+ struct buffer *b;
+ for (b = all_buffers; b && b != po; b = b->next)
+ ;
+ if (b == NULL)
+ abort ();
+ }
+#endif /* GC_CHECK_MARKED_OBJECTS */
+ mark_buffer (obj);
+ }
}
else if (GC_SUBRP (obj))
break;
{
register struct Lisp_Vector *ptr = XVECTOR (obj);
register EMACS_INT size = ptr->size;
- /* See comment above under Lisp_Vector. */
- struct Lisp_Vector *volatile ptr1 = ptr;
register int i;
if (size & ARRAY_MARK_FLAG)
break; /* Already marked */
+
+ CHECK_LIVE (live_vector_p);
ptr->size |= ARRAY_MARK_FLAG; /* Else mark it */
size &= PSEUDOVECTOR_SIZE_MASK;
for (i = 0; i < size; i++) /* and then mark its elements */
{
if (i != COMPILED_CONSTANTS)
- mark_object (&ptr1->contents[i]);
+ mark_object (&ptr->contents[i]);
}
/* This cast should be unnecessary, but some Mips compiler complains
(MIPS-ABI + SysVR4, DC/OSx, etc). */
- objptr = (Lisp_Object *) &ptr1->contents[COMPILED_CONSTANTS];
+ objptr = (Lisp_Object *) &ptr->contents[COMPILED_CONSTANTS];
goto loop;
}
else if (GC_FRAMEP (obj))
{
- /* See comment above under Lisp_Vector for why this is volatile. */
- register struct frame *volatile ptr = XFRAME (obj);
+ register struct frame *ptr = XFRAME (obj);
register EMACS_INT size = ptr->size;
if (size & ARRAY_MARK_FLAG) break; /* Already marked */
ptr->size |= ARRAY_MARK_FLAG; /* Else mark it */
+ CHECK_LIVE (live_vector_p);
mark_object (&ptr->name);
mark_object (&ptr->icon_name);
mark_object (&ptr->title);
mark_face_cache (ptr->face_cache);
#ifdef HAVE_WINDOW_SYSTEM
mark_image_cache (ptr);
- mark_object (&ptr->desired_tool_bar_items);
- mark_object (&ptr->current_tool_bar_items);
+ mark_object (&ptr->tool_bar_items);
mark_object (&ptr->desired_tool_bar_string);
mark_object (&ptr->current_tool_bar_string);
#endif /* HAVE_WINDOW_SYSTEM */
if (ptr->size & ARRAY_MARK_FLAG)
break; /* Already marked */
+ CHECK_LIVE (live_vector_p);
ptr->size |= ARRAY_MARK_FLAG; /* Else mark it */
}
else if (GC_WINDOWP (obj))
register struct Lisp_Vector *ptr = XVECTOR (obj);
struct window *w = XWINDOW (obj);
register EMACS_INT size = ptr->size;
- /* The reason we use ptr1 is to avoid an apparent hardware bug
- that happens occasionally on the FSF's HP 300s.
- The bug is that a2 gets clobbered by recursive calls to mark_object.
- The clobberage seems to happen during function entry,
- perhaps in the moveml instruction.
- Yes, this is a crock, but we have to do it. */
- struct Lisp_Vector *volatile ptr1 = ptr;
register int i;
/* Stop if already marked. */
break;
/* Mark it. */
+ CHECK_LIVE (live_vector_p);
ptr->size |= ARRAY_MARK_FLAG;
/* There is no Lisp data above The member CURRENT_MATRIX in
struct WINDOW. Stop marking when that slot is reached. */
for (i = 0;
- (char *) &ptr1->contents[i] < (char *) &w->current_matrix;
+ (char *) &ptr->contents[i] < (char *) &w->current_matrix;
i++)
- mark_object (&ptr1->contents[i]);
+ mark_object (&ptr->contents[i]);
/* Mark glyphs for leaf windows. Marking window matrices is
sufficient because frame matrices use the same glyph
/* Stop if already marked. */
if (size & ARRAY_MARK_FLAG)
break;
-
+
/* Mark it. */
+ CHECK_LIVE (live_vector_p);
h->size |= ARRAY_MARK_FLAG;
/* Mark contents. */
{
register struct Lisp_Vector *ptr = XVECTOR (obj);
register EMACS_INT size = ptr->size;
- /* The reason we use ptr1 is to avoid an apparent hardware bug
- that happens occasionally on the FSF's HP 300s.
- The bug is that a2 gets clobbered by recursive calls to mark_object.
- The clobberage seems to happen during function entry,
- perhaps in the moveml instruction.
- Yes, this is a crock, but we have to do it. */
- struct Lisp_Vector *volatile ptr1 = ptr;
register int i;
if (size & ARRAY_MARK_FLAG) break; /* Already marked */
+ CHECK_LIVE (live_vector_p);
ptr->size |= ARRAY_MARK_FLAG; /* Else mark it */
if (size & PSEUDOVECTOR_FLAG)
size &= PSEUDOVECTOR_SIZE_MASK;
for (i = 0; i < size; i++) /* and then mark its elements */
- mark_object (&ptr1->contents[i]);
+ mark_object (&ptr->contents[i]);
}
break;
case Lisp_Symbol:
{
- /* See comment above under Lisp_Vector for why this is volatile. */
- register struct Lisp_Symbol *volatile ptr = XSYMBOL (obj);
+ register struct Lisp_Symbol *ptr = XSYMBOL (obj);
struct Lisp_Symbol *ptrx;
if (XMARKBIT (ptr->plist)) break;
+ CHECK_ALLOCATED_AND_LIVE (live_symbol_p);
XMARK (ptr->plist);
mark_object ((Lisp_Object *) &ptr->value);
mark_object (&ptr->function);
break;
case Lisp_Misc:
+ CHECK_ALLOCATED_AND_LIVE (live_misc_p);
switch (XMISCTYPE (obj))
{
case Lisp_Misc_Marker:
mark_object (&ptr->realvalue);
mark_object (&ptr->buffer);
mark_object (&ptr->frame);
- /* See comment above under Lisp_Vector for why not use ptr here. */
- objptr = &XBUFFER_LOCAL_VALUE (obj)->cdr;
+ objptr = &ptr->cdr;
goto loop;
}
{
register struct Lisp_Cons *ptr = XCONS (obj);
if (XMARKBIT (ptr->car)) break;
+ CHECK_ALLOCATED_AND_LIVE (live_cons_p);
XMARK (ptr->car);
/* If the cdr is nil, avoid recursion for the car. */
if (EQ (ptr->cdr, Qnil))
goto loop;
}
mark_object (&ptr->car);
- /* See comment above under Lisp_Vector for why not use ptr here. */
- objptr = &XCDR (obj);
+ objptr = &ptr->cdr;
goto loop;
}
case Lisp_Float:
+ CHECK_ALLOCATED_AND_LIVE (live_float_p);
XMARK (XFLOAT (obj)->type);
break;
default:
abort ();
}
+
+#undef CHECK_LIVE
+#undef CHECK_ALLOCATED
+#undef CHECK_ALLOCATED_AND_LIVE
}
/* Mark the pointers in a buffer structure. */
sweep_weak_hash_tables ();
sweep_strings ();
+#ifdef GC_CHECK_STRING_BYTES
+ if (!noninteractive)
+ check_string_bytes (1);
+#endif
/* Put all unmarked conses on free list */
{
register int lim = symbol_block_index;
register int num_free = 0, num_used = 0;
- symbol_free_list = 0;
+ symbol_free_list = NULL;
for (sblk = symbol_block; sblk; sblk = *sprev)
{
- register int i;
int this_free = 0;
- for (i = 0; i < lim; i++)
- if (!XMARKBIT (sblk->symbols[i].plist))
- {
- *(struct Lisp_Symbol **)&sblk->symbols[i].value = symbol_free_list;
- symbol_free_list = &sblk->symbols[i];
+ struct Lisp_Symbol *sym = sblk->symbols;
+ struct Lisp_Symbol *end = sym + lim;
+
+ for (; sym < end; ++sym)
+ {
+ /* Check if the symbol was created during loadup. In such a case
+ it might be pointed to by pure bytecode which we don't trace,
+ so we conservatively assume that it is live. */
+ int pure_p = PURE_POINTER_P (sym->name);
+
+ if (!XMARKBIT (sym->plist) && !pure_p)
+ {
+ *(struct Lisp_Symbol **) &sym->value = symbol_free_list;
+ symbol_free_list = sym;
#if GC_MARK_STACK
- symbol_free_list->function = Vdead;
+ symbol_free_list->function = Vdead;
#endif
- this_free++;
- }
- else
- {
- num_used++;
- if (!PURE_POINTER_P (sblk->symbols[i].name))
- UNMARK_STRING (sblk->symbols[i].name);
- XUNMARK (sblk->symbols[i].plist);
- }
+ ++this_free;
+ }
+ else
+ {
+ ++num_used;
+ if (!pure_p)
+ UNMARK_STRING (sym->name);
+ XUNMARK (sym->plist);
+ }
+ }
+
lim = SYMBOL_BLOCK_SIZE;
/* If this block contains only free symbols and we have already
seen more than two blocks worth of free symbols then deallocate
prev = vector, vector = vector->next;
}
}
+
+#ifdef GC_CHECK_STRING_BYTES
+ if (!noninteractive)
+ check_string_bytes (1);
+#endif
}
init_alloc_once ()
{
/* Used to do Vpurify_flag = Qt here, but Qt isn't set up yet! */
- pureptr = 0;
-#if GC_MARK_STACK
+ pure_bytes_used = 0;
+#if GC_MARK_STACK || defined GC_MALLOC_CHECK
mem_init ();
Vdead = make_pure_string ("DEAD", 4, 4, 0);
#endif
By binding this temporarily to a large number, you can effectively\n\
prevent garbage collection during a part of the program.");
- DEFVAR_INT ("pure-bytes-used", &pureptr,
+ DEFVAR_INT ("pure-bytes-used", &pure_bytes_used,
"Number of bytes of sharable Lisp data allocated so far.");
DEFVAR_INT ("cons-cells-consed", &cons_cells_consed,