* src/alloc.c (enum mem_type): Remove MEM_TYPE_BUFFER.
(allocate_buffer): Allocate like any other pseudovector.
Don't register on `all_buffers` any more.
(live_buffer_holding, live_buffer_p): Delete functions.
(mark_maybe_object, valid_lisp_object_p): Don't pay attention to
MEM_TYPE_BUFFER any more.
(garbage_collect): Only compact the live buffers.
(mark_buffer): Mark the undo_list of dead buffers here.
(mark_object): Buffers are normal pseudovectors now.
(sweep_buffers): Don't do the actual sweep here, just cleanup the
markers and only for live buffers.
* src/buffer.c (all_buffers): Remove variable.
(Fkill_buffer): Don't check indirect dead buffers.
Set the undo_list before we remove ourselves from the list of live buffers.
(Fbuffer_swap_text, Fset_buffer_multibyte): Don't check indirect dead
buffers.
(init_buffer_once): Don't set `all_buffers`.
(init_buffer): Don't map new memory for dead buffers.
* src/buffer.h (struct buffer): Remove `next` field.
(FOR_EACH_BUFFER): Remove macro.
* src/pdumper.c (dump_buffer): Don't dump the `next` field.
enum mem_type
{
MEM_TYPE_NON_LISP,
- MEM_TYPE_BUFFER,
MEM_TYPE_CONS,
MEM_TYPE_STRING,
MEM_TYPE_SYMBOL,
struct buffer *
allocate_buffer (void)
{
- struct buffer *b = lisp_malloc (sizeof *b, false, MEM_TYPE_BUFFER);
-
+ struct buffer *b
+ = ALLOCATE_PSEUDOVECTOR (struct buffer, cursor_in_non_selected_windows_,
+ PVEC_BUFFER);
BUFFER_PVEC_INIT (b);
- /* Put B on the chain of all buffers including killed ones. */
- b->next = all_buffers;
- all_buffers = b;
/* Note that the rest fields of B are not initialized. */
return b;
}
return !NILP (live_vector_holding (m, p));
}
-/* If P is a pointer into a valid buffer object, return the buffer.
- Otherwise, return nil. M is a pointer to the mem_block for P.
- If IGNORE_KILLED is non-zero, treat killed buffers as invalid. */
-
-static Lisp_Object
-live_buffer_holding (struct mem_node *m, void *p, bool ignore_killed)
-{
- /* P must point into the block, and the buffer must not
- have been killed unless ALL-BUFFERS is true. */
- if (m->type == MEM_TYPE_BUFFER)
- {
- struct buffer *b = m->start;
- char *cb = m->start;
- char *cp = p;
- ptrdiff_t offset = cp - cb;
- if (0 <= offset && offset < sizeof *b
- && !(ignore_killed && NILP (b->name_)))
- {
- Lisp_Object obj;
- XSETBUFFER (obj, b);
- return obj;
- }
- }
- return Qnil;
-}
-
-/* If P is a pointer into a live (valid and not killed) buffer object,
- return non-zero. */
-static bool
-live_buffer_p (struct mem_node *m, void *p)
-{
- return !NILP (live_buffer_holding (m, p, true));
-}
-
/* Mark OBJ if we can prove it's a Lisp_Object. */
static void
break;
case Lisp_Vectorlike:
- mark_p = (EQ (obj, live_vector_holding (m, po))
- || EQ (obj, live_buffer_holding (m, po, false)));
+ mark_p = (EQ (obj, live_vector_holding (m, po)));
break;
default:
/* Nothing to do; not a pointer to Lisp memory. */
break;
- case MEM_TYPE_BUFFER:
- obj = live_buffer_holding (m, p, false);
- break;
-
case MEM_TYPE_CONS:
obj = live_cons_holding (m, p);
break;
case MEM_TYPE_SPARE:
return 0;
- case MEM_TYPE_BUFFER:
- return live_buffer_p (m, p) ? 1 : 2;
-
case MEM_TYPE_CONS:
return live_cons_p (m, p);
void
garbage_collect (void)
{
- struct buffer *nextb;
+ Lisp_Object tail, buffer;
char stack_top_variable;
bool message_p;
ptrdiff_t count = SPECPDL_INDEX ();
/* Don't keep undo information around forever.
Do this early on, so it is no problem if the user quits. */
- FOR_EACH_BUFFER (nextb)
- compact_buffer (nextb);
+ FOR_EACH_LIVE_BUFFER (tail, buffer)
+ compact_buffer (XBUFFER (buffer));
byte_ct tot_before = (profiler_memory_running
? total_bytes_of_live_objects ()
compact_font_caches ();
- FOR_EACH_BUFFER (nextb)
+ FOR_EACH_LIVE_BUFFER (tail, buffer)
{
+ struct buffer *nextb = XBUFFER (buffer);
if (!EQ (BVAR (nextb, undo_list), Qt))
bset_undo_list (nextb, compact_undo_list (BVAR (nextb, undo_list)));
/* Now that we have stripped the elements that need not be
/* For now, we just don't mark the undo_list. It's done later in
a special way just before the sweep phase, and after stripping
- some of its elements that are not needed any more. */
+ some of its elements that are not needed any more.
+ Note: this later processing is only done for live buffers, so
+ for dead buffers, the undo_list should be nil (set by Fkill_buffer),
+ but just to be on the safe side, we mark it here. */
+ if (!BUFFER_LIVE_P (buffer))
+ mark_object (BVAR (buffer, undo_list));
mark_overlay (buffer->overlays_before);
mark_overlay (buffer->overlays_after);
= PSEUDOVECTOR_TYPE (ptr);
if (pvectype != PVEC_SUBR &&
- pvectype != PVEC_BUFFER &&
!main_thread_p (po))
CHECK_LIVE (live_vector_p);
switch (pvectype)
{
case PVEC_BUFFER:
-#if GC_CHECK_MARKED_OBJECTS
- {
- struct buffer *b;
- FOR_EACH_BUFFER (b)
- if (b == po)
- break;
- if (b == NULL)
- emacs_abort ();
- }
-#endif /* GC_CHECK_MARKED_OBJECTS */
mark_buffer ((struct buffer *) ptr);
break;
static void
sweep_buffers (void)
{
- struct buffer *buffer, **bprev = &all_buffers;
+ Lisp_Object tail, buf;
gcstat.total_buffers = 0;
- for (buffer = all_buffers; buffer; buffer = *bprev)
- if (!vectorlike_marked_p (&buffer->header))
- {
- *bprev = buffer->next;
- lisp_free (buffer);
- }
- else
- {
- if (!pdumper_object_p (buffer))
- XUNMARK_VECTOR (buffer);
- /* Do not use buffer_(set|get)_intervals here. */
- buffer->text->intervals = balance_intervals (buffer->text->intervals);
- unchain_dead_markers (buffer);
- gcstat.total_buffers++;
- bprev = &buffer->next;
- }
+ FOR_EACH_LIVE_BUFFER (tail, buf)
+ {
+ struct buffer *buffer = XBUFFER (buf);
+ /* Do not use buffer_(set|get)_intervals here. */
+ buffer->text->intervals = balance_intervals (buffer->text->intervals);
+ unchain_dead_markers (buffer);
+ gcstat.total_buffers++;
+ }
}
/* Sweep: find all structures not marked, and free them. */
#include "w32heap.h" /* for mmap_* */
#endif
-/* First buffer in chain of all buffers (in reverse order of creation).
- Threaded through ->header.next.buffer. */
-
-struct buffer *all_buffers;
-
/* This structure holds the default values of the buffer-local variables
defined with DEFVAR_PER_BUFFER, that have special slots in each buffer.
The default value occupies the same slot in this structure
ask questions or their hooks get errors. */
if (!b->base_buffer && b->indirections > 0)
{
- struct buffer *other;
+ Lisp_Object tail, other;
- FOR_EACH_BUFFER (other)
- if (other->base_buffer == b)
- {
- Lisp_Object buf;
- XSETBUFFER (buf, other);
- Fkill_buffer (buf);
- }
+ FOR_EACH_LIVE_BUFFER (tail, other)
+ if (XBUFFER (other)->base_buffer == b)
+ Fkill_buffer (other);
/* Exit if we now have killed the base buffer (Bug#11665). */
if (!BUFFER_LIVE_P (b))
tem = Vinhibit_quit;
Vinhibit_quit = Qt;
+ /* Once the buffer is removed from Vbuffer_alist, its undo_list field is
+ not traced by the GC in the same way. So set it to nil early. */
+ bset_undo_list (b, Qnil);
/* Remove the buffer from the list of all buffers. */
Vbuffer_alist = Fdelq (Frassq (buffer, Vbuffer_alist), Vbuffer_alist);
/* If replace_buffer_in_windows didn't do its job fix that now. */
}
bset_width_table (b, Qnil);
unblock_input ();
- bset_undo_list (b, Qnil);
/* Run buffer-list-update-hook. */
if (!NILP (Vrun_hooks) && !b->inhibit_buffer_hooks)
error ("Cannot swap indirect buffers's text");
{ /* This is probably harder to make work. */
- struct buffer *other;
- FOR_EACH_BUFFER (other)
- if (other->base_buffer == other_buffer
- || other->base_buffer == current_buffer)
+ Lisp_Object tail, other;
+ FOR_EACH_LIVE_BUFFER (tail, other)
+ if (XBUFFER (other)->base_buffer == other_buffer
+ || XBUFFER (other)->base_buffer == current_buffer)
error ("One of the buffers to swap has indirect buffers");
}
(Lisp_Object flag)
{
struct Lisp_Marker *tail, *markers;
- struct buffer *other;
+ Lisp_Object btail, other;
ptrdiff_t begv, zv;
bool narrowed = (BEG != BEGV || Z != ZV);
bool modified_p = !NILP (Fbuffer_modified_p (Qnil));
/* Copy this buffer's new multibyte status
into all of its indirect buffers. */
- FOR_EACH_BUFFER (other)
- if (other->base_buffer == current_buffer && BUFFER_LIVE_P (other))
- {
- BVAR (other, enable_multibyte_characters)
- = BVAR (current_buffer, enable_multibyte_characters);
- other->prevent_redisplay_optimizations_p = 1;
- }
+ FOR_EACH_LIVE_BUFFER (btail, other)
+ {
+ struct buffer *o = XBUFFER (other);
+ if (o->base_buffer == current_buffer && BUFFER_LIVE_P (o))
+ {
+ BVAR (o, enable_multibyte_characters)
+ = BVAR (current_buffer, enable_multibyte_characters);
+ o->prevent_redisplay_optimizations_p = true;
+ }
+ }
/* Restore the modifiedness of the buffer. */
if (!modified_p && !NILP (Fbuffer_modified_p (Qnil)))
Vbuffer_alist = Qnil;
current_buffer = 0;
pdumper_remember_lv_ptr_raw (¤t_buffer, Lisp_Vectorlike);
- all_buffers = 0;
- pdumper_remember_lv_ptr_raw (&all_buffers, Lisp_Vectorlike);
QSFundamental = build_pure_c_string ("Fundamental");
#ifdef USE_MMAP_FOR_BUFFERS
if (dumped_with_unexec_p ())
{
- struct buffer *b;
+ Lisp_Object tail, buffer;
#ifndef WINDOWSNT
/* These must be reset in the dumped Emacs, to avoid stale
" *code-conversion-work*". They are created by
init_buffer_once and init_window_once (which are not called
in the dumped Emacs), and by the first call to coding.c routines. */
- FOR_EACH_BUFFER (b)
+ FOR_EACH_LIVE_BUFFER (tail, buffer)
{
+ struct buffer *b = XBUFFER (buffer);
b->text->beg = NULL;
enlarge_buffer_text (b, 0);
}
In an indirect buffer, this is the own_text field of another buffer. */
struct buffer_text *text;
- /* Next buffer, in chain of all buffers, including killed ones. */
- struct buffer *next;
-
/* Char position of point in buffer. */
ptrdiff_t pt;
}
}
-/* Chain of all buffers, including killed ones. */
-
-extern struct buffer *all_buffers;
-
-/* Used to iterate over the chain above. */
-
-#define FOR_EACH_BUFFER(b) \
- for ((b) = all_buffers; (b); (b) = (b)->next)
-
/* This structure holds the default values of the buffer-local variables
that have special slots in each buffer.
The default value occupies the same slot in this structure
ctx->obj_offset + dump_offsetof (struct buffer, text),
base_offset + dump_offsetof (struct buffer, own_text));
- dump_field_lv_rawptr (ctx, out, buffer, &buffer->next,
- Lisp_Vectorlike, WEIGHT_NORMAL);
DUMP_FIELD_COPY (out, buffer, pt);
DUMP_FIELD_COPY (out, buffer, pt_byte);
DUMP_FIELD_COPY (out, buffer, begv);