+2012-07-20 Dmitry Antipov <dmantipov@yandex.ru>
+
+ Add indirection counting to speed up Fkill_buffer.
+ * buffer.h (struct buffer): New member.
+ * buffer.c (Fget_buffer_create): Set indirection counter to 0.
+ (Fmake_indirect_buffer): Set indirection counter to -1, increment
+ base buffer indirection counter.
+ (compact_buffer): If ENABLE_CHECKING, verify indirection counters.
+ (Fkill_buffer): Adjust indirection counters as needed, don't walk
+ through buffer list if indirection counter is 0.
+
2012-07-20 Dmitry Antipov <dmantipov@yandex.ru>
Extend the value returned by Fgarbage_collect with heap statistics.
/* An ordinary buffer uses its own struct buffer_text. */
b->text = &b->own_text;
- b->base_buffer = 0;
+ b->base_buffer = NULL;
+ /* No one shares the text with us now. */
+ b->indirections = 0;
BUF_GAP_SIZE (b) = 20;
BLOCK_INPUT;
b = allocate_buffer ();
+ /* No double indirection - if base buffer is indirect,
+ new buffer becomes an indirect to base's base. */
b->base_buffer = (XBUFFER (base_buffer)->base_buffer
? XBUFFER (base_buffer)->base_buffer
: XBUFFER (base_buffer));
/* Use the base buffer's text object. */
b->text = b->base_buffer->text;
+ /* We have no own text. */
+ b->indirections = -1;
+ /* Notify base buffer that we share the text now. */
+ b->base_buffer->indirections++;
b->pt = b->base_buffer->pt;
b->begv = b->base_buffer->begv;
int
compact_buffer (struct buffer *buffer)
{
+ /* Verify indirection counters. */
+ if (buffer->base_buffer)
+ {
+ eassert (buffer->indirections == -1);
+ eassert (buffer->base_buffer->indirections > 0);
+ }
+ else
+ eassert (buffer->indirections >= 0);
+
/* Skip dead buffers, indirect buffers and buffers
which aren't changed since last compaction. */
if (!NILP (buffer->BUFFER_INTERNAL_FIELD (name))
if (EQ (buffer, XWINDOW (minibuf_window)->buffer))
return Qnil;
- /* When we kill a base buffer, kill all its indirect buffers.
+ /* Notify our base buffer that we don't share the text anymore. */
+ if (b->base_buffer)
+ {
+ eassert (b->indirections == -1);
+ b->base_buffer->indirections--;
+ eassert (b->base_buffer->indirections >= 0);
+ }
+
+ /* When we kill an ordinary buffer which shares it's buffer text
+ with indirect buffer(s), we must kill indirect buffer(s) too.
We do it at this stage so nothing terrible happens if they
ask questions or their hooks get errors. */
- if (! b->base_buffer)
+ if (!b->base_buffer && b->indirections > 0)
{
struct buffer *other;
In an ordinary buffer, it is 0. */
struct buffer *base_buffer;
+ /* In an indirect buffer, this is -1. In an ordinary buffer,
+ it's the number of indirect buffers which shares our text;
+ zero means that we're the only owner of this text. */
+ int indirections;
+
/* A non-zero value in slot IDX means that per-buffer variable
with index IDX has a local value in this buffer. The index IDX
for a buffer-local variable is stored in that variable's slot