/* Storage allocation and gc for GNU Emacs Lisp interpreter.
-Copyright (C) 1985-1986, 1988, 1993-1995, 1997-2015 Free Software
+Copyright (C) 1985-1986, 1988, 1993-1995, 1997-2016 Free Software
Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
#endif
#include "lisp.h"
-#include "process.h"
+#include "dispextern.h"
#include "intervals.h"
#include "puresize.h"
+#include "systime.h"
#include "character.h"
#include "buffer.h"
#include "window.h"
static bool valgrind_p;
#endif
-/* 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_CHECK_MARKED_OBJECTS means do sanity checks on allocated objects. */
/* GC_MALLOC_CHECK defined means perform validity checks of malloc'd
memory. Can do this only if using gmalloc.c and if not checking
#include "w32heap.h" /* for sbrk */
#endif
+#if defined DOUG_LEA_MALLOC || defined GNU_LINUX
+/* The address where the heap starts. */
+void *
+my_heap_start (void)
+{
+ static void *start;
+ if (! start)
+ start = sbrk (0);
+ return start;
+}
+#endif
+
#ifdef DOUG_LEA_MALLOC
#include <malloc.h>
#define MMAP_MAX_AREAS 100000000
-#endif /* not DOUG_LEA_MALLOC */
+/* A pointer to the memory allocated that copies that static data
+ inside glibc's malloc. */
+static void *malloc_state_ptr;
+
+/* Get and free this pointer; useful around unexec. */
+void
+alloc_unexec_pre (void)
+{
+ malloc_state_ptr = malloc_get_state ();
+}
+void
+alloc_unexec_post (void)
+{
+ free (malloc_state_ptr);
+}
+
+/* Restore the dumped malloc state. Because malloc can be invoked
+ even before main (e.g. by the dynamic linker), the dumped malloc
+ state must be restored as early as possible using this special hook. */
+static void
+malloc_initialize_hook (void)
+{
+ static bool malloc_using_checking;
+
+ if (! initialized)
+ {
+ my_heap_start ();
+ malloc_using_checking = getenv ("MALLOC_CHECK_") != NULL;
+ }
+ else
+ {
+ if (!malloc_using_checking)
+ {
+ /* Work around a bug in glibc's malloc. MALLOC_CHECK_ must be
+ ignored if the heap to be restored was constructed without
+ malloc checking. Can't use unsetenv, since that calls malloc. */
+ char **p = environ;
+ if (p)
+ for (; *p; p++)
+ if (strncmp (*p, "MALLOC_CHECK_=", 14) == 0)
+ {
+ do
+ *p = p[1];
+ while (*++p);
+
+ break;
+ }
+ }
+
+ malloc_set_state (malloc_state_ptr);
+# ifndef XMALLOC_OVERRUN_CHECK
+ alloc_unexec_post ();
+# endif
+ }
+}
+
+# ifndef __MALLOC_HOOK_VOLATILE
+# define __MALLOC_HOOK_VOLATILE
+# endif
+voidfuncptr __MALLOC_HOOK_VOLATILE __malloc_initialize_hook
+ = malloc_initialize_hook;
+
+#endif
/* Mark, unmark, query mark bit of a Lisp string. S must be a pointer
to a struct Lisp_String. */
static ptrdiff_t pure_bytes_used_before_overflow;
-/* True if P points into pure space. */
-
-#define PURE_POINTER_P(P) \
- ((uintptr_t) (P) - (uintptr_t) purebeg <= pure_size)
-
/* Index in pure at which next pure Lisp object will be allocated.. */
static ptrdiff_t pure_bytes_used_lisp;
MEM_TYPE_SPARE
};
-#if GC_MARK_STACK || defined GC_MALLOC_CHECK
-
/* A unique object in pure space used to make some Lisp objects
on free lists recognizable in O(1). */
static void mem_delete_fixup (struct mem_node *);
static struct mem_node *mem_find (void *);
-#endif /* GC_MARK_STACK || GC_MALLOC_CHECK */
-
#ifndef DEADP
# define DEADP(x) 0
#endif
-/* Recording what needs to be marked for gc. */
-
-struct gcpro *gcprolist;
-
/* Addresses of staticpro'd variables. Initialize it to a nonzero
value; otherwise some compilers put it into BSS. */
return (void *) ROUNDUP ((uintptr_t) ptr, alignment);
}
+/* Extract the pointer hidden within A, if A is not a symbol.
+ If A is a symbol, extract the hidden pointer's offset from lispsym,
+ converted to void *. */
+
+#define macro_XPNTR_OR_SYMBOL_OFFSET(a) \
+ ((void *) (intptr_t) (USE_LSB_TAG ? XLI (a) - XTYPE (a) : XLI (a) & VALMASK))
+
+/* Extract the pointer hidden within A. */
+
+#define macro_XPNTR(a) \
+ ((void *) ((intptr_t) XPNTR_OR_SYMBOL_OFFSET (a) \
+ + (SYMBOLP (a) ? (char *) lispsym : NULL)))
+
+/* For pointer access, define XPNTR and XPNTR_OR_SYMBOL_OFFSET as
+ functions, as functions are cleaner and can be used in debuggers.
+ Also, define them as macros if being compiled with GCC without
+ optimization, for performance in that case. The macro_* names are
+ private to this section of code. */
+
+static ATTRIBUTE_UNUSED void *
+XPNTR_OR_SYMBOL_OFFSET (Lisp_Object a)
+{
+ return macro_XPNTR_OR_SYMBOL_OFFSET (a);
+}
+static ATTRIBUTE_UNUSED void *
+XPNTR (Lisp_Object a)
+{
+ return macro_XPNTR (a);
+}
+
+#if DEFINE_KEY_OPS_AS_MACROS
+# define XPNTR_OR_SYMBOL_OFFSET(a) macro_XPNTR_OR_SYMBOL_OFFSET (a)
+# define XPNTR(a) macro_XPNTR (a)
+#endif
+
static void
XFLOAT_INIT (Lisp_Object f, double n)
{
XFLOAT (f)->u.data = n;
}
+#ifdef DOUG_LEA_MALLOC
static bool
pointers_fit_in_lispobj_p (void)
{
regions. */
return pointers_fit_in_lispobj_p () && !might_dump;
}
+#endif
/* Head of a circularly-linked list of extant finalizers. */
static struct Lisp_Finalizer finalizers;
malloc_probe (size); \
} while (0)
+static void *lmalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1));
+static void *lrealloc (void *, size_t);
-/* Like malloc but check for no memory and block interrupt input.. */
+/* Like malloc but check for no memory and block interrupt input. */
void *
xmalloc (size_t size)
void *val;
MALLOC_BLOCK_INPUT;
- val = malloc (size);
+ val = lmalloc (size);
MALLOC_UNBLOCK_INPUT;
if (!val && size)
void *val;
MALLOC_BLOCK_INPUT;
- val = malloc (size);
+ val = lmalloc (size);
MALLOC_UNBLOCK_INPUT;
if (!val && size)
/* We must call malloc explicitly when BLOCK is 0, since some
reallocs don't do this. */
if (! block)
- val = malloc (size);
+ val = lmalloc (size);
else
- val = realloc (block, size);
+ val = lrealloc (block, size);
MALLOC_UNBLOCK_INPUT;
if (!val && size)
xnmalloc (ptrdiff_t nitems, ptrdiff_t item_size)
{
eassert (0 <= nitems && 0 < item_size);
- if (min (PTRDIFF_MAX, SIZE_MAX) / item_size < nitems)
+ ptrdiff_t nbytes;
+ if (INT_MULTIPLY_WRAPV (nitems, item_size, &nbytes) || SIZE_MAX < nbytes)
memory_full (SIZE_MAX);
- return xmalloc (nitems * item_size);
+ return xmalloc (nbytes);
}
xnrealloc (void *pa, ptrdiff_t nitems, ptrdiff_t item_size)
{
eassert (0 <= nitems && 0 < item_size);
- if (min (PTRDIFF_MAX, SIZE_MAX) / item_size < nitems)
+ ptrdiff_t nbytes;
+ if (INT_MULTIPLY_WRAPV (nitems, item_size, &nbytes) || SIZE_MAX < nbytes)
memory_full (SIZE_MAX);
- return xrealloc (pa, nitems * item_size);
+ return xrealloc (pa, nbytes);
}
xpalloc (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min,
ptrdiff_t nitems_max, ptrdiff_t item_size)
{
+ ptrdiff_t n0 = *nitems;
+ eassume (0 < item_size && 0 < nitems_incr_min && 0 <= n0 && -1 <= nitems_max);
+
/* The approximate size to use for initial small allocation
requests. This is the largest "small" request for the GNU C
library malloc. */
enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 };
/* If the array is tiny, grow it to about (but no greater than)
- DEFAULT_MXFAST bytes. Otherwise, grow it by about 50%. */
- ptrdiff_t n = *nitems;
- ptrdiff_t tiny_max = DEFAULT_MXFAST / item_size - n;
- ptrdiff_t half_again = n >> 1;
- ptrdiff_t incr_estimate = max (tiny_max, half_again);
-
- /* Adjust the increment according to three constraints: NITEMS_INCR_MIN,
+ DEFAULT_MXFAST bytes. Otherwise, grow it by about 50%.
+ Adjust the growth according to three constraints: NITEMS_INCR_MIN,
NITEMS_MAX, and what the C language can represent safely. */
- ptrdiff_t C_language_max = min (PTRDIFF_MAX, SIZE_MAX) / item_size;
- ptrdiff_t n_max = (0 <= nitems_max && nitems_max < C_language_max
- ? nitems_max : C_language_max);
- ptrdiff_t nitems_incr_max = n_max - n;
- ptrdiff_t incr = max (nitems_incr_min, min (incr_estimate, nitems_incr_max));
- eassert (0 < item_size && 0 < nitems_incr_min && 0 <= n && -1 <= nitems_max);
+ ptrdiff_t n, nbytes;
+ if (INT_ADD_WRAPV (n0, n0 >> 1, &n))
+ n = PTRDIFF_MAX;
+ if (0 <= nitems_max && nitems_max < n)
+ n = nitems_max;
+
+ ptrdiff_t adjusted_nbytes
+ = ((INT_MULTIPLY_WRAPV (n, item_size, &nbytes) || SIZE_MAX < nbytes)
+ ? min (PTRDIFF_MAX, SIZE_MAX)
+ : nbytes < DEFAULT_MXFAST ? DEFAULT_MXFAST : 0);
+ if (adjusted_nbytes)
+ {
+ n = adjusted_nbytes / item_size;
+ nbytes = adjusted_nbytes - adjusted_nbytes % item_size;
+ }
+
if (! pa)
*nitems = 0;
- if (nitems_incr_max < incr)
+ if (n - n0 < nitems_incr_min
+ && (INT_ADD_WRAPV (n0, nitems_incr_min, &n)
+ || (0 <= nitems_max && nitems_max < n)
+ || INT_MULTIPLY_WRAPV (n, item_size, &nbytes)))
memory_full (SIZE_MAX);
- n += incr;
- pa = xrealloc (pa, n * item_size);
+ pa = xrealloc (pa, nbytes);
*nitems = n;
return pa;
}
allocated_mem_type = type;
#endif
- val = malloc (nbytes);
+ val = lmalloc (nbytes);
#if ! USE_LSB_TAG
/* If the memory just allocated cannot be addressed thru a Lisp
}
#endif
-#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
+#ifndef GC_MALLOC_CHECK
if (val && type != MEM_TYPE_NON_LISP)
mem_insert (val, (char *) val + nbytes, type);
#endif
{
MALLOC_BLOCK_INPUT;
free (block);
-#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
+#ifndef GC_MALLOC_CHECK
mem_delete (mem_find (block));
#endif
MALLOC_UNBLOCK_INPUT;
/* Use aligned_alloc if it or a simple substitute is available.
Address sanitization breaks aligned allocation, as of gcc 4.8.2 and
- clang 3.3 anyway. */
+ clang 3.3 anyway. Aligned allocation is incompatible with
+ unexmacosx.c, so don't use it on Darwin. */
-#if ! ADDRESS_SANITIZER
+#if ! ADDRESS_SANITIZER && !defined DARWIN_OS
# if !defined SYSTEM_MALLOC && !defined DOUG_LEA_MALLOC && !defined HYBRID_MALLOC
# define USE_ALIGNED_ALLOC 1
+# ifndef HAVE_ALIGNED_ALLOC
/* Defined in gmalloc.c. */
void *aligned_alloc (size_t, size_t);
+# endif
# elif defined HYBRID_MALLOC
-# if defined ALIGNED_ALLOC || defined HAVE_POSIX_MEMALIGN
+# if defined HAVE_ALIGNED_ALLOC || defined HAVE_POSIX_MEMALIGN
# define USE_ALIGNED_ALLOC 1
# define aligned_alloc hybrid_aligned_alloc
/* Defined in gmalloc.c. */
val = free_ablock;
free_ablock = free_ablock->x.next_free;
-#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
+#ifndef GC_MALLOC_CHECK
if (type != MEM_TYPE_NON_LISP)
mem_insert (val, (char *) val + nbytes, type);
#endif
struct ablocks *abase = ABLOCK_ABASE (ablock);
MALLOC_BLOCK_INPUT;
-#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
+#ifndef GC_MALLOC_CHECK
mem_delete (mem_find (block));
#endif
/* Put on free list. */
MALLOC_UNBLOCK_INPUT;
}
+#if !defined __GNUC__ && !defined __alignof__
+# define __alignof__(type) alignof (type)
+#endif
+
+/* True if malloc returns a multiple of GCALIGNMENT. In practice this
+ holds if __alignof__ (max_align_t) is a multiple. Use __alignof__
+ if available, as otherwise this check would fail with GCC x86.
+ This is a macro, not an enum constant, for portability to HP-UX
+ 10.20 cc and AIX 3.2.5 xlc. */
+#define MALLOC_IS_GC_ALIGNED (__alignof__ (max_align_t) % GCALIGNMENT == 0)
+
+/* True if P is suitably aligned for SIZE, where Lisp alignment may be
+ needed if SIZE is Lisp-aligned. */
+
+static bool
+laligned (void *p, size_t size)
+{
+ return (MALLOC_IS_GC_ALIGNED || (intptr_t) p % GCALIGNMENT == 0
+ || size % GCALIGNMENT != 0);
+}
+
+/* Like malloc and realloc except that if SIZE is Lisp-aligned, make
+ sure the result is too, if necessary by reallocating (typically
+ with larger and larger sizes) until the allocator returns a
+ Lisp-aligned pointer. Code that needs to allocate C heap memory
+ for a Lisp object should use one of these functions to obtain a
+ pointer P; that way, if T is an enum Lisp_Type value and L ==
+ make_lisp_ptr (P, T), then XPNTR (L) == P and XTYPE (L) == T.
+
+ On typical modern platforms these functions' loops do not iterate.
+ On now-rare (and perhaps nonexistent) platforms, the loops in
+ theory could repeat forever. If an infinite loop is possible on a
+ platform, a build would surely loop and the builder can then send
+ us a bug report. Adding a counter to try to detect any such loop
+ would complicate the code (and possibly introduce bugs, in code
+ that's never really exercised) for little benefit. */
+
+static void *
+lmalloc (size_t size)
+{
+#if USE_ALIGNED_ALLOC
+ if (! MALLOC_IS_GC_ALIGNED)
+ return aligned_alloc (GCALIGNMENT, size);
+#endif
+
+ void *p;
+ while (true)
+ {
+ p = malloc (size);
+ if (laligned (p, size))
+ break;
+ free (p);
+ size_t bigger;
+ if (! INT_ADD_WRAPV (size, GCALIGNMENT, &bigger))
+ size = bigger;
+ }
+
+ eassert ((intptr_t) p % GCALIGNMENT == 0);
+ return p;
+}
+
+static void *
+lrealloc (void *p, size_t size)
+{
+ while (true)
+ {
+ p = realloc (p, size);
+ if (laligned (p, size))
+ break;
+ size_t bigger;
+ if (! INT_ADD_WRAPV (size, GCALIGNMENT, &bigger))
+ size = bigger;
+ }
+
+ eassert ((intptr_t) p % GCALIGNMENT == 0);
+ return p;
+}
+
\f
/***********************************************************************
Interval Allocation
ptrdiff_t nbytes =
(s->size_byte < 0 ? s->size & ~ARRAY_MARK_FLAG : s->size_byte);
- if (!PURE_POINTER_P (s)
- && s->data
- && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
+ if (!PURE_P (s) && s->data && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
emacs_abort ();
return nbytes;
}
{
nbytes = XINT (length);
val = make_uninit_string (nbytes);
- memset (SDATA (val), c, nbytes);
- SDATA (val)[nbytes] = 0;
+ if (nbytes)
+ {
+ memset (SDATA (val), c, nbytes);
+ SDATA (val)[nbytes] = 0;
+ }
}
else
{
EMACS_INT string_len = XINT (length);
unsigned char *p, *beg, *end;
- if (string_len > STRING_BYTES_MAX / len)
+ if (INT_MULTIPLY_WRAPV (len, string_len, &nbytes))
string_overflow ();
- nbytes = len * string_len;
val = make_uninit_multibyte_string (string_len, nbytes);
for (beg = SDATA (val), p = beg, end = beg + nbytes; p < end; p += len)
{
memcpy (p, beg, len);
}
}
- *p = 0;
+ if (nbytes)
+ *p = 0;
}
return val;
free_cons (struct Lisp_Cons *ptr)
{
ptr->u.chain = cons_free_list;
-#if GC_MARK_STACK
ptr->car = Vdead;
-#endif
cons_free_list = ptr;
consing_since_gc -= sizeof *ptr;
total_free_conses++;
{
struct vector_block *block = xmalloc (sizeof *block);
-#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
+#ifndef GC_MALLOC_CHECK
mem_insert (block->data, block->data + VECTOR_BLOCK_BYTES,
MEM_TYPE_VECTOR_BLOCK);
#endif
if (free_this_block)
{
*bprev = block->next;
-#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
+#ifndef GC_MALLOC_CHECK
mem_delete (mem_find (block->data));
#endif
xfree (block);
if (min ((nbytes_max - header_size) / word_size, MOST_POSITIVE_FIXNUM) < len)
memory_full (SIZE_MAX);
v = allocate_vectorlike (len);
- v->header.size = len;
+ if (len)
+ v->header.size = len;
return v;
}
}
}
+#ifdef HAVE_MODULES
+/* Create a new module user ptr object. */
+Lisp_Object
+make_user_ptr (void (*finalizer) (void *), void *p)
+{
+ Lisp_Object obj;
+ struct Lisp_User_Ptr *uptr;
+
+ obj = allocate_misc (Lisp_Misc_User_Ptr);
+ uptr = XUSER_PTR (obj);
+ uptr->finalizer = finalizer;
+ uptr->p = p;
+ return obj;
+}
+
+#endif
+
static void
init_finalizer_list (struct Lisp_Finalizer *head)
{
static Lisp_Object
run_finalizer_handler (Lisp_Object args)
{
- add_to_log ("finalizer failed: %S", args, Qnil);
+ add_to_log ("finalizer failed: %S", args);
return Qnil;
}
static void
run_finalizer_function (Lisp_Object function)
{
- struct gcpro gcpro1;
ptrdiff_t count = SPECPDL_INDEX ();
- GCPRO1 (function);
specbind (Qinhibit_quit, Qt);
internal_condition_case_1 (call0, function, Qt, run_finalizer_handler);
unbind_to (count, Qnil);
- UNGCPRO;
}
static void
C Stack Marking
************************************************************************/
-#if GC_MARK_STACK || defined GC_MALLOC_CHECK
-
/* Conservative C stack marking requires a method to identify possibly
live Lisp objects given a pointer value. We do this by keeping
track of blocks of Lisp data that are allocated in a red-black tree
c = mem_root;
parent = NULL;
-#if GC_MARK_STACK != GC_MAKE_GCPROS_NOOPS
-
- while (c != MEM_NIL)
- {
- if (start >= c->start && start < c->end)
- emacs_abort ();
- parent = c;
- c = start < c->start ? c->left : c->right;
- }
-
-#else /* GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS */
-
while (c != MEM_NIL)
{
parent = c;
c = start < c->start ? c->left : c->right;
}
-#endif /* GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS */
-
/* Create a new node. */
#ifdef GC_MALLOC_CHECK
x = malloc (sizeof *x);
&& !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
-
-/* Currently not used, but may be called from gdb. */
-
-void dump_zombies (void) EXTERNALLY_VISIBLE;
-
-/* Array of objects that are kept alive because the C stack contains
- a pattern that looks like a reference to them. */
-
-#define MAX_ZOMBIES 10
-static Lisp_Object zombies[MAX_ZOMBIES];
-
-/* Number of zombie objects. */
-
-static EMACS_INT nzombies;
-
-/* Number of garbage collections. */
-
-static EMACS_INT ngcs;
-
-/* Average percentage of zombies per collection. */
-
-static double avg_zombies;
-
-/* Max. number of live and zombie objects. */
-
-static EMACS_INT max_live, max_zombies;
-
-/* Average number of live objects per GC. */
-
-static double avg_live;
-
-DEFUN ("gc-status", Fgc_status, Sgc_status, 0, 0, "",
- doc: /* Show information about live and zombie objects. */)
- (void)
-{
- Lisp_Object zombie_list = Qnil;
- for (int i = 0; i < min (MAX_ZOMBIES, nzombies); i++)
- zombie_list = Fcons (zombies[i], zombie_list);
- AUTO_STRING (format, ("%d GCs, avg live/zombies = %.2f/%.2f (%f%%),"
- " max %d/%d\nzombies: %S"));
- return CALLN (Fmessage, format,
- make_number (ngcs), make_float (avg_live),
- make_float (avg_zombies),
- make_float (avg_zombies / avg_live / 100),
- make_number (max_live), make_number (max_zombies),
- zombie_list);
-}
-
-#endif /* GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES */
-
-
/* Mark OBJ if we can prove it's a Lisp_Object. */
static void
mark_maybe_object (Lisp_Object obj)
{
- void *po;
- struct mem_node *m;
-
#if USE_VALGRIND
if (valgrind_p)
VALGRIND_MAKE_MEM_DEFINED (&obj, sizeof (obj));
if (INTEGERP (obj))
return;
- po = (void *) XPNTR (obj);
- m = mem_find (po);
+ void *po = XPNTR (obj);
+ struct mem_node *m = mem_find (po);
if (m != MEM_NIL)
{
- bool mark_p = 0;
+ bool mark_p = false;
switch (XTYPE (obj))
{
}
if (mark_p)
- {
-#if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
- if (nzombies < MAX_ZOMBIES)
- zombies[nzombies] = obj;
- ++nzombies;
-#endif
- mark_object (obj);
- }
+ mark_object (obj);
}
}
return (uintptr_t) p % GCALIGNMENT == 0;
}
+#ifndef HAVE_MODULES
+enum { HAVE_MODULES = false };
+#endif
+
/* If P points to Lisp data, mark that as live if it isn't already
marked. */
VALGRIND_MAKE_MEM_DEFINED (&p, sizeof (p));
#endif
- if (!maybe_lisp_pointer (p))
- return;
+ if (sizeof (Lisp_Object) == sizeof (void *) || !HAVE_MODULES)
+ {
+ if (!maybe_lisp_pointer (p))
+ return;
+ }
+ else
+ {
+ /* For the wide-int case, also mark emacs_value tagged pointers,
+ which can be generated by emacs-module.c's value_to_lisp. */
+ p = (void *) ((uintptr_t) p & ~(GCALIGNMENT - 1));
+ }
m = mem_find (p);
if (m != MEM_NIL)
static void ATTRIBUTE_NO_SANITIZE_ADDRESS
mark_memory (void *start, void *end)
{
- void **pp;
- int i;
-
-#if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
- nzombies = 0;
-#endif
+ char *pp;
/* Make START the pointer to the start of the memory region,
if it isn't already. */
end = tem;
}
+ eassert (((uintptr_t) start) % GC_POINTER_ALIGNMENT == 0);
+
/* 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:
away. The only reference to the life string is through the
pointer `s'. */
- for (pp = start; (void *) pp < end; pp++)
- for (i = 0; i < sizeof *pp; i += GC_POINTER_ALIGNMENT)
- {
- void *p = *(void **) ((char *) pp + i);
- mark_maybe_pointer (p);
- mark_maybe_object (XIL ((intptr_t) p));
- }
+ for (pp = start; (void *) pp < end; pp += GC_POINTER_ALIGNMENT)
+ {
+ mark_maybe_pointer (*(void **) pp);
+ mark_maybe_object (*(Lisp_Object *) pp);
+ }
}
#if !defined GC_SAVE_REGISTERS_ON_STACK && !defined GC_SETJMP_WORKS
#endif /* not GC_SAVE_REGISTERS_ON_STACK && not GC_SETJMP_WORKS */
-#if GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS
-
-/* Abort if anything GCPRO'd doesn't survive the GC. */
-
-static void
-check_gcpros (void)
-{
- struct gcpro *p;
- ptrdiff_t i;
-
- for (p = gcprolist; p; p = p->next)
- for (i = 0; i < p->nvars; ++i)
- if (!survives_gc_p (p->var[i]))
- /* FIXME: It's not necessarily a bug. It might just be that the
- GCPRO is unnecessary or should release the object sooner. */
- emacs_abort ();
-}
-
-#elif GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
-
-void
-dump_zombies (void)
-{
- int i;
-
- fprintf (stderr, "\nZombies kept alive = %"pI"d:\n", nzombies);
- for (i = 0; i < min (MAX_ZOMBIES, nzombies); ++i)
- {
- fprintf (stderr, " %d = ", i);
- debug_print (zombies[i]);
- }
-}
-
-#endif /* GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES */
-
-
/* Mark live Lisp objects on the C stack.
There are several system-dependent problems to consider when
#ifdef GC_MARK_SECONDARY_STACK
GC_MARK_SECONDARY_STACK ();
#endif
-
-#if GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS
- check_gcpros ();
-#endif
}
-#else /* GC_MARK_STACK == 0 */
-
-#define mark_maybe_object(obj) emacs_abort ()
-
-#endif /* GC_MARK_STACK != 0 */
-
static bool
c_symbol_p (struct Lisp_Symbol *sym)
{
int
valid_lisp_object_p (Lisp_Object obj)
{
- void *p;
-#if GC_MARK_STACK
- struct mem_node *m;
-#endif
-
if (INTEGERP (obj))
return 1;
- p = (void *) XPNTR (obj);
- if (PURE_POINTER_P (p))
+ void *p = XPNTR (obj);
+ if (PURE_P (p))
return 1;
if (SYMBOLP (obj) && c_symbol_p (p))
if (p == &buffer_defaults || p == &buffer_local_symbols)
return 2;
-#if !GC_MARK_STACK
- return valid_pointer_p (p);
-#else
-
- m = mem_find (p);
+ struct mem_node *m = mem_find (p);
if (m == MEM_NIL)
{
}
return 0;
-#endif
-}
-
-/* If GC_MARK_STACK, return 1 if STR is a relocatable data of Lisp_String
- (i.e. there is a non-pure Lisp_Object X so that SDATA (X) == STR) and 0
- if not. Otherwise we can't rely on valid_lisp_object_p and return -1.
- This function is slow and should be used for debugging purposes. */
-
-int
-relocatable_string_data_p (const char *str)
-{
- if (PURE_POINTER_P (str))
- return 0;
-#if GC_MARK_STACK
- if (str)
- {
- struct sdata *sdata
- = (struct sdata *) (str - offsetof (struct sdata, data));
-
- if (0 < valid_pointer_p (sdata)
- && 0 < valid_pointer_p (sdata->string)
- && maybe_lisp_pointer (sdata->string))
- return (valid_lisp_object_p
- (make_lisp_ptr (sdata->string, Lisp_String))
- && (const char *) sdata->string->data == str);
- }
- return 0;
-#endif /* GC_MARK_STACK */
- return -1;
}
/***********************************************************************
static Lisp_Object
purecopy (Lisp_Object obj)
{
- if (PURE_POINTER_P (XPNTR (obj)) || INTEGERP (obj) || SUBRP (obj))
+ if (INTEGERP (obj)
+ || (! SYMBOLP (obj) && PURE_P (XPNTR_OR_SYMBOL_OFFSET (obj)))
+ || SUBRP (obj))
return obj; /* Already pure. */
+ if (STRINGP (obj) && XSTRING (obj)->intervals)
+ message_with_string ("Dropping text-properties while making string `%s' pure",
+ obj, true);
+
if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing. */
{
Lisp_Object tmp = Fgethash (obj, Vpurify_flag, Qnil);
else if (FLOATP (obj))
obj = make_pure_float (XFLOAT_DATA (obj));
else if (STRINGP (obj))
- {
- if (XSTRING (obj)->intervals)
- message ("Dropping text-properties when making string pure");
- obj = make_pure_string (SSDATA (obj), SCHARS (obj),
- SBYTES (obj),
- STRING_MULTIBYTE (obj));
- }
+ obj = make_pure_string (SSDATA (obj), SCHARS (obj),
+ SBYTES (obj),
+ STRING_MULTIBYTE (obj));
else if (COMPILEDP (obj) || VECTORP (obj) || HASH_TABLE_P (obj))
{
struct Lisp_Vector *objp = XVECTOR (obj);
#ifdef HAVE_WINDOW_SYSTEM
-/* This code has a few issues on MS-Windows, see Bug#15876 and Bug#16140. */
-
-#if !defined (HAVE_NTGUI)
-
/* Remove unmarked font-spec and font-entity objects from ENTRY, which is
(DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...), and return changed entry. */
Lisp_Object obj = XCAR (tail);
/* Consider OBJ if it is (font-spec . [font-entity font-entity ...]). */
- if (CONSP (obj) && FONT_SPEC_P (XCAR (obj))
- && !VECTOR_MARKED_P (XFONT_SPEC (XCAR (obj)))
- && VECTORP (XCDR (obj)))
+ if (CONSP (obj) && GC_FONT_SPEC_P (XCAR (obj))
+ && !VECTOR_MARKED_P (GC_XFONT_SPEC (XCAR (obj)))
+ /* Don't use VECTORP here, as that calls ASIZE, which could
+ hit assertion violation during GC. */
+ && (VECTORLIKEP (XCDR (obj))
+ && ! (gc_asize (XCDR (obj)) & PSEUDOVECTOR_FLAG)))
{
- ptrdiff_t i, size = ASIZE (XCDR (obj)) & ~ARRAY_MARK_FLAG;
+ ptrdiff_t i, size = gc_asize (XCDR (obj));
+ Lisp_Object obj_cdr = XCDR (obj);
/* If font-spec is not marked, most likely all font-entities
are not marked too. But we must be sure that nothing is
marked within OBJ before we really drop it. */
for (i = 0; i < size; i++)
- if (VECTOR_MARKED_P (XFONT_ENTITY (AREF (XCDR (obj), i))))
- break;
+ {
+ Lisp_Object objlist;
+
+ if (VECTOR_MARKED_P (GC_XFONT_ENTITY (AREF (obj_cdr, i))))
+ break;
+
+ objlist = AREF (AREF (obj_cdr, i), FONT_OBJLIST_INDEX);
+ for (; CONSP (objlist); objlist = XCDR (objlist))
+ {
+ Lisp_Object val = XCAR (objlist);
+ struct font *font = GC_XFONT_OBJECT (val);
+
+ if (!NILP (AREF (val, FONT_TYPE_INDEX))
+ && VECTOR_MARKED_P(font))
+ break;
+ }
+ if (CONSP (objlist))
+ {
+ /* Found a marked font, bail out. */
+ break;
+ }
+ }
if (i == size)
- drop = 1;
+ {
+ /* No marked fonts were found, so this entire font
+ entity can be dropped. */
+ drop = 1;
+ }
}
if (drop)
*prev = XCDR (tail);
return entry;
}
-#endif /* not HAVE_NTGUI */
-
/* Compact font caches on all terminals and mark
everything which is still here after compaction. */
for (t = terminal_list; t; t = t->next_terminal)
{
Lisp_Object cache = TERMINAL_FONT_CACHE (t);
-#if !defined (HAVE_NTGUI)
if (CONSP (cache))
{
Lisp_Object entry;
for (entry = XCDR (cache); CONSP (entry); entry = XCDR (entry))
XSETCAR (entry, compact_font_cache_entry (XCAR (entry)));
}
-#endif /* not HAVE_NTGUI */
mark_object (cache);
}
}
don't let that cause a recursive GC. */
consing_since_gc = 0;
- /* Save what's currently displayed in the echo area. */
- message_p = push_message ();
- record_unwind_protect_void (pop_message_unwind);
+ /* Save what's currently displayed in the echo area. Don't do that
+ if we are GC'ing because we've run out of memory, since
+ push_message will cons, and we might have no memory for that. */
+ if (NILP (Vmemory_full))
+ {
+ message_p = push_message ();
+ record_unwind_protect_void (pop_message_unwind);
+ }
+ else
+ message_p = false;
/* Save a copy of the contents of the stack, for debugging. */
#if MAX_SAVE_STACK > 0
xg_mark_data ();
#endif
-#if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \
- || GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS)
mark_stack (end);
-#else
- {
- register struct gcpro *tail;
- for (tail = gcprolist; tail; tail = tail->next)
- for (i = 0; i < tail->nvars; i++)
- mark_object (tail->var[i]);
- }
- mark_byte_stack ();
-#endif
+
{
struct handler *handler;
for (handler = handlerlist; handler; handler = handler->next)
mark_fringe_data ();
#endif
-#if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
- mark_stack (end);
-#endif
-
/* Everything is now marked, except for the data in font caches,
undo lists, and finalizers. The first two are compacted by
removing an items which aren't reachable otherwise. */
gc_sweep ();
- /* Clear the mark bits that we set in certain root slots. */
+ relocate_byte_stack ();
- unmark_byte_stack ();
+ /* Clear the mark bits that we set in certain root slots. */
VECTOR_UNMARK (&buffer_defaults);
VECTOR_UNMARK (&buffer_local_symbols);
-#if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES && 0
- dump_zombies ();
-#endif
-
check_cons_list ();
gc_in_progress = 0;
}
}
- if (garbage_collection_messages)
+ if (garbage_collection_messages && NILP (Vmemory_full))
{
if (message_p || minibuf_level > 0)
restore_message ();
};
retval = CALLMANY (Flist, total);
-#if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
- {
- /* Compute average percentage of zombies. */
- double nlive
- = (total_conses + total_symbols + total_markers + total_strings
- + total_vectors + total_floats + total_intervals + total_buffers);
-
- avg_live = (avg_live * ngcs + nlive) / (ngcs + 1);
- max_live = max (nlive, max_live);
- avg_zombies = (avg_zombies * ngcs + nzombies) / (ngcs + 1);
- max_zombies = max (nzombies, max_zombies);
- ++ngcs;
- }
-#endif
-
/* GC is complete: now we can run our finalizer callbacks. */
run_finalizers (&doomed_finalizers);
See Info node `(elisp)Garbage Collection'. */)
(void)
{
-#if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \
- || GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS \
- || GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES)
void *end;
#ifdef HAVE___BUILTIN_UNWIND_INIT
#endif /* not GC_SAVE_REGISTERS_ON_STACK */
#endif /* not HAVE___BUILTIN_UNWIND_INIT */
return garbage_collect_1 (end);
-#elif (GC_MARK_STACK == GC_USE_GCPROS_AS_BEFORE)
- /* Old GCPROs-based method without stack marking. */
- return garbage_collect_1 (NULL);
-#else
- emacs_abort ();
-#endif /* GC_MARK_STACK */
}
/* Mark Lisp objects in glyph matrix MATRIX. Currently the
/* If `save_type' is zero, `data[0].pointer' is the address
of a memory area containing `data[1].integer' potential
Lisp_Objects. */
- if (GC_MARK_STACK && ptr->save_type == SAVE_TYPE_MEMORY)
+ if (ptr->save_type == SAVE_TYPE_MEMORY)
{
Lisp_Object *p = ptr->data[0].pointer;
ptrdiff_t nelt;
loop:
po = XPNTR (obj);
- if (PURE_POINTER_P (po))
+ if (PURE_P (po))
return;
last_marked[last_marked_index++] = obj;
/* 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. */
+ by ~80%. */
#ifdef GC_CHECK_MARKED_OBJECTS
/* Check that the object pointed to by PO is known to be a Lisp
break;
default: emacs_abort ();
}
- if (!PURE_POINTER_P (XSTRING (ptr->name)))
+ if (!PURE_P (XSTRING (ptr->name)))
MARK_STRING (XSTRING (ptr->name));
MARK_INTERVAL_TREE (string_intervals (ptr->name));
/* Inner loop to mark next symbol in this bucket, if any. */
- ptr = ptr->next;
+ po = ptr = ptr->next;
if (ptr)
goto nextsym;
}
mark_object (XFINALIZER (obj)->function);
break;
+#ifdef HAVE_MODULES
+ case Lisp_Misc_User_Ptr:
+ XMISCANY (obj)->gcmarkbit = true;
+ break;
+#endif
+
default:
emacs_abort ();
}
emacs_abort ();
}
- return survives_p || PURE_POINTER_P ((void *) XPNTR (obj));
+ return survives_p || PURE_P (XPNTR (obj));
}
this_free++;
cblk->conses[pos].u.chain = cons_free_list;
cons_free_list = &cblk->conses[pos];
-#if GC_MARK_STACK
cons_free_list->car = Vdead;
-#endif
}
else
{
xfree (SYMBOL_BLV (&sym->s));
sym->s.next = symbol_free_list;
symbol_free_list = &sym->s;
-#if GC_MARK_STACK
symbol_free_list->function = Vdead;
-#endif
++this_free;
}
else
{
if (mblk->markers[i].m.u_any.type == Lisp_Misc_Marker)
unchain_marker (&mblk->markers[i].m.u_marker);
- if (mblk->markers[i].m.u_any.type == Lisp_Misc_Finalizer)
+ else if (mblk->markers[i].m.u_any.type == Lisp_Misc_Finalizer)
unchain_finalizer (&mblk->markers[i].m.u_finalizer);
+#ifdef HAVE_MODULES
+ else if (mblk->markers[i].m.u_any.type == Lisp_Misc_User_Ptr)
+ {
+ struct Lisp_User_Ptr *uptr = &mblk->markers[i].m.u_user_ptr;
+ uptr->finalizer (uptr->p);
+ }
+#endif
/* Set the type of the freed object to Lisp_Misc_Free.
We could leave the type alone, since nobody checks it,
but this might catch bugs faster. */
{
/* Even though Qt's contents are not set up, its address is known. */
Vpurify_flag = Qt;
- gc_precise = (GC_MARK_STACK == GC_USE_GCPROS_AS_BEFORE);
purebeg = PUREBEG;
pure_size = PURESIZE;
init_finalizer_list (&finalizers);
init_finalizer_list (&doomed_finalizers);
-#if GC_MARK_STACK || defined GC_MALLOC_CHECK
mem_init ();
Vdead = make_pure_string ("DEAD", 4, 4, 0);
-#endif
#ifdef DOUG_LEA_MALLOC
mallopt (M_TRIM_THRESHOLD, 128 * 1024); /* Trim threshold. */
void
init_alloc (void)
{
- gcprolist = 0;
- byte_stack_list = 0;
-#if GC_MARK_STACK
#if !defined GC_SAVE_REGISTERS_ON_STACK && !defined GC_SETJMP_WORKS
setjmp_tested_p = longjmps_done = 0;
-#endif
#endif
Vgc_elapsed = make_float (0.0);
gcs_done = 0;
DEFVAR_INT ("gcs-done", gcs_done,
doc: /* Accumulated number of garbage collections done. */);
- DEFVAR_BOOL ("gc-precise", gc_precise,
- doc: /* Non-nil means GC stack marking is precise.
-Useful mainly for automated GC tests. Build time constant.*/);
- XSYMBOL (intern_c_string ("gc-precise"))->constant = 1;
-
defsubr (&Scons);
defsubr (&Slist);
defsubr (&Svector);
defsubr (&Smemory_info);
defsubr (&Smemory_use_counts);
defsubr (&Ssuspicious_object);
-
-#if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
- defsubr (&Sgc_status);
-#endif
}
/* When compiled with GCC, GDB might say "No enum type named