summaryrefslogtreecommitdiff
path: root/src/alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/alloc.c')
-rw-r--r--src/alloc.c1581
1 files changed, 1581 insertions, 0 deletions
diff --git a/src/alloc.c b/src/alloc.c
new file mode 100644
index 00000000000..06b7b818f7f
--- /dev/null
+++ b/src/alloc.c
@@ -0,0 +1,1581 @@
+/* Storage allocation and gc for GNU Emacs Lisp interpreter.
+ Copyright (C) 1985, 1986 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 1, 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
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "config.h"
+#include "lisp.h"
+#ifndef standalone
+#include "buffer.h"
+#include "window.h"
+#endif
+
+#define max(A,B) ((A) > (B) ? (A) : (B))
+
+/* Macro to verify that storage intended for Lisp objects is not
+ out of range to fit in the space for a pointer.
+ ADDRESS is the start of the block, and SIZE
+ is the amount of space within which objects can start. */
+#define VALIDATE_LISP_STORAGE(address, size) \
+do \
+ { \
+ Lisp_Object val; \
+ XSET (val, Lisp_Cons, (char *) address + size); \
+ if ((char *) XCONS (val) != (char *) address + size) \
+ { \
+ free (address); \
+ memory_full (); \
+ } \
+ } while (0)
+
+/* Number of bytes of consing done since the last gc */
+int consing_since_gc;
+
+/* Number of bytes of consing since gc before another gc should be done. */
+int gc_cons_threshold;
+
+/* value of consing_since_gc when undos were last truncated. */
+int consing_at_last_truncate;
+
+/* Nonzero during gc */
+int gc_in_progress;
+
+#ifndef VIRT_ADDR_VARIES
+extern
+#endif /* VIRT_ADDR_VARIES */
+ int malloc_sbrk_used;
+
+#ifndef VIRT_ADDR_VARIES
+extern
+#endif /* VIRT_ADDR_VARIES */
+ int malloc_sbrk_unused;
+
+/* Two thresholds controlling how much undo information to keep. */
+int undo_threshold;
+int undo_high_threshold;
+
+/* Non-nil means defun should do purecopy on the function definition */
+Lisp_Object Vpurify_flag;
+
+/* Argument we give to Fsignal when memory is full.
+ Preallocated since perhaps we can't allocate it when memory is full. */
+Lisp_Object memory_exhausted_message;
+
+#ifndef HAVE_SHM
+#ifdef VMS
+int pure[PURESIZE / sizeof (int)]; /*no need to initialize - wasted space*/
+#else
+int pure[PURESIZE / sizeof (int)] = {0,}; /* Force it into data space! */
+#endif /* NOT VMS */
+#define PUREBEG (char *) pure
+#else
+#define pure PURE_SEG_BITS /* Use shared memory segment */
+#define PUREBEG (char *)PURE_SEG_BITS
+#endif /* not HAVE_SHM */
+
+/* Index in pure at which next pure object will be allocated. */
+int pureptr;
+
+/* If nonzero, this is a warning delivered by malloc and not yet displayed. */
+char *pending_malloc_warning;
+
+Lisp_Object
+malloc_warning_1 (str)
+ Lisp_Object str;
+{
+ Fprinc (str, Vstandard_output);
+ write_string ("\nKilling some buffers may delay running out of memory.\n", -1);
+ write_string ("However, certainly by the time you receive the 95% warning,\n", -1);
+ write_string ("you should clean up, kill this Emacs, and start a new one.", -1);
+ return Qnil;
+}
+
+/* malloc calls this if it finds we are near exhausting storage */
+malloc_warning (str)
+ char *str;
+{
+ pending_malloc_warning = str;
+}
+
+display_malloc_warning ()
+{
+ register Lisp_Object val;
+
+ val = build_string (pending_malloc_warning);
+ pending_malloc_warning = 0;
+ internal_with_output_to_temp_buffer (" *Danger*", malloc_warning_1, val);
+}
+
+/* Called if malloc returns zero */
+memory_full ()
+{
+ while (1)
+ Fsignal (Qerror, memory_exhausted_message);
+}
+
+/* like malloc and realloc but check for no memory left */
+
+long *
+xmalloc (size)
+ int size;
+{
+ register long *val;
+ /* Avoid failure if malloc (0) returns 0. */
+ if (size == 0)
+ size = 1;
+ val = (long *) malloc (size);
+ if (!val) memory_full ();
+ return val;
+}
+
+long *
+xrealloc (block, size)
+ long *block;
+ int size;
+{
+ register long *val;
+ /* Avoid failure if malloc (0) returns 0. */
+ if (size == 0)
+ size = 1;
+ val = (long *) realloc (block, size);
+ if (!val) memory_full ();
+ return val;
+}
+
+/* Allocation of cons cells */
+/* We store cons cells inside of cons_blocks, allocating a new
+ cons_block with malloc whenever necessary. Cons cells reclaimed by
+ GC are put on a free list to be reallocated before allocating
+ any new cons cells from the latest cons_block.
+
+ Each cons_block is just under 1016 bytes long,
+ since malloc really allocates in units of powers of two
+ and uses 8 bytes for its own overhead. */
+
+#define CONS_BLOCK_SIZE \
+ ((1016 - sizeof (struct cons_block *)) / sizeof (struct Lisp_Cons))
+
+struct cons_block
+ {
+ struct cons_block *next;
+ struct Lisp_Cons conses[CONS_BLOCK_SIZE];
+ };
+
+struct cons_block *cons_block;
+int cons_block_index;
+
+struct Lisp_Cons *cons_free_list;
+
+void
+init_cons ()
+{
+ cons_block = (struct cons_block *) malloc (sizeof (struct cons_block));
+ cons_block->next = 0;
+ bzero (cons_block->conses, sizeof cons_block->conses);
+ cons_block_index = 0;
+ cons_free_list = 0;
+}
+
+/* Explicitly free a cons cell. */
+free_cons (ptr)
+ struct Lisp_Cons *ptr;
+{
+ XFASTINT (ptr->car) = (int) cons_free_list;
+ cons_free_list = ptr;
+}
+
+DEFUN ("cons", Fcons, Scons, 2, 2, 0,
+ "Create a new cons, give it CAR and CDR as components, and return it.")
+ (car, cdr)
+ Lisp_Object car, cdr;
+{
+ register Lisp_Object val;
+
+ if (cons_free_list)
+ {
+ XSET (val, Lisp_Cons, cons_free_list);
+ cons_free_list = (struct Lisp_Cons *) XFASTINT (cons_free_list->car);
+ }
+ else
+ {
+ if (cons_block_index == CONS_BLOCK_SIZE)
+ {
+ register struct cons_block *new = (struct cons_block *) malloc (sizeof (struct cons_block));
+ if (!new) memory_full ();
+ VALIDATE_LISP_STORAGE (new, sizeof *new);
+ new->next = cons_block;
+ cons_block = new;
+ cons_block_index = 0;
+ XSET (val, Lisp_Cons, &cons_block->conses[CONS_BLOCK_SIZE - 1]);
+ }
+ XSET (val, Lisp_Cons, &cons_block->conses[cons_block_index++]);
+ }
+ XCONS (val)->car = car;
+ XCONS (val)->cdr = cdr;
+ consing_since_gc += sizeof (struct Lisp_Cons);
+ return val;
+}
+
+DEFUN ("list", Flist, Slist, 0, MANY, 0,
+ "Return a newly created list whose elements are the arguments (any number).")
+ (nargs, args)
+ int nargs;
+ register Lisp_Object *args;
+{
+ register Lisp_Object len, val, val_tail;
+
+ XFASTINT (len) = nargs;
+ val = Fmake_list (len, Qnil);
+ val_tail = val;
+ while (!NULL (val_tail))
+ {
+ XCONS (val_tail)->car = *args++;
+ val_tail = XCONS (val_tail)->cdr;
+ }
+ return val;
+}
+
+DEFUN ("make-list", Fmake_list, Smake_list, 2, 2, 0,
+ "Return a newly created list of length LENGTH, with each element being INIT.")
+ (length, init)
+ register Lisp_Object length, init;
+{
+ register Lisp_Object val;
+ register int size;
+
+ if (XTYPE (length) != Lisp_Int || XINT (length) < 0)
+ length = wrong_type_argument (Qnatnump, length);
+ size = XINT (length);
+
+ val = Qnil;
+ while (size-- > 0)
+ val = Fcons (init, val);
+ return val;
+}
+
+/* Allocation of vectors */
+
+struct Lisp_Vector *all_vectors;
+
+DEFUN ("make-vector", Fmake_vector, Smake_vector, 2, 2, 0,
+ "Return a newly created vector of length LENGTH, with each element being INIT.")
+ (length, init)
+ register Lisp_Object length, init;
+{
+ register int sizei, index;
+ register Lisp_Object vector;
+ register struct Lisp_Vector *p;
+
+ if (XTYPE (length) != Lisp_Int || XINT (length) < 0)
+ length = wrong_type_argument (Qnatnump, length);
+ sizei = XINT (length);
+
+ p = (struct Lisp_Vector *) malloc (sizeof (struct Lisp_Vector) + (sizei - 1) * sizeof (Lisp_Object));
+ if (p == 0)
+ memory_full ();
+ VALIDATE_LISP_STORAGE (p, 0);
+
+ XSET (vector, Lisp_Vector, p);
+ consing_since_gc += sizeof (struct Lisp_Vector) + (sizei - 1) * sizeof (Lisp_Object);
+
+ p->size = sizei;
+ p->next = all_vectors;
+ all_vectors = p;
+
+ for (index = 0; index < sizei; index++)
+ p->contents[index] = init;
+
+ return vector;
+}
+
+DEFUN ("vector", Fvector, Svector, 0, MANY, 0,
+ "Return a newly created vector with our arguments (any number) as its elements.")
+ (nargs, args)
+ register int nargs;
+ Lisp_Object *args;
+{
+ register Lisp_Object len, val;
+ register int index;
+ register struct Lisp_Vector *p;
+
+ XFASTINT (len) = nargs;
+ val = Fmake_vector (len, Qnil);
+ p = XVECTOR (val);
+ for (index = 0; index < nargs; index++)
+ p->contents[index] = args[index];
+ return val;
+}
+
+/* Allocation of symbols.
+ Just like allocation of conses!
+
+ Each symbol_block is just under 1016 bytes long,
+ since malloc really allocates in units of powers of two
+ and uses 8 bytes for its own overhead. */
+
+#define SYMBOL_BLOCK_SIZE \
+ ((1016 - sizeof (struct symbol_block *)) / sizeof (struct Lisp_Symbol))
+
+struct symbol_block
+ {
+ struct symbol_block *next;
+ struct Lisp_Symbol symbols[SYMBOL_BLOCK_SIZE];
+ };
+
+struct symbol_block *symbol_block;
+int symbol_block_index;
+
+struct Lisp_Symbol *symbol_free_list;
+
+void
+init_symbol ()
+{
+ symbol_block = (struct symbol_block *) malloc (sizeof (struct symbol_block));
+ symbol_block->next = 0;
+ bzero (symbol_block->symbols, sizeof symbol_block->symbols);
+ symbol_block_index = 0;
+ symbol_free_list = 0;
+}
+
+DEFUN ("make-symbol", Fmake_symbol, Smake_symbol, 1, 1, 0,
+ "Return a newly allocated uninterned symbol whose name is NAME.\n\
+Its value and function definition are void, and its property list is NIL.")
+ (str)
+ Lisp_Object str;
+{
+ register Lisp_Object val;
+ register struct Lisp_Symbol *p;
+
+ CHECK_STRING (str, 0);
+
+ if (symbol_free_list)
+ {
+ XSET (val, Lisp_Symbol, symbol_free_list);
+ symbol_free_list
+ = (struct Lisp_Symbol *) XFASTINT (symbol_free_list->value);
+ }
+ else
+ {
+ if (symbol_block_index == SYMBOL_BLOCK_SIZE)
+ {
+ struct symbol_block *new = (struct symbol_block *) malloc (sizeof (struct symbol_block));
+ if (!new) memory_full ();
+ VALIDATE_LISP_STORAGE (new, sizeof *new);
+ new->next = symbol_block;
+ symbol_block = new;
+ symbol_block_index = 0;
+ }
+ XSET (val, Lisp_Symbol, &symbol_block->symbols[symbol_block_index++]);
+ }
+ p = XSYMBOL (val);
+ p->name = XSTRING (str);
+ p->plist = Qnil;
+ p->value = Qunbound;
+ p->function = Qunbound;
+ p->next = 0;
+ consing_since_gc += sizeof (struct Lisp_Symbol);
+ return val;
+}
+
+/* Allocation of markers.
+ Works like allocation of conses. */
+
+#define MARKER_BLOCK_SIZE \
+ ((1016 - sizeof (struct marker_block *)) / sizeof (struct Lisp_Marker))
+
+struct marker_block
+ {
+ struct marker_block *next;
+ struct Lisp_Marker markers[MARKER_BLOCK_SIZE];
+ };
+
+struct marker_block *marker_block;
+int marker_block_index;
+
+struct Lisp_Marker *marker_free_list;
+
+void
+init_marker ()
+{
+ marker_block = (struct marker_block *) malloc (sizeof (struct marker_block));
+ marker_block->next = 0;
+ bzero (marker_block->markers, sizeof marker_block->markers);
+ marker_block_index = 0;
+ marker_free_list = 0;
+}
+
+DEFUN ("make-marker", Fmake_marker, Smake_marker, 0, 0, 0,
+ "Return a newly allocated marker which does not point at any place.")
+ ()
+{
+ register Lisp_Object val;
+ register struct Lisp_Marker *p;
+
+ if (marker_free_list)
+ {
+ XSET (val, Lisp_Marker, marker_free_list);
+ marker_free_list
+ = (struct Lisp_Marker *) XFASTINT (marker_free_list->chain);
+ }
+ else
+ {
+ if (marker_block_index == MARKER_BLOCK_SIZE)
+ {
+ struct marker_block *new = (struct marker_block *) malloc (sizeof (struct marker_block));
+ if (!new) memory_full ();
+ VALIDATE_LISP_STORAGE (new, sizeof *new);
+ new->next = marker_block;
+ marker_block = new;
+ marker_block_index = 0;
+ }
+ XSET (val, Lisp_Marker, &marker_block->markers[marker_block_index++]);
+ }
+ p = XMARKER (val);
+ p->buffer = 0;
+ p->bufpos = 0;
+ p->chain = Qnil;
+ consing_since_gc += sizeof (struct Lisp_Marker);
+ return val;
+}
+
+/* Allocation of strings */
+
+/* Strings reside inside of string_blocks. The entire data of the string,
+ both the size and the contents, live in part of the `chars' component of a string_block.
+ The `pos' component is the index within `chars' of the first free byte.
+
+ first_string_block points to the first string_block ever allocated.
+ Each block points to the next one with its `next' field.
+ The `prev' fields chain in reverse order.
+ The last one allocated is the one currently being filled.
+ current_string_block points to it.
+
+ The string_blocks that hold individual large strings
+ go in a separate chain, started by large_string_blocks. */
+
+
+/* String blocks contain this many useful bytes.
+ 8184 is power of 2, minus 8 for malloc overhead. */
+#define STRING_BLOCK_SIZE (8184 - sizeof (struct string_block_head))
+
+/* A string bigger than this gets its own specially-made string block
+ if it doesn't fit in the current one. */
+#define STRING_BLOCK_OUTSIZE 1024
+
+struct string_block_head
+ {
+ struct string_block *next, *prev;
+ int pos;
+ };
+
+struct string_block
+ {
+ struct string_block *next, *prev;
+ int pos;
+ char chars[STRING_BLOCK_SIZE];
+ };
+
+/* This points to the string block we are now allocating strings. */
+
+struct string_block *current_string_block;
+
+/* This points to the oldest string block, the one that starts the chain. */
+
+struct string_block *first_string_block;
+
+/* Last string block in chain of those made for individual large strings. */
+
+struct string_block *large_string_blocks;
+
+/* If SIZE is the length of a string, this returns how many bytes
+ the string occupies in a string_block (including padding). */
+
+#define STRING_FULLSIZE(SIZE) \
+(((SIZE) + 2 * sizeof (int)) & ~(sizeof (int) - 1))
+
+void
+init_strings ()
+{
+ current_string_block = (struct string_block *) malloc (sizeof (struct string_block));
+ first_string_block = current_string_block;
+ consing_since_gc += sizeof (struct string_block);
+ current_string_block->next = 0;
+ current_string_block->prev = 0;
+ current_string_block->pos = 0;
+ large_string_blocks = 0;
+}
+
+static Lisp_Object make_uninit_string ();
+
+DEFUN ("make-string", Fmake_string, Smake_string, 2, 2, 0,
+ "Return a newly created string of length LENGTH, with each element being INIT.\n\
+Both LENGTH and INIT must be numbers.")
+ (length, init)
+ Lisp_Object length, init;
+{
+ register Lisp_Object val;
+ register unsigned char *p, *end, c;
+
+ if (XTYPE (length) != Lisp_Int || XINT (length) < 0)
+ length = wrong_type_argument (Qnatnump, length);
+ CHECK_NUMBER (init, 1);
+ val = make_uninit_string (XINT (length));
+ c = XINT (init);
+ p = XSTRING (val)->data;
+ end = p + XSTRING (val)->size;
+ while (p != end)
+ *p++ = c;
+ *p = 0;
+ return val;
+}
+
+Lisp_Object
+make_string (contents, length)
+ char *contents;
+ int length;
+{
+ register Lisp_Object val;
+ val = make_uninit_string (length, 0);
+ bcopy (contents, XSTRING (val)->data, length);
+ return val;
+}
+
+Lisp_Object
+build_string (str)
+ char *str;
+{
+ return make_string (str, strlen (str));
+}
+
+static Lisp_Object
+make_uninit_string (length)
+ int length;
+{
+ register Lisp_Object val;
+ register int fullsize = STRING_FULLSIZE (length);
+
+ if (length < 0) abort ();
+
+ if (fullsize <= STRING_BLOCK_SIZE - current_string_block->pos)
+ /* This string can fit in the current string block */
+ {
+ XSET (val, Lisp_String,
+ (struct Lisp_String *) (current_string_block->chars + current_string_block->pos));
+ current_string_block->pos += fullsize;
+ }
+ else if (fullsize > STRING_BLOCK_OUTSIZE)
+ /* This string gets its own string block */
+ {
+ register struct string_block *new
+ = (struct string_block *) malloc (sizeof (struct string_block_head) + fullsize);
+ if (!new) memory_full ();
+ VALIDATE_LISP_STORAGE (new, 0);
+ consing_since_gc += sizeof (struct string_block_head) + fullsize;
+ new->pos = fullsize;
+ new->next = large_string_blocks;
+ large_string_blocks = new;
+ XSET (val, Lisp_String,
+ (struct Lisp_String *) ((struct string_block_head *)new + 1));
+ }
+ else
+ /* Make a new current string block and start it off with this string */
+ {
+ register struct string_block *new
+ = (struct string_block *) malloc (sizeof (struct string_block));
+ if (!new) memory_full ();
+ VALIDATE_LISP_STORAGE (new, sizeof *new);
+ consing_since_gc += sizeof (struct string_block);
+ current_string_block->next = new;
+ new->prev = current_string_block;
+ new->next = 0;
+ current_string_block = new;
+ new->pos = fullsize;
+ XSET (val, Lisp_String,
+ (struct Lisp_String *) current_string_block->chars);
+ }
+
+ XSTRING (val)->size = length;
+ XSTRING (val)->data[length] = 0;
+
+ return val;
+}
+
+/* Must get an error if pure storage is full,
+ since if it cannot hold a large string
+ it may be able to hold conses that point to that string;
+ then the string is not protected from gc. */
+
+Lisp_Object
+make_pure_string (data, length)
+ char *data;
+ int length;
+{
+ register Lisp_Object new;
+ register int size = sizeof (int) + length + 1;
+
+ if (pureptr + size > PURESIZE)
+ error ("Pure Lisp storage exhausted");
+ XSET (new, Lisp_String, PUREBEG + pureptr);
+ XSTRING (new)->size = length;
+ bcopy (data, XSTRING (new)->data, length);
+ XSTRING (new)->data[length] = 0;
+ pureptr += (size + sizeof (int) - 1)
+ / sizeof (int) * sizeof (int);
+ return new;
+}
+
+Lisp_Object
+pure_cons (car, cdr)
+ Lisp_Object car, cdr;
+{
+ register Lisp_Object new;
+
+ if (pureptr + sizeof (struct Lisp_Cons) > PURESIZE)
+ error ("Pure Lisp storage exhausted");
+ XSET (new, Lisp_Cons, PUREBEG + pureptr);
+ pureptr += sizeof (struct Lisp_Cons);
+ XCONS (new)->car = Fpurecopy (car);
+ XCONS (new)->cdr = Fpurecopy (cdr);
+ return new;
+}
+
+Lisp_Object
+make_pure_vector (len)
+ int len;
+{
+ register Lisp_Object new;
+ register int size = sizeof (struct Lisp_Vector) + (len - 1) * sizeof (Lisp_Object);
+
+ if (pureptr + size > PURESIZE)
+ error ("Pure Lisp storage exhausted");
+
+ XSET (new, Lisp_Vector, PUREBEG + pureptr);
+ pureptr += size;
+ XVECTOR (new)->size = len;
+ return new;
+}
+
+DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
+ "Make a copy of OBJECT in pure storage.\n\
+Recursively copies contents of vectors and cons cells.\n\
+Does not copy symbols.")
+ (obj)
+ register Lisp_Object obj;
+{
+ register Lisp_Object new, tem;
+ register int i;
+
+ if (NULL (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)
+ return obj;
+
+#ifdef SWITCH_ENUM_BUG
+ switch ((int) XTYPE (obj))
+#else
+ switch (XTYPE (obj))
+#endif
+ {
+ case Lisp_Marker:
+ error ("Attempt to copy a marker to pure storage");
+
+ case Lisp_Cons:
+ return pure_cons (XCONS (obj)->car, XCONS (obj)->cdr);
+
+ case Lisp_String:
+ return make_pure_string (XSTRING (obj)->data, XSTRING (obj)->size);
+
+ case Lisp_Vector:
+ new = make_pure_vector (XVECTOR (obj)->size);
+ for (i = 0; i < XVECTOR (obj)->size; i++)
+ {
+ tem = XVECTOR (obj)->contents[i];
+ XVECTOR (new)->contents[i] = Fpurecopy (tem);
+ }
+ return new;
+
+ default:
+ return obj;
+ }
+}
+
+/* Recording what needs to be marked for gc. */
+
+struct gcpro *gcprolist;
+
+#define NSTATICS 200
+
+int staticidx = 0;
+
+#ifdef __GNUC__
+Lisp_Object *staticvec[NSTATICS] = {0};
+#else
+char staticvec1[NSTATICS * sizeof (Lisp_Object *)] = {0};
+#define staticvec ((Lisp_Object **) staticvec1)
+#endif
+
+/* Put an entry in staticvec, pointing at the variable whose address is given */
+
+void
+staticpro (varaddress)
+ Lisp_Object *varaddress;
+{
+ staticvec[staticidx++] = varaddress;
+ if (staticidx >= NSTATICS)
+ abort ();
+}
+
+struct catchtag
+ {
+ Lisp_Object tag;
+ Lisp_Object val;
+ struct catchtag *next;
+/* jmp_buf jmp; /* We don't need this for GC purposes */
+ };
+
+extern struct catchtag *catchlist;
+
+struct backtrace
+ {
+ struct backtrace *next;
+ Lisp_Object *function;
+ Lisp_Object *args; /* Points to vector of args. */
+ int nargs; /* length of vector */
+ /* if nargs is UNEVALLED, args points to slot holding list of unevalled args */
+ char evalargs;
+ };
+
+extern struct backtrace *backtrace_list;
+
+/* Two flags that are set during GC in the `size' component
+ of a string or vector. On some machines, these flags
+ are defined by the m- file to be different bits. */
+
+/* On vector, means it has been marked.
+ On string size field or a reference to a string,
+ means not the last reference in the chain. */
+
+#ifndef ARRAY_MARK_FLAG
+#define ARRAY_MARK_FLAG ((MARKBIT >> 1) & ~MARKBIT)
+#endif /* no ARRAY_MARK_FLAG */
+
+/* Any slot that is a Lisp_Object can point to a string
+ and thus can be put on a string's reference-chain
+ and thus may need to have its ARRAY_MARK_FLAG set.
+ This includes the slots whose markbits are used to mark
+ the containing objects. */
+
+#if ARRAY_MARK_FLAG == MARKBIT
+you lose
+#endif
+
+int total_conses, total_markers, total_symbols, total_string_size, total_vector_size;
+int total_free_conses, total_free_markers, total_free_symbols;
+
+static void mark_object (), mark_buffer ();
+static void clear_marks (), gc_sweep ();
+static void compact_strings ();
+
+DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "",
+ "Reclaim storage for Lisp objects no longer needed.\n\
+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\
+Garbage collection happens automatically if you cons more than\n\
+gc-cons-threshold bytes of Lisp data since previous garbage collection.")
+ ()
+{
+ register struct gcpro *tail;
+ register struct specbinding *bind;
+ struct catchtag *catch;
+ struct handler *handler;
+ register struct backtrace *backlist;
+ register Lisp_Object tem;
+ char *omessage = echo_area_contents;
+
+ register int i;
+
+ if (!noninteractive)
+ message1 ("Garbage collecting...");
+
+ /* Don't keep command history around forever */
+ tem = Fnthcdr (make_number (30), Vcommand_history);
+ if (CONSP (tem))
+ XCONS (tem)->cdr = Qnil;
+ /* Likewise for undo information. */
+ truncate_all_undos ();
+
+ gc_in_progress = 1;
+
+/* clear_marks (); */
+
+ /* In each "large string", set the MARKBIT of the size field.
+ That enables mark_object to recognize them. */
+ {
+ register struct string_block *b;
+ for (b = large_string_blocks; b; b = b->next)
+ ((struct Lisp_String *)(&b->chars[0]))->size |= MARKBIT;
+ }
+
+ /* Mark all the special slots that serve as the roots of accessibility.
+
+ Usually the special slots to mark are contained in particular structures.
+ Then we know no slot is marked twice because the structures don't overlap.
+ In some cases, the structures point to the slots to be marked.
+ For these, we use MARKBIT to avoid double marking of the slot. */
+
+ for (i = 0; i < staticidx; i++)
+ mark_object (staticvec[i]);
+ for (tail = gcprolist; tail; tail = tail->next)
+ for (i = 0; i < tail->nvars; i++)
+ if (!XMARKBIT (tail->var[i]))
+ {
+ mark_object (&tail->var[i]);
+ XMARK (tail->var[i]);
+ }
+ for (bind = specpdl; bind != specpdl_ptr; bind++)
+ {
+ mark_object (&bind->symbol);
+ mark_object (&bind->old_value);
+ }
+ for (catch = catchlist; catch; catch = catch->next)
+ {
+ mark_object (&catch->tag);
+ mark_object (&catch->val);
+ }
+ for (handler = handlerlist; handler; handler = handler->next)
+ {
+ mark_object (&handler->handler);
+ mark_object (&handler->var);
+ }
+ for (backlist = backtrace_list; backlist; backlist = backlist->next)
+ {
+ if (!XMARKBIT (*backlist->function))
+ {
+ mark_object (backlist->function);
+ XMARK (*backlist->function);
+ }
+ if (backlist->nargs == UNEVALLED || backlist->nargs == MANY)
+ i = 0;
+ else
+ i = backlist->nargs - 1;
+ for (; i >= 0; i--)
+ if (!XMARKBIT (backlist->args[i]))
+ {
+ mark_object (&backlist->args[i]);
+ XMARK (backlist->args[i]);
+ }
+ }
+
+ gc_sweep ();
+
+ /* Clear the mark bits that we set in certain root slots. */
+
+ for (tail = gcprolist; tail; tail = tail->next)
+ for (i = 0; i < tail->nvars; i++)
+ XUNMARK (tail->var[i]);
+ for (backlist = backtrace_list; backlist; backlist = backlist->next)
+ {
+ XUNMARK (*backlist->function);
+ if (backlist->nargs == UNEVALLED || backlist->nargs == MANY)
+ i = 0;
+ else
+ i = backlist->nargs - 1;
+ for (; i >= 0; i--)
+ XUNMARK (backlist->args[i]);
+ }
+ XUNMARK (buffer_defaults.name);
+ XUNMARK (buffer_local_symbols.name);
+
+/* clear_marks (); */
+ gc_in_progress = 0;
+
+ consing_since_gc = 0;
+ consing_at_last_truncate = 0;
+ if (gc_cons_threshold < 10000)
+ gc_cons_threshold = 10000;
+
+ if (omessage)
+ message1 (omessage);
+ else if (!noninteractive)
+ message1 ("Garbage collecting...done");
+
+ return Fcons (Fcons (make_number (total_conses),
+ make_number (total_free_conses)),
+ Fcons (Fcons (make_number (total_symbols),
+ make_number (total_free_symbols)),
+ Fcons (Fcons (make_number (total_markers),
+ make_number (total_free_markers)),
+ Fcons (make_number (total_string_size),
+ Fcons (make_number (total_vector_size),
+ Qnil)))));
+}
+
+#if 0
+static void
+clear_marks ()
+{
+ /* Clear marks on all conses */
+ {
+ register struct cons_block *cblk;
+ register int lim = cons_block_index;
+
+ for (cblk = cons_block; cblk; cblk = cblk->next)
+ {
+ register int i;
+ for (i = 0; i < lim; i++)
+ XUNMARK (cblk->conses[i].car);
+ lim = CONS_BLOCK_SIZE;
+ }
+ }
+ /* Clear marks on all symbols */
+ {
+ register struct symbol_block *sblk;
+ register int lim = symbol_block_index;
+
+ for (sblk = symbol_block; sblk; sblk = sblk->next)
+ {
+ register int i;
+ for (i = 0; i < lim; i++)
+ {
+ XUNMARK (sblk->symbols[i].plist);
+ }
+ lim = SYMBOL_BLOCK_SIZE;
+ }
+ }
+ /* Clear marks on all markers */
+ {
+ register struct marker_block *sblk;
+ register int lim = marker_block_index;
+
+ for (sblk = marker_block; sblk; sblk = sblk->next)
+ {
+ register int i;
+ for (i = 0; i < lim; i++)
+ XUNMARK (sblk->markers[i].chain);
+ lim = MARKER_BLOCK_SIZE;
+ }
+ }
+ /* Clear mark bits on all buffers */
+ {
+ register struct buffer *nextb = all_buffers;
+
+ while (nextb)
+ {
+ XUNMARK (nextb->name);
+ nextb = nextb->next;
+ }
+ }
+}
+#endif
+
+/* Mark reference to a Lisp_Object. If the object referred to
+ has not been seen yet, recursively mark all the references contained in it.
+
+ If the object referenced is a short string, the referrencing slot
+ is threaded into a chain of such slots, pointed to from
+ the `size' field of the string. The actual string size
+ lives in the last slot in the chain. We recognize the end
+ because it is < (unsigned) STRING_BLOCK_SIZE. */
+
+static void
+mark_object (objptr)
+ Lisp_Object *objptr;
+{
+ register Lisp_Object obj;
+
+ obj = *objptr;
+ XUNMARK (obj);
+
+ loop:
+
+ if ((PNTR_COMPARISON_TYPE) XPNTR (obj) < (PNTR_COMPARISON_TYPE) ((char *) pure + PURESIZE)
+ && (PNTR_COMPARISON_TYPE) XPNTR (obj) >= (PNTR_COMPARISON_TYPE) pure)
+ return;
+
+#ifdef SWITCH_ENUM_BUG
+ switch ((int) XGCTYPE (obj))
+#else
+ switch (XGCTYPE (obj))
+#endif
+ {
+ case Lisp_String:
+ {
+ register struct Lisp_String *ptr = XSTRING (obj);
+
+ if (ptr->size & MARKBIT)
+ /* A large string. Just set ARRAY_MARK_FLAG. */
+ ptr->size |= ARRAY_MARK_FLAG;
+ else
+ {
+ /* A small string. Put this reference
+ into the chain of references to it.
+ The address OBJPTR is even, so if the address
+ includes MARKBIT, put it in the low bit
+ when we store OBJPTR into the size field. */
+
+ if (XMARKBIT (*objptr))
+ {
+ XFASTINT (*objptr) = ptr->size;
+ XMARK (*objptr);
+ }
+ else
+ XFASTINT (*objptr) = ptr->size;
+ if ((int)objptr & 1) abort ();
+ ptr->size = (int) objptr & ~MARKBIT;
+ if ((int) objptr & MARKBIT)
+ ptr->size ++;
+ }
+ }
+ break;
+
+ case Lisp_Vector:
+ case Lisp_Window:
+ case Lisp_Process:
+ case Lisp_Window_Configuration:
+ {
+ register struct Lisp_Vector *ptr = XVECTOR (obj);
+ register int size = ptr->size;
+ register int i;
+
+ if (size & ARRAY_MARK_FLAG) break; /* Already marked */
+ ptr->size |= ARRAY_MARK_FLAG; /* Else mark it */
+ for (i = 0; i < size; i++) /* and then mark its elements */
+ mark_object (&ptr->contents[i]);
+ }
+ break;
+
+#if 0
+ case Lisp_Temp_Vector:
+ {
+ register struct Lisp_Vector *ptr = XVECTOR (obj);
+ register int size = ptr->size;
+ register int i;
+
+ for (i = 0; i < size; i++) /* and then mark its elements */
+ mark_object (&ptr->contents[i]);
+ }
+ break;
+#endif 0
+
+ case Lisp_Symbol:
+ {
+ register struct Lisp_Symbol *ptr = XSYMBOL (obj);
+ struct Lisp_Symbol *ptrx;
+
+ if (XMARKBIT (ptr->plist)) break;
+ XMARK (ptr->plist);
+ XSETTYPE (*(Lisp_Object *) &ptr->name, Lisp_String);
+ mark_object (&ptr->name);
+ mark_object ((Lisp_Object *) &ptr->value);
+ mark_object (&ptr->function);
+ mark_object (&ptr->plist);
+ ptr = ptr->next;
+ if (ptr)
+ {
+ ptrx = ptr; /* Use pf ptrx avoids compiler bug on Sun */
+ XSETSYMBOL (obj, ptrx);
+ goto loop;
+ }
+ }
+ break;
+
+ case Lisp_Marker:
+ XMARK (XMARKER (obj)->chain);
+ /* DO NOT mark thru the marker's chain.
+ The buffer's markers chain does not preserve markers from gc;
+ instead, markers are removed from the chain when they are freed by gc. */
+ break;
+
+ case Lisp_Cons:
+ case Lisp_Buffer_Local_Value:
+ case Lisp_Some_Buffer_Local_Value:
+ {
+ register struct Lisp_Cons *ptr = XCONS (obj);
+ if (XMARKBIT (ptr->car)) break;
+ XMARK (ptr->car);
+ /* If the cdr is nil, avoid recursion for the car. */
+ if (EQ (ptr->cdr, Qnil))
+ {
+ objptr = &ptr->car;
+ obj = ptr->car;
+ XUNMARK (obj);
+ goto loop;
+ }
+ /* If the cdr is (INTEGER . nil), mark the cdr first,
+ to avoid recursion for the car. This case occurs
+ in every compiled function. */
+ if (XTYPE (ptr->cdr) == Lisp_Cons
+ && XGCTYPE (XCONS (ptr->cdr)->car) == Lisp_Int
+ && EQ (XCONS (ptr->cdr)->cdr, Qnil))
+ {
+ mark_object (&ptr->cdr);
+ objptr = &ptr->car;
+ obj = ptr->car;
+ XUNMARK (obj);
+ goto loop;
+ }
+ mark_object (&ptr->car);
+ objptr = &ptr->cdr;
+ obj = ptr->cdr;
+ goto loop;
+ }
+
+ case Lisp_Buffer:
+ if (!XMARKBIT (XBUFFER (obj)->name))
+ mark_buffer (obj);
+ break;
+
+ case Lisp_Int:
+ case Lisp_Void:
+ case Lisp_Subr:
+ case Lisp_Intfwd:
+ case Lisp_Boolfwd:
+ case Lisp_Objfwd:
+ case Lisp_Buffer_Objfwd:
+ case Lisp_Internal_Stream:
+ /* Don't bother with Lisp_Buffer_Objfwd,
+ since all markable slots in current buffer marked anyway. */
+ /* Don't need to do Lisp_Objfwd, since the places they point
+ are protected with staticpro. */
+ break;
+
+ default:
+ abort ();
+ }
+}
+
+/* Mark the pointers in a buffer structure. */
+
+static void
+mark_buffer (buf)
+ Lisp_Object buf;
+{
+ Lisp_Object tem;
+ register struct buffer *buffer = XBUFFER (buf);
+ register Lisp_Object *ptr;
+
+ /* This is the buffer's markbit */
+ mark_object (&buffer->name);
+ XMARK (buffer->name);
+
+ for (ptr = &buffer->name + 1;
+ (char *)ptr < (char *)buffer + sizeof (struct buffer);
+ ptr++)
+ mark_object (ptr);
+}
+
+/* Find all structures not marked, and free them. */
+
+static void
+gc_sweep ()
+{
+ total_string_size = 0;
+ compact_strings ();
+
+ /* Put all unmarked conses on free list */
+ {
+ register struct cons_block *cblk;
+ register int lim = cons_block_index;
+ register int num_free = 0, num_used = 0;
+
+ cons_free_list = 0;
+
+ for (cblk = cons_block; cblk; cblk = cblk->next)
+ {
+ register int i;
+ for (i = 0; i < lim; i++)
+ if (!XMARKBIT (cblk->conses[i].car))
+ {
+ XFASTINT (cblk->conses[i].car) = (int) cons_free_list;
+ num_free++;
+ cons_free_list = &cblk->conses[i];
+ }
+ else
+ {
+ num_used++;
+ XUNMARK (cblk->conses[i].car);
+ }
+ lim = CONS_BLOCK_SIZE;
+ }
+ total_conses = num_used;
+ total_free_conses = num_free;
+ }
+
+ /* Put all unmarked symbols on free list */
+ {
+ register struct symbol_block *sblk;
+ register int lim = symbol_block_index;
+ register int num_free = 0, num_used = 0;
+
+ symbol_free_list = 0;
+
+ for (sblk = symbol_block; sblk; sblk = sblk->next)
+ {
+ register int i;
+ for (i = 0; i < lim; i++)
+ if (!XMARKBIT (sblk->symbols[i].plist))
+ {
+ XFASTINT (sblk->symbols[i].value) = (int) symbol_free_list;
+ symbol_free_list = &sblk->symbols[i];
+ num_free++;
+ }
+ else
+ {
+ num_used++;
+ sblk->symbols[i].name
+ = XSTRING (*(Lisp_Object *) &sblk->symbols[i].name);
+ XUNMARK (sblk->symbols[i].plist);
+ }
+ lim = SYMBOL_BLOCK_SIZE;
+ }
+ total_symbols = num_used;
+ total_free_symbols = num_free;
+ }
+
+#ifndef standalone
+ /* Put all unmarked markers on free list.
+ Dechain each one first from the buffer it points into. */
+ {
+ register struct marker_block *mblk;
+ struct Lisp_Marker *tem1;
+ register int lim = marker_block_index;
+ register int num_free = 0, num_used = 0;
+
+ marker_free_list = 0;
+
+ for (mblk = marker_block; mblk; mblk = mblk->next)
+ {
+ register int i;
+ for (i = 0; i < lim; i++)
+ if (!XMARKBIT (mblk->markers[i].chain))
+ {
+ Lisp_Object tem;
+ tem1 = &mblk->markers[i]; /* tem1 avoids Sun compiler bug */
+ XSET (tem, Lisp_Marker, tem1);
+ if (tem1->buffer)
+ unchain_marker (tem);
+ XFASTINT (mblk->markers[i].chain) = (int) marker_free_list;
+ marker_free_list = &mblk->markers[i];
+ num_free++;
+ }
+ else
+ {
+ num_used++;
+ XUNMARK (mblk->markers[i].chain);
+ }
+ lim = MARKER_BLOCK_SIZE;
+ }
+
+ total_markers = num_used;
+ total_free_markers = num_free;
+ }
+
+ /* Free all unmarked buffers */
+ {
+ register struct buffer *buffer = all_buffers, *prev = 0, *next;
+
+ while (buffer)
+ if (!XMARKBIT (buffer->name))
+ {
+ if (prev)
+ prev->next = buffer->next;
+ else
+ all_buffers = buffer->next;
+ next = buffer->next;
+ free (buffer);
+ buffer = next;
+ }
+ else
+ {
+ XUNMARK (buffer->name);
+ prev = buffer, buffer = buffer->next;
+ }
+ }
+
+#endif standalone
+
+ /* Free all unmarked vectors */
+ {
+ register struct Lisp_Vector *vector = all_vectors, *prev = 0, *next;
+ total_vector_size = 0;
+
+ while (vector)
+ if (!(vector->size & ARRAY_MARK_FLAG))
+ {
+ if (prev)
+ prev->next = vector->next;
+ else
+ all_vectors = vector->next;
+ next = vector->next;
+ free (vector);
+ vector = next;
+ }
+ else
+ {
+ vector->size &= ~ARRAY_MARK_FLAG;
+ total_vector_size += vector->size;
+ prev = vector, vector = vector->next;
+ }
+ }
+
+ /* Free all "large strings" not marked with ARRAY_MARK_FLAG. */
+ {
+ register struct string_block *sb = large_string_blocks, *prev = 0, *next;
+
+ while (sb)
+ if (!(((struct Lisp_String *)(&sb->chars[0]))->size & ARRAY_MARK_FLAG))
+ {
+ if (prev)
+ prev->next = sb->next;
+ else
+ large_string_blocks = sb->next;
+ next = sb->next;
+ free (sb);
+ sb = next;
+ }
+ else
+ {
+ ((struct Lisp_String *)(&sb->chars[0]))->size
+ &= ~ARRAY_MARK_FLAG & ~MARKBIT;
+ total_string_size += ((struct Lisp_String *)(&sb->chars[0]))->size;
+ prev = sb, sb = sb->next;
+ }
+ }
+}
+
+/* Compactify strings, relocate references to them, and
+ free any string blocks that become empty. */
+
+static void
+compact_strings ()
+{
+ /* String block of old strings we are scanning. */
+ register struct string_block *from_sb;
+ /* A preceding string block (or maybe the same one)
+ where we are copying the still-live strings to. */
+ register struct string_block *to_sb;
+ int pos;
+ int to_pos;
+
+ to_sb = first_string_block;
+ to_pos = 0;
+
+ /* Scan each existing string block sequentially, string by string. */
+ for (from_sb = first_string_block; from_sb; from_sb = from_sb->next)
+ {
+ pos = 0;
+ /* POS is the index of the next string in the block. */
+ while (pos < from_sb->pos)
+ {
+ register struct Lisp_String *nextstr
+ = (struct Lisp_String *) &from_sb->chars[pos];
+
+ register struct Lisp_String *newaddr;
+ register int size = nextstr->size;
+
+ /* NEXTSTR is the old address of the next string.
+ Just skip it if it isn't marked. */
+ if ((unsigned) size > STRING_BLOCK_SIZE)
+ {
+ /* It is marked, so its size field is really a chain of refs.
+ Find the end of the chain, where the actual size lives. */
+ while ((unsigned) size > STRING_BLOCK_SIZE)
+ {
+ if (size & 1) size ^= MARKBIT | 1;
+ size = *(int *)size & ~MARKBIT;
+ }
+
+ total_string_size += size;
+
+ /* If it won't fit in TO_SB, close it out,
+ and move to the next sb. Keep doing so until
+ TO_SB reaches a large enough, empty enough string block.
+ We know that TO_SB cannot advance past FROM_SB here
+ since FROM_SB is large enough to contain this string.
+ Any string blocks skipped here
+ will be patched out and freed later. */
+ while (to_pos + STRING_FULLSIZE (size)
+ > max (to_sb->pos, STRING_BLOCK_SIZE))
+ {
+ to_sb->pos = to_pos;
+ to_sb = to_sb->next;
+ to_pos = 0;
+ }
+ /* Compute new address of this string
+ and update TO_POS for the space being used. */
+ newaddr = (struct Lisp_String *) &to_sb->chars[to_pos];
+ to_pos += STRING_FULLSIZE (size);
+
+ /* Copy the string itself to the new place. */
+ if (nextstr != newaddr)
+ bcopy (nextstr, newaddr, size + 1 + sizeof (int));
+
+ /* Go through NEXTSTR's chain of references
+ and make each slot in the chain point to
+ the new address of this string. */
+ size = newaddr->size;
+ while ((unsigned) size > STRING_BLOCK_SIZE)
+ {
+ register Lisp_Object *objptr;
+ if (size & 1) size ^= MARKBIT | 1;
+ objptr = (Lisp_Object *)size;
+
+ size = XFASTINT (*objptr) & ~MARKBIT;
+ if (XMARKBIT (*objptr))
+ {
+ XSET (*objptr, Lisp_String, newaddr);
+ XMARK (*objptr);
+ }
+ else
+ XSET (*objptr, Lisp_String, newaddr);
+ }
+ /* Store the actual size in the size field. */
+ newaddr->size = size;
+ }
+ pos += STRING_FULLSIZE (size);
+ }
+ }
+
+ /* Close out the last string block still used and free any that follow. */
+ to_sb->pos = to_pos;
+ current_string_block = to_sb;
+
+ from_sb = to_sb->next;
+ to_sb->next = 0;
+ while (from_sb)
+ {
+ to_sb = from_sb->next;
+ free (from_sb);
+ from_sb = to_sb;
+ }
+
+ /* Free any empty string blocks further back in the chain.
+ This loop will never free first_string_block, but it is very
+ unlikely that that one will become empty, so why bother checking? */
+
+ from_sb = first_string_block;
+ while (to_sb = from_sb->next)
+ {
+ if (to_sb->pos == 0)
+ {
+ if (from_sb->next = to_sb->next)
+ from_sb->next->prev = from_sb;
+ free (to_sb);
+ }
+ else
+ from_sb = to_sb;
+ }
+}
+
+truncate_all_undos ()
+{
+ register struct buffer *nextb = all_buffers;
+
+ consing_at_last_truncate = consing_since_gc;
+
+ while (nextb)
+ {
+ /* If a buffer's undo list is Qt, that means that undo is
+ 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 (! EQ (nextb->undo_list, Qt))
+ nextb->undo_list
+ = truncate_undo_list (nextb->undo_list, undo_threshold,
+ undo_high_threshold);
+ nextb = nextb->next;
+ }
+}
+
+/* Initialization */
+
+init_alloc_once ()
+{
+ /* Used to do Vpurify_flag = Qt here, but Qt isn't set up yet! */
+ pureptr = 0;
+ all_vectors = 0;
+ init_strings ();
+ init_cons ();
+ init_symbol ();
+ init_marker ();
+ gcprolist = 0;
+ staticidx = 0;
+ consing_since_gc = 0;
+ gc_cons_threshold = 100000;
+#ifdef VIRT_ADDR_VARIES
+ malloc_sbrk_unused = 1<<22; /* A large number */
+ malloc_sbrk_used = 100000; /* as reasonable as any number */
+#endif /* VIRT_ADDR_VARIES */
+}
+
+init_alloc ()
+{
+ gcprolist = 0;
+}
+
+void
+syms_of_alloc ()
+{
+ memory_exhausted_message = Fcons (build_string ("Memory exhausted"), Qnil);
+ staticpro (&memory_exhausted_message);
+
+ DEFVAR_INT ("gc-cons-threshold", &gc_cons_threshold,
+ "*Number of bytes of consing between garbage collections.");
+
+ DEFVAR_INT ("pure-bytes-used", &pureptr,
+ "Number of bytes of sharable Lisp data allocated so far.");
+
+#if 0
+ DEFVAR_INT ("data-bytes-used", &malloc_sbrk_used,
+ "Number of bytes of unshared memory allocated in this session.");
+
+ DEFVAR_INT ("data-bytes-free", &malloc_sbrk_unused,
+ "Number of bytes of unshared memory remaining available in this session.");
+#endif
+
+ DEFVAR_LISP ("purify-flag", &Vpurify_flag,
+ "Non-nil means loading Lisp code in order to dump an executable.");
+
+ DEFVAR_INT ("undo-threshold", &undo_threshold,
+ "Keep no more undo information once it exceeds this size.\n\
+This threshold is applied when garbage collection happens.\n\
+The size is counted as the number of bytes occupied,\n\
+which includes both saved text and other data.");
+ undo_threshold = 15000;
+ DEFVAR_INT ("undo-high-threshold", &undo_high_threshold,
+ "Don't keep more than this much size of undo information.\n\
+A command which pushes past this size is itself forgotten.\n\
+This threshold is applied when garbage collection happens.\n\
+The size is counted as the number of bytes occupied,\n\
+which includes both saved text and other data.");
+ undo_high_threshold = 20000;
+
+ defsubr (&Scons);
+ defsubr (&Slist);
+ defsubr (&Svector);
+ defsubr (&Smake_list);
+ defsubr (&Smake_vector);
+ defsubr (&Smake_string);
+ defsubr (&Smake_symbol);
+ defsubr (&Smake_marker);
+ defsubr (&Spurecopy);
+ defsubr (&Sgarbage_collect);
+}