/* Storage allocation and gc for GNU Emacs Lisp interpreter.
- Copyright (C) 1985, 1986, 1988, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1985, 1986, 1988, 1993 Free Software Foundation, Inc.
This file is part of GNU Emacs.
along with GNU Emacs; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <signal.h>
-#include "config.h"
+#include <config.h>
#include "lisp.h"
#include "intervals.h"
#include "puresize.h"
#include "buffer.h"
#include "window.h"
#include "frame.h"
+#include "blockinput.h"
#endif
#include "syssignal.h"
XSET (val, Lisp_Cons, (char *) address + size); \
if ((char *) XCONS (val) != (char *) address + size) \
{ \
- free (address); \
+ xfree (address); \
memory_full (); \
} \
} while (0)
error ("Memory exhausted");
}
-/* like malloc and realloc but check for no memory left */
+/* like malloc routines but check for no memory and block interrupt input. */
long *
xmalloc (size)
{
register long *val;
+ BLOCK_INPUT;
val = (long *) malloc (size);
+ UNBLOCK_INPUT;
if (!val && size) memory_full ();
return val;
{
register long *val;
+ BLOCK_INPUT;
/* We must call malloc explicitly when BLOCK is 0, since some
reallocs don't do this. */
if (! block)
val = (long *) malloc (size);
else
val = (long *) realloc (block, size);
+ UNBLOCK_INPUT;
if (!val && size) memory_full ();
return val;
}
+
+void
+xfree (block)
+ long *block;
+{
+ BLOCK_INPUT;
+ free (block);
+ UNBLOCK_INPUT;
+}
+
+\f
+/* Arranging to disable input signals while we're in malloc.
+
+ This only works with GNU malloc. To help out systems which can't
+ use GNU malloc, all the calls to malloc, realloc, and free
+ elsewhere in the code should be inside a BLOCK_INPUT/UNBLOCK_INPUT
+ pairs; unfortunately, we have no idea what C library functions
+ might call malloc, so we can't really protect them unless you're
+ using GNU malloc. Fortunately, most of the major operating can use
+ GNU malloc. */
+
+#ifndef SYSTEM_MALLOC
+extern void * (*__malloc_hook) ();
+static void * (*old_malloc_hook) ();
+extern void * (*__realloc_hook) ();
+static void * (*old_realloc_hook) ();
+extern void (*__free_hook) ();
+static void (*old_free_hook) ();
+
+static void
+emacs_blocked_free (ptr)
+ void *ptr;
+{
+ BLOCK_INPUT;
+ __free_hook = old_free_hook;
+ free (ptr);
+ __free_hook = emacs_blocked_free;
+ UNBLOCK_INPUT;
+}
+
+static void *
+emacs_blocked_malloc (size)
+ unsigned size;
+{
+ void *value;
+
+ BLOCK_INPUT;
+ __malloc_hook = old_malloc_hook;
+ value = (void *) malloc (size);
+ __malloc_hook = emacs_blocked_malloc;
+ UNBLOCK_INPUT;
+
+ return value;
+}
+
+static void *
+emacs_blocked_realloc (ptr, size)
+ void *ptr;
+ unsigned size;
+{
+ void *value;
+
+ BLOCK_INPUT;
+ __realloc_hook = old_realloc_hook;
+ value = (void *) realloc (ptr, size);
+ __realloc_hook = emacs_blocked_realloc;
+ UNBLOCK_INPUT;
+
+ return value;
+}
+
+void
+uninterrupt_malloc ()
+{
+ old_free_hook = __free_hook;
+ __free_hook = emacs_blocked_free;
+
+ old_malloc_hook = __malloc_hook;
+ __malloc_hook = emacs_blocked_malloc;
+
+ old_realloc_hook = __realloc_hook;
+ __realloc_hook = emacs_blocked_realloc;
+}
+#endif
\f
/* Interval allocation. */
if (interval_block_index == INTERVAL_BLOCK_SIZE)
{
register struct interval_block *newi
- = (struct interval_block *) malloc (sizeof (struct interval_block));
-
- if (!newi)
- memory_full ();
+ = (struct interval_block *) xmalloc (sizeof (struct interval_block));
VALIDATE_LISP_STORAGE (newi, sizeof *newi);
newi->next = interval_block;
mark_interval_tree (tree)
register INTERVAL tree;
{
- if (XMARKBIT (tree->plist))
- return;
+ /* No need to test if this tree has been marked already; this
+ function is always called through the MARK_INTERVAL_TREE macro,
+ which takes care of that. */
+
+ /* XMARK expands to an assignment; the LHS of an assignment can't be
+ a cast. */
+ XMARK (* (Lisp_Object *) &tree->parent);
traverse_intervals (tree, 1, 0, mark_interval, Qnil);
}
-#define MARK_INTERVAL_TREE(i) \
- { if (!NULL_INTERVAL_P (i)) mark_interval_tree (i); }
+#define MARK_INTERVAL_TREE(i) \
+ do { \
+ if (!NULL_INTERVAL_P (i) \
+ && ! XMARKBIT ((Lisp_Object) i->parent)) \
+ mark_interval_tree (i); \
+ } while (0)
/* The oddity in the call to XUNMARK is necessary because XUNMARK
- expands to an assigment to its argument, and most C compilers don't
+ expands to an assignment to its argument, and most C compilers don't
support casts on the left operand of `='. */
#define UNMARK_BALANCE_INTERVALS(i) \
{ \
{
if (float_block_index == FLOAT_BLOCK_SIZE)
{
- register struct float_block *new = (struct float_block *) malloc (sizeof (struct float_block));
- if (!new) memory_full ();
+ register struct float_block *new = (struct float_block *) xmalloc (sizeof (struct float_block));
VALIDATE_LISP_STORAGE (new, sizeof *new);
new->next = float_block;
float_block = new;
{
if (cons_block_index == CONS_BLOCK_SIZE)
{
- register struct cons_block *new = (struct cons_block *) malloc (sizeof (struct cons_block));
- if (!new) memory_full ();
+ register struct cons_block *new = (struct cons_block *) xmalloc (sizeof (struct cons_block));
VALIDATE_LISP_STORAGE (new, sizeof *new);
new->next = cons_block;
cons_block = new;
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 ();
+ p = (struct Lisp_Vector *) xmalloc (sizeof (struct Lisp_Vector) + (sizei - 1) * sizeof (Lisp_Object));
VALIDATE_LISP_STORAGE (p, 0);
XSET (vector, Lisp_Vector, p);
{
if (symbol_block_index == SYMBOL_BLOCK_SIZE)
{
- struct symbol_block *new = (struct symbol_block *) malloc (sizeof (struct symbol_block));
- if (!new) memory_full ();
+ struct symbol_block *new = (struct symbol_block *) xmalloc (sizeof (struct symbol_block));
VALIDATE_LISP_STORAGE (new, sizeof *new);
new->next = symbol_block;
symbol_block = new;
{
if (marker_block_index == MARKER_BLOCK_SIZE)
{
- struct marker_block *new = (struct marker_block *) malloc (sizeof (struct marker_block));
- if (!new) memory_full ();
+ struct marker_block *new = (struct marker_block *) xmalloc (sizeof (struct marker_block));
VALIDATE_LISP_STORAGE (new, sizeof *new);
new->next = marker_block;
marker_block = new;
/* This string gets its own string block */
{
register struct string_block *new
- = (struct string_block *) malloc (sizeof (struct string_block_head) + fullsize);
+ = (struct string_block *) xmalloc (sizeof (struct string_block_head) + fullsize);
VALIDATE_LISP_STORAGE (new, 0);
- if (!new) memory_full ();
consing_since_gc += sizeof (struct string_block_head) + fullsize;
new->pos = fullsize;
new->next = large_string_blocks;
/* 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 ();
+ = (struct string_block *) xmalloc (sizeof (struct string_block));
VALIDATE_LISP_STORAGE (new, sizeof *new);
consing_since_gc += sizeof (struct string_block);
current_string_block->next = new;
}
/* Return a newly created vector or string with specified arguments as
- elements. If all the arguments are characters, make a string;
- otherwise, make a vector. Any number of arguments, even zero
- arguments, are allowed. */
+ elements. If all the arguments are characters that can fit
+ in a string of events, make a string; otherwise, make a vector.
+
+ Any number of arguments, even zero arguments, are allowed. */
Lisp_Object
-make_array (nargs, args)
+make_event_array (nargs, args)
register int nargs;
Lisp_Object *args;
{
int i;
for (i = 0; i < nargs; i++)
+ /* The things that fit in a string
+ are characters that are in 0...127,
+ after discarding the meta bit and all the bits above it. */
if (XTYPE (args[i]) != Lisp_Int
- || (unsigned) XINT (args[i]) >= 0400)
+ || (XUINT (args[i]) & ~(-CHAR_META)) >= 0200)
return Fvector (nargs, args);
/* Since the loop exited, we know that all the things in it are
Lisp_Object result = Fmake_string (nargs, make_number (0));
for (i = 0; i < nargs; i++)
- XSTRING (result)->data[i] = XINT (args[i]);
+ {
+ XSTRING (result)->data[i] = XINT (args[i]);
+ /* Move the meta bit to the right place for a string char. */
+ if (XINT (args[i]) & CHAR_META)
+ XSTRING (result)->data[i] |= 0x80;
+ }
return result;
}
}
\f
-/* Allocation of ropes. */
-
-/* Note: the user cannot manipulate ropes portably by referring
- to the chars of the string, because combining two chars to make a GLYPH
- depends on endianness. */
-
-DEFUN ("make-rope", Fmake_rope, Smake_rope, 0, MANY, 0,
- "Return a newly created rope containing the arguments of this function.\n\
-A rope is a string, except that its contents will be treated as an\n\
-array of glyphs, where a glyph is an integer type that may be larger\n\
-than a character. Emacs is normally configured to use 8-bit glyphs,\n\
-so ropes are normally no different from strings. But Emacs may be\n\
-configured to use 16-bit glyphs, to allow the use of larger fonts.\n\
-\n\
-Each argument (which must be an integer) specifies one glyph, whatever\n\
-size glyphs may be.\n\
-\n\
-See variable `buffer-display-table' for the uses of ropes.")
- (nargs, args)
- register int nargs;
- Lisp_Object *args;
-{
- register int i;
- register Lisp_Object val;
- register GLYPH *p;
-
- val = make_uninit_string (nargs * sizeof (GLYPH));
-
- p = (GLYPH *) XSTRING (val)->data;
- for (i = 0; i < nargs; i++)
- {
- CHECK_NUMBER (args[i], i);
- p[i] = XFASTINT (args[i]);
- }
- return val;
-}
-
-DEFUN ("rope-elt", Frope_elt, Srope_elt, 2, 2, 0,
- "Return an element of rope R at index N.\n\
-A rope is a string in which each pair of bytes is considered an element.\n\
-See variable `buffer-display-table' for the uses of ropes.")
- (r, n)
- Lisp_Object r, n;
-{
- CHECK_STRING (r, 0);
- CHECK_NUMBER (n, 1);
- if ((XSTRING (r)->size / sizeof (GLYPH)) <= XINT (n) || XINT (n) < 0)
- args_out_of_range (r, n);
- return ((GLYPH *) XSTRING (r)->data)[XFASTINT (n)];
-}
-\f
/* Pure storage management. */
/* Must get an error if pure storage is full,
if (i < MAX_SAVE_STACK)
{
if (stack_copy == 0)
- stack_copy = (char *) malloc (stack_copy_size = i);
+ stack_copy = (char *) xmalloc (stack_copy_size = i);
else if (stack_copy_size < i)
- stack_copy = (char *) realloc (stack_copy, (stack_copy_size = i));
+ stack_copy = (char *) xrealloc (stack_copy, (stack_copy_size = i));
if (stack_copy)
{
if ((int) (&stack_top_variable - stack_bottom) > 0)
if (gc_cons_threshold < 10000)
gc_cons_threshold = 10000;
- if (omessage)
+ if (omessage || minibuf_level > 0)
message1 (omessage);
else if (!noninteractive)
message1 ("Garbage collecting...done");
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
+ If the object referenced is a short string, the referencing 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
{
register struct Lisp_Vector *ptr = XVECTOR (obj);
register int size = ptr->size;
+ /* The reason we use ptr1 is to avoid an apparent hardware bug
+ that happens occasionally on the FSF's HP 300s.
+ The bug is that a2 gets clobbered by recursive calls to mark_object.
+ The clobberage seems to happen during function entry,
+ perhaps in the moveml instruction.
+ Yes, this is a crock, but we have to do it. */
struct Lisp_Vector *volatile ptr1 = ptr;
register int i;
if (size & ARRAY_MARK_FLAG) break; /* Already marked */
ptr->size |= ARRAY_MARK_FLAG; /* Else mark it */
for (i = 0; i < size; i++) /* and then mark its elements */
- {
- if (ptr != ptr1)
- abort ();
- mark_object (&ptr->contents[i]);
- }
+ mark_object (&ptr1->contents[i]);
}
break;
{
register struct Lisp_Vector *ptr = XVECTOR (obj);
register int size = ptr->size;
+ /* See comment above under Lisp_Vector. */
struct Lisp_Vector *volatile ptr1 = ptr;
register int i;
ptr->size |= ARRAY_MARK_FLAG; /* Else mark it */
for (i = 0; i < size; i++) /* and then mark its elements */
{
- if (ptr != ptr1)
- abort ();
if (i != COMPILED_CONSTANTS)
- mark_object (&ptr->contents[i]);
+ mark_object (&ptr1->contents[i]);
}
- objptr = &ptr->contents[COMPILED_CONSTANTS];
+ objptr = &ptr1->contents[COMPILED_CONSTANTS];
obj = *objptr;
goto loop;
}
#ifdef MULTI_FRAME
case Lisp_Frame:
{
- register struct frame *ptr = XFRAME (obj);
+ /* See comment above under Lisp_Vector for why this is volatile. */
+ register struct frame *volatile ptr = XFRAME (obj);
register int size = ptr->size;
if (size & ARRAY_MARK_FLAG) break; /* Already marked */
mark_object (&ptr->param_alist);
mark_object (&ptr->scroll_bars);
mark_object (&ptr->condemned_scroll_bars);
+ mark_object (&ptr->menu_bar_items);
+ mark_object (&ptr->face_alist);
}
break;
-#endif /* not MULTI_FRAME */
+#endif /* MULTI_FRAME */
case Lisp_Symbol:
{
- register struct Lisp_Symbol *ptr = XSYMBOL (obj);
+ /* See comment above under Lisp_Vector for why this is volatile. */
+ register struct Lisp_Symbol *volatile ptr = XSYMBOL (obj);
struct Lisp_Symbol *ptrx;
if (XMARKBIT (ptr->plist)) break;
ptr = ptr->next;
if (ptr)
{
- ptrx = ptr; /* Use pf ptrx avoids compiler bug on Sun */
+ ptrx = ptr; /* Use of ptrx avoids compiler bug on Sun */
XSETSYMBOL (obj, ptrx);
goto loop;
}
case Lisp_Cons:
case Lisp_Buffer_Local_Value:
case Lisp_Some_Buffer_Local_Value:
+ case Lisp_Overlay:
{
register struct Lisp_Cons *ptr = XCONS (obj);
if (XMARKBIT (ptr->car)) break;
goto loop;
}
mark_object (&ptr->car);
- objptr = &ptr->cdr;
+ /* See comment above under Lisp_Vector for why not use ptr here. */
+ objptr = &XCONS (obj)->cdr;
obj = ptr->cdr;
goto loop;
}
else
all_buffers = buffer->next;
next = buffer->next;
- free (buffer);
+ xfree (buffer);
buffer = next;
}
else
else
all_vectors = vector->next;
next = vector->next;
- free (vector);
+ xfree (vector);
vector = next;
}
else
/* Free all "large strings" not marked with ARRAY_MARK_FLAG. */
{
register struct string_block *sb = large_string_blocks, *prev = 0, *next;
+ struct Lisp_String *s;
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;
- }
+ {
+ s = (struct Lisp_String *) &sb->chars[0];
+ if (s->size & ARRAY_MARK_FLAG)
+ {
+ ((struct Lisp_String *)(&sb->chars[0]))->size
+ &= ~ARRAY_MARK_FLAG & ~MARKBIT;
+ UNMARK_BALANCE_INTERVALS (s->intervals);
+ total_string_size += ((struct Lisp_String *)(&sb->chars[0]))->size;
+ prev = sb, sb = sb->next;
+ }
+ else
+ {
+ if (prev)
+ prev->next = sb->next;
+ else
+ large_string_blocks = sb->next;
+ next = sb->next;
+ xfree (sb);
+ sb = next;
+ }
+ }
}
}
\f
}
/* Store the actual size in the size field. */
newaddr->size = size;
+
+#ifdef USE_TEXT_PROPERTIES
+ /* Now that the string has been relocated, rebalance its
+ interval tree, and update the tree's parent pointer. */
+ if (! NULL_INTERVAL_P (newaddr->intervals))
+ {
+ UNMARK_BALANCE_INTERVALS (newaddr->intervals);
+ XSET (* (Lisp_Object *) &newaddr->intervals->parent,
+ Lisp_String,
+ newaddr);
+ }
+#endif /* USE_TEXT_PROPERTIES */
}
pos += STRING_FULLSIZE (size);
}
while (from_sb)
{
to_sb = from_sb->next;
- free (from_sb);
+ xfree (from_sb);
from_sb = to_sb;
}
{
if (from_sb->next = to_sb->next)
from_sb->next->prev = from_sb;
- free (to_sb);
+ xfree (to_sb);
}
else
from_sb = to_sb;
defsubr (&Smake_list);
defsubr (&Smake_vector);
defsubr (&Smake_string);
- defsubr (&Smake_rope);
- defsubr (&Srope_elt);
defsubr (&Smake_symbol);
defsubr (&Smake_marker);
defsubr (&Spurecopy);