diff options
| author | Dmitry Antipov | 2012-07-20 20:05:47 +0400 |
|---|---|---|
| committer | Dmitry Antipov | 2012-07-20 20:05:47 +0400 |
| commit | 9928463dcdb0164477785e83406602065de79ef8 (patch) | |
| tree | 14d6b28885b7e333733ff4eb62275e6e425f81b3 /src | |
| parent | f8643a6b9e35af22b69a84f83df5d9410de82f16 (diff) | |
| download | emacs-9928463dcdb0164477785e83406602065de79ef8.tar.gz emacs-9928463dcdb0164477785e83406602065de79ef8.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 11 | ||||
| -rw-r--r-- | src/buffer.c | 32 | ||||
| -rw-r--r-- | src/buffer.h | 5 |
3 files changed, 45 insertions, 3 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index d7d02a2262a..e90e48ee9dc 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,16 @@ | |||
| 1 | 2012-07-20 Dmitry Antipov <dmantipov@yandex.ru> | 1 | 2012-07-20 Dmitry Antipov <dmantipov@yandex.ru> |
| 2 | 2 | ||
| 3 | Add indirection counting to speed up Fkill_buffer. | ||
| 4 | * buffer.h (struct buffer): New member. | ||
| 5 | * buffer.c (Fget_buffer_create): Set indirection counter to 0. | ||
| 6 | (Fmake_indirect_buffer): Set indirection counter to -1, increment | ||
| 7 | base buffer indirection counter. | ||
| 8 | (compact_buffer): If ENABLE_CHECKING, verify indirection counters. | ||
| 9 | (Fkill_buffer): Adjust indirection counters as needed, don't walk | ||
| 10 | through buffer list if indirection counter is 0. | ||
| 11 | |||
| 12 | 2012-07-20 Dmitry Antipov <dmantipov@yandex.ru> | ||
| 13 | |||
| 3 | Extend the value returned by Fgarbage_collect with heap statistics. | 14 | Extend the value returned by Fgarbage_collect with heap statistics. |
| 4 | * alloc.c (Qheap): New symbol. | 15 | * alloc.c (Qheap): New symbol. |
| 5 | (syms_of_alloc): DEFSYM it. | 16 | (syms_of_alloc): DEFSYM it. |
diff --git a/src/buffer.c b/src/buffer.c index b722ff135dd..5f9f6a79b67 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
| @@ -329,7 +329,9 @@ even if it is dead. The return value is never nil. */) | |||
| 329 | 329 | ||
| 330 | /* An ordinary buffer uses its own struct buffer_text. */ | 330 | /* An ordinary buffer uses its own struct buffer_text. */ |
| 331 | b->text = &b->own_text; | 331 | b->text = &b->own_text; |
| 332 | b->base_buffer = 0; | 332 | b->base_buffer = NULL; |
| 333 | /* No one shares the text with us now. */ | ||
| 334 | b->indirections = 0; | ||
| 333 | 335 | ||
| 334 | BUF_GAP_SIZE (b) = 20; | 336 | BUF_GAP_SIZE (b) = 20; |
| 335 | BLOCK_INPUT; | 337 | BLOCK_INPUT; |
| @@ -568,12 +570,18 @@ CLONE nil means the indirect buffer's state is reset to default values. */) | |||
| 568 | 570 | ||
| 569 | b = allocate_buffer (); | 571 | b = allocate_buffer (); |
| 570 | 572 | ||
| 573 | /* No double indirection - if base buffer is indirect, | ||
| 574 | new buffer becomes an indirect to base's base. */ | ||
| 571 | b->base_buffer = (XBUFFER (base_buffer)->base_buffer | 575 | b->base_buffer = (XBUFFER (base_buffer)->base_buffer |
| 572 | ? XBUFFER (base_buffer)->base_buffer | 576 | ? XBUFFER (base_buffer)->base_buffer |
| 573 | : XBUFFER (base_buffer)); | 577 | : XBUFFER (base_buffer)); |
| 574 | 578 | ||
| 575 | /* Use the base buffer's text object. */ | 579 | /* Use the base buffer's text object. */ |
| 576 | b->text = b->base_buffer->text; | 580 | b->text = b->base_buffer->text; |
| 581 | /* We have no own text. */ | ||
| 582 | b->indirections = -1; | ||
| 583 | /* Notify base buffer that we share the text now. */ | ||
| 584 | b->base_buffer->indirections++; | ||
| 577 | 585 | ||
| 578 | b->pt = b->base_buffer->pt; | 586 | b->pt = b->base_buffer->pt; |
| 579 | b->begv = b->base_buffer->begv; | 587 | b->begv = b->base_buffer->begv; |
| @@ -1439,6 +1447,15 @@ No argument or nil as argument means do this for the current buffer. */) | |||
| 1439 | int | 1447 | int |
| 1440 | compact_buffer (struct buffer *buffer) | 1448 | compact_buffer (struct buffer *buffer) |
| 1441 | { | 1449 | { |
| 1450 | /* Verify indirection counters. */ | ||
| 1451 | if (buffer->base_buffer) | ||
| 1452 | { | ||
| 1453 | eassert (buffer->indirections == -1); | ||
| 1454 | eassert (buffer->base_buffer->indirections > 0); | ||
| 1455 | } | ||
| 1456 | else | ||
| 1457 | eassert (buffer->indirections >= 0); | ||
| 1458 | |||
| 1442 | /* Skip dead buffers, indirect buffers and buffers | 1459 | /* Skip dead buffers, indirect buffers and buffers |
| 1443 | which aren't changed since last compaction. */ | 1460 | which aren't changed since last compaction. */ |
| 1444 | if (!NILP (buffer->BUFFER_INTERNAL_FIELD (name)) | 1461 | if (!NILP (buffer->BUFFER_INTERNAL_FIELD (name)) |
| @@ -1555,10 +1572,19 @@ cleaning up all windows currently displaying the buffer to be killed. */) | |||
| 1555 | if (EQ (buffer, XWINDOW (minibuf_window)->buffer)) | 1572 | if (EQ (buffer, XWINDOW (minibuf_window)->buffer)) |
| 1556 | return Qnil; | 1573 | return Qnil; |
| 1557 | 1574 | ||
| 1558 | /* When we kill a base buffer, kill all its indirect buffers. | 1575 | /* Notify our base buffer that we don't share the text anymore. */ |
| 1576 | if (b->base_buffer) | ||
| 1577 | { | ||
| 1578 | eassert (b->indirections == -1); | ||
| 1579 | b->base_buffer->indirections--; | ||
| 1580 | eassert (b->base_buffer->indirections >= 0); | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | /* When we kill an ordinary buffer which shares it's buffer text | ||
| 1584 | with indirect buffer(s), we must kill indirect buffer(s) too. | ||
| 1559 | We do it at this stage so nothing terrible happens if they | 1585 | We do it at this stage so nothing terrible happens if they |
| 1560 | ask questions or their hooks get errors. */ | 1586 | ask questions or their hooks get errors. */ |
| 1561 | if (! b->base_buffer) | 1587 | if (!b->base_buffer && b->indirections > 0) |
| 1562 | { | 1588 | { |
| 1563 | struct buffer *other; | 1589 | struct buffer *other; |
| 1564 | 1590 | ||
diff --git a/src/buffer.h b/src/buffer.h index a97cc13705b..69be4dc7773 100644 --- a/src/buffer.h +++ b/src/buffer.h | |||
| @@ -775,6 +775,11 @@ struct buffer | |||
| 775 | In an ordinary buffer, it is 0. */ | 775 | In an ordinary buffer, it is 0. */ |
| 776 | struct buffer *base_buffer; | 776 | struct buffer *base_buffer; |
| 777 | 777 | ||
| 778 | /* In an indirect buffer, this is -1. In an ordinary buffer, | ||
| 779 | it's the number of indirect buffers which shares our text; | ||
| 780 | zero means that we're the only owner of this text. */ | ||
| 781 | int indirections; | ||
| 782 | |||
| 778 | /* A non-zero value in slot IDX means that per-buffer variable | 783 | /* A non-zero value in slot IDX means that per-buffer variable |
| 779 | with index IDX has a local value in this buffer. The index IDX | 784 | with index IDX has a local value in this buffer. The index IDX |
| 780 | for a buffer-local variable is stored in that variable's slot | 785 | for a buffer-local variable is stored in that variable's slot |