X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/4b5afbb0d98ba4a95359ca5edaee8c3ecd7ae007..7d7e0027e7c7ad6584fd44c611b3c77be69391a9:/src/alloc.c diff --git a/src/alloc.c b/src/alloc.c index 400b11c296..bb57d46ee0 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -38,27 +38,35 @@ along with GNU Emacs. If not, see . */ #include "process.h" #include "intervals.h" #include "puresize.h" +#include "character.h" #include "buffer.h" #include "window.h" #include "keyboard.h" #include "frame.h" #include "blockinput.h" -#include "character.h" #include "syssignal.h" #include "termhooks.h" /* For struct terminal. */ #include #include +/* GC_CHECK_MARKED_OBJECTS means do sanity checks on allocated objects. + Doable only if GC_MARK_STACK. */ +#if ! GC_MARK_STACK +# undef GC_CHECK_MARKED_OBJECTS +#endif + /* GC_MALLOC_CHECK defined means perform validity checks of malloc'd - memory. Can do this only if using gmalloc.c. */ + memory. Can do this only if using gmalloc.c and if not checking + marked objects. */ -#if defined SYSTEM_MALLOC || defined DOUG_LEA_MALLOC +#if (defined SYSTEM_MALLOC || defined DOUG_LEA_MALLOC \ + || defined GC_CHECK_MARKED_OBJECTS) #undef GC_MALLOC_CHECK #endif #include #ifndef HAVE_UNISTD_H -extern POINTER_TYPE *sbrk (); +extern void *sbrk (); #endif #include @@ -226,11 +234,11 @@ static ptrdiff_t pure_bytes_used_before_overflow; /* Index in pure at which next pure Lisp object will be allocated.. */ -static EMACS_INT pure_bytes_used_lisp; +static ptrdiff_t pure_bytes_used_lisp; /* Number of bytes allocated for non-Lisp objects in pure storage. */ -static EMACS_INT pure_bytes_used_non_lisp; +static ptrdiff_t pure_bytes_used_non_lisp; /* If nonzero, this is a warning delivered by malloc and not yet displayed. */ @@ -265,6 +273,7 @@ static Lisp_Object Qpost_gc_hook; static void mark_buffer (Lisp_Object); static void mark_terminals (void); static void gc_sweep (void); +static Lisp_Object make_pure_vector (ptrdiff_t); static void mark_glyph_matrix (struct glyph_matrix *); static void mark_face_cache (struct face_cache *); @@ -295,10 +304,12 @@ enum mem_type process, hash_table, frame, terminal, and window, but we never made use of the distinction, so it only caused source-code complexity and runtime slowdown. Minor but pointless. */ - MEM_TYPE_VECTORLIKE + MEM_TYPE_VECTORLIKE, + /* Special type to denote vector blocks. */ + MEM_TYPE_VECTOR_BLOCK }; -static POINTER_TYPE *lisp_malloc (size_t, enum mem_type); +static void *lisp_malloc (size_t, enum mem_type); #if GC_MARK_STACK || defined GC_MALLOC_CHECK @@ -379,8 +390,8 @@ static void *min_heap_address, *max_heap_address; static struct mem_node mem_z; #define MEM_NIL &mem_z -static struct Lisp_Vector *allocate_vectorlike (EMACS_INT); -static void lisp_free (POINTER_TYPE *); +static struct Lisp_Vector *allocate_vectorlike (ptrdiff_t); +static void lisp_free (void *); static void mark_stack (void); static int live_vector_p (struct mem_node *, void *); static int live_buffer_p (struct mem_node *, void *); @@ -391,11 +402,8 @@ static int live_float_p (struct mem_node *, void *); static int live_misc_p (struct mem_node *, void *); static void mark_maybe_object (Lisp_Object); static void mark_memory (void *, void *); +#if GC_MARK_STACK || defined GC_MALLOC_CHECK static void mem_init (void); -#if (defined GC_MALLOC_CHECK \ - ? !defined SYSTEM_MALLOC && !defined SYNC_INPUT \ - : GC_MARK_STACK) -# define NEED_MEM_INSERT static struct mem_node *mem_insert (void *, void *, enum mem_type); static void mem_insert_fixup (struct mem_node *); #endif @@ -423,22 +431,22 @@ struct gcpro *gcprolist; /* Addresses of staticpro'd variables. Initialize it to a nonzero value; otherwise some compilers put it into BSS. */ -#define NSTATICS 0x640 +#define NSTATICS 0x650 static Lisp_Object *staticvec[NSTATICS] = {&Vpurify_flag}; /* Index of next unused slot in staticvec. */ static int staticidx = 0; -static POINTER_TYPE *pure_alloc (size_t, int); +static void *pure_alloc (size_t, int); /* Value is SZ rounded up to the next multiple of ALIGNMENT. ALIGNMENT must be a power of 2. */ #define ALIGN(ptr, ALIGNMENT) \ - ((POINTER_TYPE *) ((((uintptr_t) (ptr)) + (ALIGNMENT) - 1) \ - & ~((ALIGNMENT) - 1))) + ((void *) (((uintptr_t) (ptr) + (ALIGNMENT) - 1) \ + & ~ ((ALIGNMENT) - 1))) @@ -470,7 +478,7 @@ display_malloc_warning (void) /* Called if we can't allocate relocatable space for a buffer. */ void -buffer_memory_full (EMACS_INT nbytes) +buffer_memory_full (ptrdiff_t nbytes) { /* If buffers use the relocating allocator, no need to free spare_memory, because we may have plenty of malloc space left @@ -488,6 +496,11 @@ buffer_memory_full (EMACS_INT nbytes) xsignal (Qnil, Vmemory_signal_data); } +/* A common multiple of the positive integers A and B. Ideally this + would be the least common multiple, but there's no way to do that + as a constant expression in C, so do the best that we can easily do. */ +#define COMMON_MULTIPLE(a, b) \ + ((a) % (b) == 0 ? (a) : (b) % (a) == 0 ? (b) : (a) * (b)) #ifndef XMALLOC_OVERRUN_CHECK #define XMALLOC_OVERRUN_CHECK_OVERHEAD 0 @@ -519,12 +532,8 @@ buffer_memory_full (EMACS_INT nbytes) char c; \ }, \ c) -#ifdef USE_LSB_TAG -/* A common multiple of the positive integers A and B. Ideally this - would be the least common multiple, but there's no way to do that - as a constant expression in C, so do the best that we can easily do. */ -# define COMMON_MULTIPLE(a, b) \ - ((a) % (b) == 0 ? (a) : (b) % (a) == 0 ? (b) : (a) * (b)) + +#if USE_LSB_TAG # define XMALLOC_HEADER_ALIGNMENT \ COMMON_MULTIPLE (1 << GCTYPEBITS, XMALLOC_BASE_ALIGNMENT) #else @@ -599,7 +608,7 @@ static ptrdiff_t check_depth; /* Like malloc, but wraps allocated block with header and trailer. */ -static POINTER_TYPE * +static void * overrun_check_malloc (size_t size) { register unsigned char *val; @@ -617,15 +626,15 @@ overrun_check_malloc (size_t size) XMALLOC_OVERRUN_CHECK_SIZE); } --check_depth; - return (POINTER_TYPE *)val; + return val; } /* Like realloc, but checks old block for overrun, and wraps new block with header and trailer. */ -static POINTER_TYPE * -overrun_check_realloc (POINTER_TYPE *block, size_t size) +static void * +overrun_check_realloc (void *block, size_t size) { register unsigned char *val = (unsigned char *) block; int overhead = ++check_depth == 1 ? XMALLOC_OVERRUN_CHECK_OVERHEAD : 0; @@ -647,7 +656,7 @@ overrun_check_realloc (POINTER_TYPE *block, size_t size) memset (val, 0, XMALLOC_OVERRUN_CHECK_SIZE + XMALLOC_OVERRUN_SIZE_SIZE); } - val = (unsigned char *) realloc ((POINTER_TYPE *)val, size + overhead); + val = realloc (val, size + overhead); if (val && check_depth == 1) { @@ -658,13 +667,13 @@ overrun_check_realloc (POINTER_TYPE *block, size_t size) XMALLOC_OVERRUN_CHECK_SIZE); } --check_depth; - return (POINTER_TYPE *)val; + return val; } /* Like free, but checks block for overrun. */ static void -overrun_check_free (POINTER_TYPE *block) +overrun_check_free (void *block) { unsigned char *val = (unsigned char *) block; @@ -713,13 +722,13 @@ overrun_check_free (POINTER_TYPE *block) /* Like malloc but check for no memory and block interrupt input.. */ -POINTER_TYPE * +void * xmalloc (size_t size) { - register POINTER_TYPE *val; + void *val; MALLOC_BLOCK_INPUT; - val = (POINTER_TYPE *) malloc (size); + val = malloc (size); MALLOC_UNBLOCK_INPUT; if (!val && size) @@ -730,18 +739,18 @@ xmalloc (size_t size) /* Like realloc but check for no memory and block interrupt input.. */ -POINTER_TYPE * -xrealloc (POINTER_TYPE *block, size_t size) +void * +xrealloc (void *block, size_t size) { - register POINTER_TYPE *val; + void *val; MALLOC_BLOCK_INPUT; /* We must call malloc explicitly when BLOCK is 0, since some reallocs don't do this. */ if (! block) - val = (POINTER_TYPE *) malloc (size); + val = malloc (size); else - val = (POINTER_TYPE *) realloc (block, size); + val = realloc (block, size); MALLOC_UNBLOCK_INPUT; if (!val && size) @@ -753,7 +762,7 @@ xrealloc (POINTER_TYPE *block, size_t size) /* Like free but block interrupt input. */ void -xfree (POINTER_TYPE *block) +xfree (void *block) { if (!block) return; @@ -778,7 +787,7 @@ verify (INT_MAX <= PTRDIFF_MAX); void * xnmalloc (ptrdiff_t nitems, ptrdiff_t item_size) { - xassert (0 <= nitems && 0 < item_size); + eassert (0 <= nitems && 0 < item_size); if (min (PTRDIFF_MAX, SIZE_MAX) / item_size < nitems) memory_full (SIZE_MAX); return xmalloc (nitems * item_size); @@ -791,7 +800,7 @@ xnmalloc (ptrdiff_t nitems, ptrdiff_t item_size) void * xnrealloc (void *pa, ptrdiff_t nitems, ptrdiff_t item_size) { - xassert (0 <= nitems && 0 < item_size); + eassert (0 <= nitems && 0 < item_size); if (min (PTRDIFF_MAX, SIZE_MAX) / item_size < nitems) memory_full (SIZE_MAX); return xrealloc (pa, nitems * item_size); @@ -841,7 +850,7 @@ xpalloc (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min, ptrdiff_t nitems_incr_max = n_max - n; ptrdiff_t incr = max (nitems_incr_min, min (incr_estimate, nitems_incr_max)); - xassert (0 < item_size && 0 < nitems_incr_min && 0 <= n && -1 <= nitems_max); + eassert (0 < item_size && 0 < nitems_incr_min && 0 <= n && -1 <= nitems_max); if (! pa) *nitems = 0; if (nitems_incr_max < incr) @@ -884,11 +893,11 @@ safe_alloca_unwind (Lisp_Object arg) number of bytes to allocate, TYPE describes the intended use of the allocated memory block (for strings, for conses, ...). */ -#ifndef USE_LSB_TAG -static void *lisp_malloc_loser; +#if ! USE_LSB_TAG +void *lisp_malloc_loser EXTERNALLY_VISIBLE; #endif -static POINTER_TYPE * +static void * lisp_malloc (size_t nbytes, enum mem_type type) { register void *val; @@ -901,7 +910,7 @@ lisp_malloc (size_t nbytes, enum mem_type type) val = (void *) malloc (nbytes); -#ifndef USE_LSB_TAG +#if ! USE_LSB_TAG /* If the memory just allocated cannot be addressed thru a Lisp object's pointer, and it needs to be, that's equivalent to running out of memory. */ @@ -933,7 +942,7 @@ lisp_malloc (size_t nbytes, enum mem_type type) call to lisp_malloc. */ static void -lisp_free (POINTER_TYPE *block) +lisp_free (void *block) { MALLOC_BLOCK_INPUT; free (block); @@ -1029,7 +1038,7 @@ static struct ablock *free_ablock; /* Allocate an aligned block of nbytes. Alignment is on a multiple of BLOCK_ALIGN and `nbytes' has to be smaller or equal to BLOCK_BYTES. */ -static POINTER_TYPE * +static void * lisp_align_malloc (size_t nbytes, enum mem_type type) { void *base, *val; @@ -1082,7 +1091,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type) mallopt (M_MMAP_MAX, MMAP_MAX_AREAS); #endif -#ifndef USE_LSB_TAG +#if ! USE_LSB_TAG /* If the memory just allocated cannot be addressed thru a Lisp object's pointer, and it needs to be, that's equivalent to running out of memory. */ @@ -1136,7 +1145,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type) } static void -lisp_align_free (POINTER_TYPE *block) +lisp_align_free (void *block) { struct ablock *ablock = block; struct ablocks *abase = ABLOCK_ABASE (ablock); @@ -1309,7 +1318,7 @@ emacs_blocked_malloc (size_t size, const void *ptr) { 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", + fprintf (stderr, "Region in use is %p...%p, %td bytes, type %d\n", m->start, m->end, (char *) m->end - (char *) m->start, m->type); abort (); @@ -1575,35 +1584,6 @@ mark_interval_tree (register INTERVAL tree) if (! NULL_INTERVAL_P (i)) \ (i) = balance_intervals (i); \ } while (0) - - -/* Number support. If USE_LISP_UNION_TYPE is in effect, we - can't create number objects in macros. */ -#ifndef make_number -Lisp_Object -make_number (EMACS_INT n) -{ - Lisp_Object obj; - obj.s.val = n; - obj.s.type = Lisp_Int; - return obj; -} -#endif - -/* Convert the pointer-sized word P to EMACS_INT while preserving its - type and ptr fields. */ -static Lisp_Object -widen_to_Lisp_Object (void *p) -{ - intptr_t i = (intptr_t) p; -#ifdef USE_LISP_UNION_TYPE - Lisp_Object obj; - obj.i = i; - return obj; -#else - return i; -#endif -} /*********************************************************************** String Allocation @@ -1657,7 +1637,7 @@ struct sdata #ifdef GC_CHECK_STRING_BYTES - EMACS_INT nbytes; + ptrdiff_t nbytes; unsigned char data[1]; #define SDATA_NBYTES(S) (S)->nbytes @@ -1672,7 +1652,7 @@ struct sdata unsigned char data[1]; /* When STRING is null. */ - EMACS_INT nbytes; + ptrdiff_t nbytes; } u; #define SDATA_NBYTES(S) (S)->u.nbytes @@ -1782,24 +1762,24 @@ static char const string_overrun_cookie[GC_STRING_OVERRUN_COOKIE_SIZE] = #define SDATA_SIZE(NBYTES) \ ((SDATA_DATA_OFFSET \ + (NBYTES) + 1 \ - + sizeof (EMACS_INT) - 1) \ - & ~(sizeof (EMACS_INT) - 1)) + + sizeof (ptrdiff_t) - 1) \ + & ~(sizeof (ptrdiff_t) - 1)) #else /* not GC_CHECK_STRING_BYTES */ /* The 'max' reserves space for the nbytes union member even when NBYTES + 1 is less than the size of that member. The 'max' is not needed when - SDATA_DATA_OFFSET is a multiple of sizeof (EMACS_INT), because then the + SDATA_DATA_OFFSET is a multiple of sizeof (ptrdiff_t), because then the alignment code reserves enough space. */ #define SDATA_SIZE(NBYTES) \ ((SDATA_DATA_OFFSET \ - + (SDATA_DATA_OFFSET % sizeof (EMACS_INT) == 0 \ + + (SDATA_DATA_OFFSET % sizeof (ptrdiff_t) == 0 \ ? NBYTES \ - : max (NBYTES, sizeof (EMACS_INT) - 1)) \ + : max (NBYTES, sizeof (ptrdiff_t) - 1)) \ + 1 \ - + sizeof (EMACS_INT) - 1) \ - & ~(sizeof (EMACS_INT) - 1)) + + sizeof (ptrdiff_t) - 1) \ + & ~(sizeof (ptrdiff_t) - 1)) #endif /* not GC_CHECK_STRING_BYTES */ @@ -1843,10 +1823,10 @@ static int check_string_bytes_count; /* Like GC_STRING_BYTES, but with debugging check. */ -EMACS_INT +ptrdiff_t string_bytes (struct Lisp_String *s) { - EMACS_INT nbytes = + ptrdiff_t nbytes = (s->size_byte < 0 ? s->size & ~ARRAY_MARK_FLAG : s->size_byte); if (!PURE_POINTER_P (s) @@ -1869,7 +1849,7 @@ check_sblock (struct sblock *b) { /* Compute the next FROM here because copying below may overwrite data we need to compute it. */ - EMACS_INT nbytes; + ptrdiff_t nbytes; /* Check that the string size recorded in the string is the same as the one recorded in the sdata structure. */ @@ -1956,13 +1936,14 @@ allocate_string (void) int i; b = (struct string_block *) lisp_malloc (sizeof *b, MEM_TYPE_STRING); - memset (b, 0, sizeof *b); b->next = string_blocks; string_blocks = b; for (i = STRING_BLOCK_SIZE - 1; i >= 0; --i) { s = b->strings + i; + /* Every string on a free list should have NULL data pointer. */ + s->data = NULL; NEXT_FREE_LISP_STRING (s) = string_free_list; string_free_list = s; } @@ -1978,9 +1959,6 @@ allocate_string (void) MALLOC_UNBLOCK_INPUT; - /* Probably not strictly necessary, but play it safe. */ - memset (s, 0, sizeof *s); - --total_free_strings; ++total_strings; ++strings_consed; @@ -2013,9 +1991,9 @@ void allocate_string_data (struct Lisp_String *s, EMACS_INT nchars, EMACS_INT nbytes) { - struct sdata *data, *old_data; + struct sdata *data; struct sblock *b; - EMACS_INT needed, old_nbytes; + ptrdiff_t needed; if (STRING_BYTES_MAX < nbytes) string_overflow (); @@ -2023,8 +2001,6 @@ allocate_string_data (struct Lisp_String *s, /* Determine the number of bytes needed to store NBYTES bytes of string data. */ needed = SDATA_SIZE (nbytes); - old_data = s->data ? SDATA_OF_STRING (s) : NULL; - old_nbytes = GC_STRING_BYTES (s); MALLOC_BLOCK_INPUT; @@ -2094,16 +2070,6 @@ allocate_string_data (struct Lisp_String *s, memcpy ((char *) data + needed, string_overrun_cookie, GC_STRING_OVERRUN_COOKIE_SIZE); #endif - - /* 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; } @@ -2254,13 +2220,13 @@ compact_small_strings (void) for (b = oldest_sblock; b; b = b->next) { end = b->next_free; - xassert ((char *) end <= (char *) b + SBLOCK_SIZE); + eassert ((char *) end <= (char *) b + SBLOCK_SIZE); 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. */ - EMACS_INT nbytes; + ptrdiff_t nbytes; #ifdef GC_CHECK_STRING_BYTES /* Check that the string size recorded in the string is the @@ -2305,7 +2271,7 @@ compact_small_strings (void) /* Copy, and update the string's `data' pointer. */ if (from != to) { - xassert (tb != b || to < from); + eassert (tb != b || to < from); memmove (to, from, nbytes + GC_STRING_EXTRA); to->string->data = SDATA_DATA (to); } @@ -2390,7 +2356,8 @@ LENGTH must be a number. INIT matters only in whether it is t or nil. */) { register Lisp_Object val; struct Lisp_Bool_Vector *p; - EMACS_INT length_in_chars, length_in_elts; + ptrdiff_t length_in_chars; + EMACS_INT length_in_elts; int bits_per_value; CHECK_NATNUM (length); @@ -2398,8 +2365,6 @@ LENGTH must be a number. INIT matters only in whether it is t or nil. */) bits_per_value = sizeof (EMACS_INT) * BOOL_VECTOR_BITS_PER_CHAR; length_in_elts = (XFASTINT (length) + bits_per_value - 1) / bits_per_value; - length_in_chars = ((XFASTINT (length) + BOOL_VECTOR_BITS_PER_CHAR - 1) - / BOOL_VECTOR_BITS_PER_CHAR); /* We must allocate one more elements than LENGTH_IN_ELTS for the slot `size' of the struct Lisp_Bool_Vector. */ @@ -2411,6 +2376,8 @@ LENGTH must be a number. INIT matters only in whether it is t or nil. */) p = XBOOL_VECTOR (val); p->size = XFASTINT (length); + length_in_chars = ((XFASTINT (length) + BOOL_VECTOR_BITS_PER_CHAR - 1) + / BOOL_VECTOR_BITS_PER_CHAR); if (length_in_chars) { memset (p->data, ! NILP (init) ? -1 : 0, length_in_chars); @@ -2429,10 +2396,10 @@ LENGTH must be a number. INIT matters only in whether it is t or nil. */) multibyte, depending on the contents. */ Lisp_Object -make_string (const char *contents, EMACS_INT nbytes) +make_string (const char *contents, ptrdiff_t nbytes) { register Lisp_Object val; - EMACS_INT nchars, multibyte_nbytes; + ptrdiff_t nchars, multibyte_nbytes; parse_str_as_multibyte ((const unsigned char *) contents, nbytes, &nchars, &multibyte_nbytes); @@ -2449,7 +2416,7 @@ make_string (const char *contents, EMACS_INT nbytes) /* Make an unibyte string from LENGTH bytes at CONTENTS. */ Lisp_Object -make_unibyte_string (const char *contents, EMACS_INT length) +make_unibyte_string (const char *contents, ptrdiff_t length) { register Lisp_Object val; val = make_uninit_string (length); @@ -2463,7 +2430,7 @@ make_unibyte_string (const char *contents, EMACS_INT length) Lisp_Object make_multibyte_string (const char *contents, - EMACS_INT nchars, EMACS_INT nbytes) + ptrdiff_t nchars, ptrdiff_t nbytes) { register Lisp_Object val; val = make_uninit_multibyte_string (nchars, nbytes); @@ -2477,7 +2444,7 @@ make_multibyte_string (const char *contents, Lisp_Object make_string_from_bytes (const char *contents, - EMACS_INT nchars, EMACS_INT nbytes) + ptrdiff_t nchars, ptrdiff_t nbytes) { register Lisp_Object val; val = make_uninit_multibyte_string (nchars, nbytes); @@ -2495,7 +2462,7 @@ make_string_from_bytes (const char *contents, Lisp_Object make_specified_string (const char *contents, - EMACS_INT nchars, EMACS_INT nbytes, int multibyte) + ptrdiff_t nchars, ptrdiff_t nbytes, int multibyte) { register Lisp_Object val; @@ -2515,16 +2482,6 @@ make_specified_string (const char *contents, } -/* Make a string from the data at STR, treating it as multibyte if the - data warrants. */ - -Lisp_Object -build_string (const char *str) -{ - return make_string (str, strlen (str)); -} - - /* Return an unibyte Lisp_String set up to hold LENGTH characters occupying LENGTH bytes. */ @@ -2556,6 +2513,7 @@ make_uninit_multibyte_string (EMACS_INT nchars, EMACS_INT nbytes) return empty_multibyte_string; s = allocate_string (); + s->intervals = NULL_INTERVAL; allocate_string_data (s, nchars, nbytes); XSETSTRING (string, s); string_chars_consed += nbytes; @@ -2694,8 +2652,10 @@ make_float (double float_value) GC are put on a free list to be reallocated before allocating any new cons cells from the latest cons_block. */ -#define CONS_BLOCK_SIZE \ - (((BLOCK_BYTES - sizeof (struct cons_block *)) * CHAR_BIT) \ +#define CONS_BLOCK_SIZE \ + (((BLOCK_BYTES - sizeof (struct cons_block *) \ + /* The compiler might add padding at the end. */ \ + - (sizeof (struct Lisp_Cons) - sizeof (int))) * CHAR_BIT) \ / (sizeof (struct Lisp_Cons) * CHAR_BIT + 1)) #define CONS_BLOCK(fptr) \ @@ -2919,22 +2879,307 @@ DEFUN ("make-list", Fmake_list, Smake_list, 2, 2, 0, Vector Allocation ***********************************************************************/ -/* Singly-linked list of all vectors. */ +/* This value is balanced well enough to avoid too much internal overhead + for the most common cases; it's not required to be a power of two, but + it's expected to be a mult-of-ROUNDUP_SIZE (see below). */ -static struct Lisp_Vector *all_vectors; +#define VECTOR_BLOCK_SIZE 4096 /* Handy constants for vectorlike objects. */ enum { header_size = offsetof (struct Lisp_Vector, contents), - word_size = sizeof (Lisp_Object) + word_size = sizeof (Lisp_Object), + roundup_size = COMMON_MULTIPLE (sizeof (Lisp_Object), + USE_LSB_TAG ? 1 << GCTYPEBITS : 1) }; +/* ROUNDUP_SIZE must be a power of 2. */ +verify ((roundup_size & (roundup_size - 1)) == 0); + +/* Round up X to nearest mult-of-ROUNDUP_SIZE. */ + +#define vroundup(x) (((x) + (roundup_size - 1)) & ~(roundup_size - 1)) + +/* Rounding helps to maintain alignment constraints if USE_LSB_TAG. */ + +#define VECTOR_BLOCK_BYTES (VECTOR_BLOCK_SIZE - vroundup (sizeof (void *))) + +/* Size of the minimal vector allocated from block. */ + +#define VBLOCK_BYTES_MIN vroundup (sizeof (struct Lisp_Vector)) + +/* Size of the largest vector allocated from block. */ + +#define VBLOCK_BYTES_MAX \ + vroundup ((VECTOR_BLOCK_BYTES / 2) - sizeof (Lisp_Object)) + +/* We maintain one free list for each possible block-allocated + vector size, and this is the number of free lists we have. */ + +#define VECTOR_MAX_FREE_LIST_INDEX \ + ((VECTOR_BLOCK_BYTES - VBLOCK_BYTES_MIN) / roundup_size + 1) + +/* When the vector is on a free list, vectorlike_header.SIZE is set to + this special value ORed with vector's memory footprint size. */ + +#define VECTOR_FREE_LIST_FLAG (~(ARRAY_MARK_FLAG | PSEUDOVECTOR_FLAG \ + | (VECTOR_BLOCK_SIZE - 1))) + +/* Common shortcut to advance vector pointer over a block data. */ + +#define ADVANCE(v, nbytes) ((struct Lisp_Vector *) ((char *) (v) + (nbytes))) + +/* Common shortcut to calculate NBYTES-vector index in VECTOR_FREE_LISTS. */ + +#define VINDEX(nbytes) (((nbytes) - VBLOCK_BYTES_MIN) / roundup_size) + +/* Common shortcut to setup vector on a free list. */ + +#define SETUP_ON_FREE_LIST(v, nbytes, index) \ + do { \ + (v)->header.size = VECTOR_FREE_LIST_FLAG | (nbytes); \ + eassert ((nbytes) % roundup_size == 0); \ + (index) = VINDEX (nbytes); \ + eassert ((index) < VECTOR_MAX_FREE_LIST_INDEX); \ + (v)->header.next.vector = vector_free_lists[index]; \ + vector_free_lists[index] = (v); \ + } while (0) + +struct vector_block +{ + char data[VECTOR_BLOCK_BYTES]; + struct vector_block *next; +}; + +/* Chain of vector blocks. */ + +static struct vector_block *vector_blocks; + +/* Vector free lists, where NTH item points to a chain of free + vectors of the same NBYTES size, so NTH == VINDEX (NBYTES). */ + +static struct Lisp_Vector *vector_free_lists[VECTOR_MAX_FREE_LIST_INDEX]; + +/* Singly-linked list of large vectors. */ + +static struct Lisp_Vector *large_vectors; + +/* The only vector with 0 slots, allocated from pure space. */ + +static struct Lisp_Vector *zero_vector; + +/* Get a new vector block. */ + +static struct vector_block * +allocate_vector_block (void) +{ + struct vector_block *block; + +#ifdef DOUG_LEA_MALLOC + mallopt (M_MMAP_MAX, 0); +#endif + + block = xmalloc (sizeof (struct vector_block)); + +#ifdef DOUG_LEA_MALLOC + mallopt (M_MMAP_MAX, MMAP_MAX_AREAS); +#endif + +#if GC_MARK_STACK && !defined GC_MALLOC_CHECK + mem_insert (block->data, block->data + VECTOR_BLOCK_BYTES, + MEM_TYPE_VECTOR_BLOCK); +#endif + + block->next = vector_blocks; + vector_blocks = block; + return block; +} + +/* Called once to initialize vector allocation. */ + +static void +init_vectors (void) +{ + zero_vector = pure_alloc (header_size, Lisp_Vectorlike); + zero_vector->header.size = 0; +} + +/* Allocate vector from a vector block. */ + +static struct Lisp_Vector * +allocate_vector_from_block (size_t nbytes) +{ + struct Lisp_Vector *vector, *rest; + struct vector_block *block; + size_t index, restbytes; + + eassert (VBLOCK_BYTES_MIN <= nbytes && nbytes <= VBLOCK_BYTES_MAX); + eassert (nbytes % roundup_size == 0); + + /* First, try to allocate from a free list + containing vectors of the requested size. */ + index = VINDEX (nbytes); + if (vector_free_lists[index]) + { + vector = vector_free_lists[index]; + vector_free_lists[index] = vector->header.next.vector; + vector->header.next.nbytes = nbytes; + return vector; + } + + /* Next, check free lists containing larger vectors. Since + we will split the result, we should have remaining space + large enough to use for one-slot vector at least. */ + for (index = VINDEX (nbytes + VBLOCK_BYTES_MIN); + index < VECTOR_MAX_FREE_LIST_INDEX; index++) + if (vector_free_lists[index]) + { + /* This vector is larger than requested. */ + vector = vector_free_lists[index]; + vector_free_lists[index] = vector->header.next.vector; + vector->header.next.nbytes = nbytes; + + /* Excess bytes are used for the smaller vector, + which should be set on an appropriate free list. */ + restbytes = index * roundup_size + VBLOCK_BYTES_MIN - nbytes; + eassert (restbytes % roundup_size == 0); + rest = ADVANCE (vector, nbytes); + SETUP_ON_FREE_LIST (rest, restbytes, index); + return vector; + } + + /* Finally, need a new vector block. */ + block = allocate_vector_block (); + + /* New vector will be at the beginning of this block. */ + vector = (struct Lisp_Vector *) block->data; + vector->header.next.nbytes = nbytes; + + /* If the rest of space from this block is large enough + for one-slot vector at least, set up it on a free list. */ + restbytes = VECTOR_BLOCK_BYTES - nbytes; + if (restbytes >= VBLOCK_BYTES_MIN) + { + eassert (restbytes % roundup_size == 0); + rest = ADVANCE (vector, nbytes); + SETUP_ON_FREE_LIST (rest, restbytes, index); + } + return vector; + } + +/* Return how many Lisp_Objects can be stored in V. */ + +#define VECTOR_SIZE(v) ((v)->header.size & PSEUDOVECTOR_FLAG ? \ + (PSEUDOVECTOR_SIZE_MASK & (v)->header.size) : \ + (v)->header.size) + +/* Nonzero if VECTOR pointer is valid pointer inside BLOCK. */ + +#define VECTOR_IN_BLOCK(vector, block) \ + ((char *) (vector) <= (block)->data \ + + VECTOR_BLOCK_BYTES - VBLOCK_BYTES_MIN) + +/* Reclaim space used by unmarked vectors. */ + +static void +sweep_vectors (void) +{ + struct vector_block *block = vector_blocks, **bprev = &vector_blocks; + struct Lisp_Vector *vector, *next, **vprev = &large_vectors; + + total_vector_size = 0; + memset (vector_free_lists, 0, sizeof (vector_free_lists)); + + /* Looking through vector blocks. */ + + for (block = vector_blocks; block; block = *bprev) + { + int free_this_block = 0; + + for (vector = (struct Lisp_Vector *) block->data; + VECTOR_IN_BLOCK (vector, block); vector = next) + { + if (VECTOR_MARKED_P (vector)) + { + VECTOR_UNMARK (vector); + total_vector_size += VECTOR_SIZE (vector); + next = ADVANCE (vector, vector->header.next.nbytes); + } + else + { + ptrdiff_t nbytes; + + if ((vector->header.size & VECTOR_FREE_LIST_FLAG) + == VECTOR_FREE_LIST_FLAG) + vector->header.next.nbytes = + vector->header.size & (VECTOR_BLOCK_SIZE - 1); + + next = ADVANCE (vector, vector->header.next.nbytes); + + /* While NEXT is not marked, try to coalesce with VECTOR, + thus making VECTOR of the largest possible size. */ + + while (VECTOR_IN_BLOCK (next, block)) + { + if (VECTOR_MARKED_P (next)) + break; + if ((next->header.size & VECTOR_FREE_LIST_FLAG) + == VECTOR_FREE_LIST_FLAG) + nbytes = next->header.size & (VECTOR_BLOCK_SIZE - 1); + else + nbytes = next->header.next.nbytes; + vector->header.next.nbytes += nbytes; + next = ADVANCE (next, nbytes); + } + + eassert (vector->header.next.nbytes % roundup_size == 0); + + if (vector == (struct Lisp_Vector *) block->data + && !VECTOR_IN_BLOCK (next, block)) + /* This block should be freed because all of it's + space was coalesced into the only free vector. */ + free_this_block = 1; + else + SETUP_ON_FREE_LIST (vector, vector->header.next.nbytes, nbytes); + } + } + + if (free_this_block) + { + *bprev = block->next; +#if GC_MARK_STACK && !defined GC_MALLOC_CHECK + mem_delete (mem_find (block->data)); +#endif + xfree (block); + } + else + bprev = &block->next; + } + + /* Sweep large vectors. */ + + for (vector = large_vectors; vector; vector = *vprev) + { + if (VECTOR_MARKED_P (vector)) + { + VECTOR_UNMARK (vector); + total_vector_size += VECTOR_SIZE (vector); + vprev = &vector->header.next.vector; + } + else + { + *vprev = vector->header.next.vector; + lisp_free (vector); + } + } +} + /* Value is a pointer to a newly allocated Lisp_Vector structure with room for LEN Lisp_Objects. */ static struct Lisp_Vector * -allocate_vectorlike (EMACS_INT len) +allocate_vectorlike (ptrdiff_t len) { struct Lisp_Vector *p; size_t nbytes; @@ -2951,8 +3196,22 @@ allocate_vectorlike (EMACS_INT len) /* This gets triggered by code which I haven't bothered to fix. --Stef */ /* eassert (!handling_signal); */ + if (len == 0) + { + MALLOC_UNBLOCK_INPUT; + return zero_vector; + } + nbytes = header_size + len * word_size; - p = (struct Lisp_Vector *) lisp_malloc (nbytes, MEM_TYPE_VECTORLIKE); + + if (nbytes <= VBLOCK_BYTES_MAX) + p = allocate_vector_from_block (vroundup (nbytes)); + else + { + p = (struct Lisp_Vector *) lisp_malloc (nbytes, MEM_TYPE_VECTORLIKE); + p->header.next.vector = large_vectors; + large_vectors = p; + } #ifdef DOUG_LEA_MALLOC /* Back to a reasonable maximum of mmap'ed areas. */ @@ -2962,9 +3221,6 @@ allocate_vectorlike (EMACS_INT len) consing_since_gc += nbytes; vector_cells_consed += len; - p->header.next.vector = all_vectors; - all_vectors = p; - MALLOC_UNBLOCK_INPUT; return p; @@ -2990,7 +3246,7 @@ allocate_vector (EMACS_INT len) /* Allocate other vector-like structures. */ struct Lisp_Vector * -allocate_pseudovector (int memlen, int lisplen, EMACS_INT tag) +allocate_pseudovector (int memlen, int lisplen, int tag) { struct Lisp_Vector *v = allocate_vectorlike (memlen); int i; @@ -3009,44 +3265,53 @@ allocate_hash_table (void) return ALLOCATE_PSEUDOVECTOR (struct Lisp_Hash_Table, count, PVEC_HASH_TABLE); } - struct window * allocate_window (void) { - return ALLOCATE_PSEUDOVECTOR (struct window, current_matrix, PVEC_WINDOW); -} + struct window *w; + w = ALLOCATE_PSEUDOVECTOR (struct window, current_matrix, PVEC_WINDOW); + /* Users assumes that non-Lisp data is zeroed. */ + memset (&w->current_matrix, 0, + sizeof (*w) - offsetof (struct window, current_matrix)); + return w; +} struct terminal * allocate_terminal (void) { - struct terminal *t = ALLOCATE_PSEUDOVECTOR (struct terminal, - next_terminal, PVEC_TERMINAL); - /* Zero out the non-GC'd fields. FIXME: This should be made unnecessary. */ - memset (&t->next_terminal, 0, - (char*) (t + 1) - (char*) &t->next_terminal); + struct terminal *t; + t = ALLOCATE_PSEUDOVECTOR (struct terminal, next_terminal, PVEC_TERMINAL); + /* Users assumes that non-Lisp data is zeroed. */ + memset (&t->next_terminal, 0, + sizeof (*t) - offsetof (struct terminal, next_terminal)); return t; } struct frame * allocate_frame (void) { - struct frame *f = ALLOCATE_PSEUDOVECTOR (struct frame, - face_cache, PVEC_FRAME); - /* Zero out the non-GC'd fields. FIXME: This should be made unnecessary. */ + struct frame *f; + + f = ALLOCATE_PSEUDOVECTOR (struct frame, face_cache, PVEC_FRAME); + /* Users assumes that non-Lisp data is zeroed. */ memset (&f->face_cache, 0, - (char *) (f + 1) - (char *) &f->face_cache); + sizeof (*f) - offsetof (struct frame, face_cache)); return f; } - struct Lisp_Process * allocate_process (void) { - return ALLOCATE_PSEUDOVECTOR (struct Lisp_Process, pid, PVEC_PROCESS); -} + struct Lisp_Process *p; + p = ALLOCATE_PSEUDOVECTOR (struct Lisp_Process, pid, PVEC_PROCESS); + /* Users assumes that non-Lisp data is zeroed. */ + memset (&p->pid, 0, + sizeof (*p) - offsetof (struct Lisp_Process, pid)); + return p; +} DEFUN ("make-vector", Fmake_vector, Smake_vector, 2, 2, 0, doc: /* Return a newly created vector of length LENGTH, with each element being INIT. @@ -3054,14 +3319,14 @@ See also the function `vector'. */) (register Lisp_Object length, Lisp_Object init) { Lisp_Object vector; - register EMACS_INT sizei; - register EMACS_INT i; + register ptrdiff_t sizei; + register ptrdiff_t i; register struct Lisp_Vector *p; CHECK_NATNUM (length); - sizei = XFASTINT (length); - p = allocate_vector (sizei); + p = allocate_vector (XFASTINT (length)); + sizei = XFASTINT (length); for (i = 0; i < sizei; i++) p->contents[i] = init; @@ -3088,6 +3353,19 @@ usage: (vector &rest OBJECTS) */) return val; } +void +make_byte_code (struct Lisp_Vector *v) +{ + if (v->header.size > 1 && STRINGP (v->contents[1]) + && STRING_MULTIBYTE (v->contents[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. */ + v->contents[1] = Fstring_as_unibyte (v->contents[1]); + XSETPVECTYPE (v, PVEC_COMPILED); +} DEFUN ("make-byte-code", Fmake_byte_code, Smake_byte_code, 4, MANY, 0, doc: /* Create a byte-code object with specified arguments as elements. @@ -3111,28 +3389,21 @@ usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INT ptrdiff_t i; register struct Lisp_Vector *p; - XSETFASTINT (len, nargs); - if (!NILP (Vpurify_flag)) - val = make_pure_vector (nargs); - else - val = Fmake_vector (len, Qnil); + /* We used to purecopy everything here, if purify-flga was set. This worked + OK for Emacs-23, but with Emacs-24's lexical binding code, it can be + dangerous, since make-byte-code is used during execution to build + closures, so any closure built during the preload phase would end up + copied into pure space, including its free variables, which is sometimes + just wasteful and other times plainly wrong (e.g. those free vars may want + to be setcar'd). */ - if (nargs > 1 && 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]); + XSETFASTINT (len, nargs); + val = Fmake_vector (len, Qnil); p = XVECTOR (val); for (i = 0; i < nargs; i++) - { - if (!NILP (Vpurify_flag)) - args[i] = Fpurecopy (args[i]); - p->contents[i] = args[i]; - } - XSETPVECTYPE (p, PVEC_COMPILED); + p->contents[i] = args[i]; + make_byte_code (p); XSETCOMPILED (val, p); return val; } @@ -3149,7 +3420,7 @@ usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INT union aligned_Lisp_Symbol { struct Lisp_Symbol s; -#ifdef USE_LSB_TAG +#if USE_LSB_TAG unsigned char c[(sizeof (struct Lisp_Symbol) + (1 << GCTYPEBITS) - 1) & -(1 << GCTYPEBITS)]; #endif @@ -3157,7 +3428,7 @@ union aligned_Lisp_Symbol /* Each symbol_block is just under 1020 bytes long, since malloc really allocates in units of powers of two and uses 4 bytes for its - own overhead. */ + own overhead. */ #define SYMBOL_BLOCK_SIZE \ ((1020 - sizeof (struct symbol_block *)) / sizeof (union aligned_Lisp_Symbol)) @@ -3255,7 +3526,7 @@ Its value and function definition are void, and its property list is nil. */) union aligned_Lisp_Misc { union Lisp_Misc m; -#ifdef USE_LSB_TAG +#if USE_LSB_TAG unsigned char c[(sizeof (union Lisp_Misc) + (1 << GCTYPEBITS) - 1) & -(1 << GCTYPEBITS)]; #endif @@ -3578,8 +3849,6 @@ mem_find (void *start) } -#ifdef NEED_MEM_INSERT - /* Insert a new node into the tree for a block of memory with start address START, end address END, and type TYPE. Value is a pointer to the node that was inserted. */ @@ -3727,8 +3996,6 @@ mem_insert_fixup (struct mem_node *x) mem_root->color = MEM_BLACK; } -#endif /* NEED_MEM_INSERT */ - /* (x) (y) / \ / \ @@ -4067,7 +4334,34 @@ live_misc_p (struct mem_node *m, void *p) static inline int live_vector_p (struct mem_node *m, void *p) { - return (p == m->start && m->type == MEM_TYPE_VECTORLIKE); + if (m->type == MEM_TYPE_VECTOR_BLOCK) + { + /* This memory node corresponds to a vector block. */ + struct vector_block *block = (struct vector_block *) m->start; + struct Lisp_Vector *vector = (struct Lisp_Vector *) block->data; + + /* P is in the block's allocation range. Scan the block + up to P and see whether P points to the start of some + vector which is not on a free list. FIXME: check whether + some allocation patterns (probably a lot of short vectors) + may cause a substantial overhead of this loop. */ + while (VECTOR_IN_BLOCK (vector, block) + && vector <= (struct Lisp_Vector *) p) + { + if ((vector->header.size & VECTOR_FREE_LIST_FLAG) + == VECTOR_FREE_LIST_FLAG) + vector = ADVANCE (vector, (vector->header.size + & (VECTOR_BLOCK_SIZE - 1))); + else if (vector == p) + return 1; + else + vector = ADVANCE (vector, vector->header.next.nbytes); + } + } + else if (m->type == MEM_TYPE_VECTORLIKE && p == m->start) + /* This memory node corresponds to a large vector. */ + return 1; + return 0; } @@ -4214,14 +4508,10 @@ mark_maybe_pointer (void *p) { struct mem_node *m; - /* Quickly rule out some values which can't point to Lisp data. */ - if ((intptr_t) p % -#ifdef USE_LSB_TAG - 8 /* USE_LSB_TAG needs Lisp data to be aligned on multiples of 8. */ -#else - 2 /* We assume that Lisp data is aligned on even addresses. */ -#endif - ) + /* Quickly rule out some values which can't point to Lisp data. + USE_LSB_TAG needs Lisp data to be aligned on multiples of 1 << GCTYPEBITS. + Otherwise, assume that Lisp data is aligned on even addresses. */ + if ((intptr_t) p % (USE_LSB_TAG ? 1 << GCTYPEBITS : 2)) return; m = mem_find (p); @@ -4267,6 +4557,7 @@ mark_maybe_pointer (void *p) break; case MEM_TYPE_VECTORLIKE: + case MEM_TYPE_VECTOR_BLOCK: if (live_vector_p (m, p)) { Lisp_Object tem; @@ -4296,8 +4587,8 @@ mark_maybe_pointer (void *p) wider than a pointer might allocate a Lisp_Object in non-adjacent halves. If USE_LSB_TAG, the bottom half is not a valid pointer, but it should suffice to widen it to to a Lisp_Object and check it that way. */ -#if defined USE_LSB_TAG || UINTPTR_MAX >> VALBITS != 0 -# if !defined USE_LSB_TAG && UINTPTR_MAX >> VALBITS >> GCTYPEBITS != 0 +#if USE_LSB_TAG || VAL_MAX < UINTPTR_MAX +# if !USE_LSB_TAG && VAL_MAX < UINTPTR_MAX >> GCTYPEBITS /* If tag bits straddle pointer-word boundaries, neither mark_maybe_pointer nor mark_maybe_object can follow the pointers. This should not occur on any practical porting target. */ @@ -4317,6 +4608,12 @@ mark_maybe_pointer (void *p) static void mark_memory (void *start, void *end) +#ifdef __clang__ + /* Do not allow -faddress-sanitizer to check this function, since it + crosses the function stack boundary, and thus would yield many + false positives. */ + __attribute__((no_address_safety_analysis)) +#endif { void **pp; int i; @@ -4358,7 +4655,7 @@ mark_memory (void *start, void *end) void *p = *(void **) ((char *) pp + i); mark_maybe_pointer (p); if (POINTERS_MIGHT_HIDE_IN_OBJECTS) - mark_maybe_object (widen_to_Lisp_Object (p)); + mark_maybe_object (XIL ((intptr_t) p)); } } @@ -4700,6 +4997,7 @@ valid_lisp_object_p (Lisp_Object obj) return live_float_p (m, p); case MEM_TYPE_VECTORLIKE: + case MEM_TYPE_VECTOR_BLOCK: return live_vector_p (m, p); default: @@ -4721,11 +5019,11 @@ valid_lisp_object_p (Lisp_Object obj) 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. */ -static POINTER_TYPE * +static void * pure_alloc (size_t size, int type) { - POINTER_TYPE *result; -#ifdef USE_LSB_TAG + void *result; +#if USE_LSB_TAG size_t alignment = (1 << GCTYPEBITS); #else size_t alignment = sizeof (EMACS_INT); @@ -4790,14 +5088,14 @@ check_pure_size (void) address. Return NULL if not found. */ static char * -find_string_data_in_pure (const char *data, EMACS_INT nbytes) +find_string_data_in_pure (const char *data, ptrdiff_t nbytes) { int i; - EMACS_INT skip, bm_skip[256], last_char_skip, infinity, start, start_max; + ptrdiff_t skip, bm_skip[256], last_char_skip, infinity, start, start_max; const unsigned char *p; char *non_lisp_beg; - if (pure_bytes_used_non_lisp < nbytes + 1) + if (pure_bytes_used_non_lisp <= nbytes) return NULL; /* Set up the Boyer-Moore table. */ @@ -4861,7 +5159,7 @@ find_string_data_in_pure (const char *data, EMACS_INT nbytes) Lisp_Object make_pure_string (const char *data, - EMACS_INT nchars, EMACS_INT nbytes, int multibyte) + ptrdiff_t nchars, ptrdiff_t nbytes, int multibyte) { Lisp_Object string; struct Lisp_String *s; @@ -4889,7 +5187,7 @@ make_pure_c_string (const char *data) { Lisp_Object string; struct Lisp_String *s; - EMACS_INT nchars = strlen (data); + ptrdiff_t nchars = strlen (data); s = (struct Lisp_String *) pure_alloc (sizeof *s, Lisp_String); s->size = nchars; @@ -4935,8 +5233,8 @@ make_pure_float (double num) /* Return a vector with room for LEN Lisp_Objects allocated from pure space. */ -Lisp_Object -make_pure_vector (EMACS_INT len) +static Lisp_Object +make_pure_vector (ptrdiff_t len) { Lisp_Object new; struct Lisp_Vector *p; @@ -4980,15 +5278,15 @@ Does not copy symbols. Copies strings without text properties. */) else if (COMPILEDP (obj) || VECTORP (obj)) { register struct Lisp_Vector *vec; - register EMACS_INT i; - EMACS_INT size; + register ptrdiff_t i; + ptrdiff_t size; size = ASIZE (obj); if (size & PSEUDOVECTOR_FLAG) size &= PSEUDOVECTOR_SIZE_MASK; vec = XVECTOR (make_pure_vector (size)); for (i = 0; i < size; i++) - vec->contents[i] = Fpurecopy (XVECTOR (obj)->contents[i]); + vec->contents[i] = Fpurecopy (AREF (obj, i)); if (COMPILEDP (obj)) { XSETPVECTYPE (vec, PVEC_COMPILED); @@ -5033,10 +5331,10 @@ staticpro (Lisp_Object *varaddress) /* Temporarily prevent garbage collection. */ -int +ptrdiff_t inhibit_garbage_collection (void) { - int count = SPECPDL_INDEX (); + ptrdiff_t count = SPECPDL_INDEX (); specbind (Qgc_cons_threshold, make_number (MOST_POSITIVE_FIXNUM)); return count; @@ -5062,7 +5360,7 @@ See Info node `(elisp)Garbage Collection'. */) ptrdiff_t i; int message_p; Lisp_Object total[8]; - int count = SPECPDL_INDEX (); + ptrdiff_t count = SPECPDL_INDEX (); EMACS_TIME t1, t2, t3; if (abort_on_gc) @@ -5086,7 +5384,8 @@ See Info node `(elisp)Garbage Collection'. */) turned off in that buffer. Calling truncate_undo_list on Qt tends to return NULL, which effectively turns undo back on. So don't call truncate_undo_list if undo_list is Qt. */ - if (! NILP (nextb->BUFFER_INTERNAL_FIELD (name)) && ! EQ (nextb->BUFFER_INTERNAL_FIELD (undo_list), Qt)) + if (! NILP (nextb->BUFFER_INTERNAL_FIELD (name)) + && ! EQ (nextb->BUFFER_INTERNAL_FIELD (undo_list), Qt)) truncate_undo_list (nextb); /* Shrink buffer gaps, but skip indirect and dead buffers. */ @@ -5357,18 +5656,20 @@ See Info node `(elisp)Garbage Collection'. */) if (!NILP (Vpost_gc_hook)) { - int gc_count = inhibit_garbage_collection (); + ptrdiff_t gc_count = inhibit_garbage_collection (); safe_run_hooks (Qpost_gc_hook); unbind_to (gc_count, Qnil); } /* Accumulate statistics. */ - EMACS_GET_TIME (t2); - EMACS_SUB_TIME (t3, t2, t1); if (FLOATP (Vgc_elapsed)) - Vgc_elapsed = make_float (XFLOAT_DATA (Vgc_elapsed) + - EMACS_SECS (t3) + - EMACS_USECS (t3) * 1.0e-6); + { + EMACS_GET_TIME (t2); + EMACS_SUB_TIME (t3, t2, t1); + Vgc_elapsed = make_float (XFLOAT_DATA (Vgc_elapsed) + + EMACS_TIME_TO_DOUBLE (t3)); + } + gcs_done++; return Flist (sizeof total / sizeof *total, total); @@ -5442,8 +5743,8 @@ ptrdiff_t mark_object_loop_halt EXTERNALLY_VISIBLE; static void mark_vectorlike (struct Lisp_Vector *ptr) { - EMACS_INT size = ptr->header.size; - EMACS_INT i; + ptrdiff_t size = ptr->header.size; + ptrdiff_t i; eassert (!VECTOR_MARKED_P (ptr)); VECTOR_MARK (ptr); /* Else mark it */ @@ -5837,7 +6138,7 @@ mark_buffer (Lisp_Object buf) } /* Mark the Lisp pointers in the terminal objects. - Called by the Fgarbage_collector. */ + Called by Fgarbage_collect. */ static void mark_terminals (void) @@ -6236,33 +6537,7 @@ gc_sweep (void) } } - /* Free all unmarked vectors */ - { - register struct Lisp_Vector *vector = all_vectors, *prev = 0, *next; - total_vector_size = 0; - - while (vector) - if (!VECTOR_MARKED_P (vector)) - { - if (prev) - prev->header.next = vector->header.next; - else - all_vectors = vector->header.next.vector; - next = vector->header.next.vector; - lisp_free (vector); - vector = next; - - } - else - { - VECTOR_UNMARK (vector); - if (vector->header.size & PSEUDOVECTOR_FLAG) - total_vector_size += PSEUDOVECTOR_SIZE_MASK & vector->header.size; - else - total_vector_size += vector->header.size; - prev = vector, vector = vector->header.next.vector; - } - } + sweep_vectors (); #ifdef GC_CHECK_STRING_BYTES if (!noninteractive) @@ -6324,7 +6599,7 @@ Lisp_Object which_symbols (Lisp_Object obj, EMACS_INT find_max) { struct symbol_block *sblk; - int gc_count = inhibit_garbage_collection (); + ptrdiff_t gc_count = inhibit_garbage_collection (); Lisp_Object found = Qnil; if (! DEADP (obj)) @@ -6399,7 +6674,6 @@ init_alloc_once (void) Vdead = make_pure_string ("DEAD", 4, 4, 0); #endif - all_vectors = 0; ignore_warnings = 1; #ifdef DOUG_LEA_MALLOC mallopt (M_TRIM_THRESHOLD, 128*1024); /* trim threshold */ @@ -6412,6 +6686,7 @@ init_alloc_once (void) init_marker (); init_float (); init_intervals (); + init_vectors (); init_weak_hash_tables (); #ifdef REL_ALLOC