From: Dmitry Antipov <dmantipov@yandex.ru>
To: Emacs development discussions <emacs-devel@gnu.org>
Subject: [RFC, experimental] save_{excursion,restriction}
Date: Mon, 23 Jul 2012 21:07:02 +0400 [thread overview]
Message-ID: <500D84B6.50303@yandex.ru> (raw)
[-- Attachment #1: Type: text/plain, Size: 328 bytes --]
It's worth trying to redesign save-restriction and save-excursion to avoid
allocating Lisp data. I tried some hacks for save-excursion, and it's quite
surprising: initially, running (while t (scroll-up) (sit-for 0.05)) over
just loaded xdisp.c with font-lock enabled asks for 600 GCs, and with this
patch it's just 350.
Dmitry
[-- Attachment #2: excursion.patch --]
[-- Type: text/plain, Size: 8601 bytes --]
=== modified file 'src/alloc.c'
--- src/alloc.c 2012-07-23 11:15:43 +0000
+++ src/alloc.c 2012-07-23 16:35:09 +0000
@@ -3658,11 +3658,8 @@
val = allocate_misc (Lisp_Misc_Marker);
p = XMARKER (val);
- p->buffer = 0;
- p->bytepos = 0;
- p->charpos = 0;
+ INIT_MARKER (p, NULL, 0, 0, 0);
p->next = NULL;
- p->insertion_type = 0;
return val;
}
@@ -3683,10 +3680,7 @@
obj = allocate_misc (Lisp_Misc_Marker);
m = XMARKER (obj);
- m->buffer = buf;
- m->charpos = charpos;
- m->bytepos = bytepos;
- m->insertion_type = 0;
+ INIT_MARKER (m, buf, charpos, bytepos, 0);
m->next = BUF_MARKERS (buf);
BUF_MARKERS (buf) = m;
return obj;
=== modified file 'src/buffer.c'
--- src/buffer.c 2012-07-23 11:15:43 +0000
+++ src/buffer.c 2012-07-23 16:59:49 +0000
@@ -366,6 +366,7 @@
*(BUF_GPT_ADDR (b)) = *(BUF_Z_ADDR (b)) = 0; /* Put an anchor '\0'. */
b->text->inhibit_shrinking = 0;
+ b->excursions = NULL;
b->newline_cache = 0;
b->width_run_cache = 0;
BVAR (b, width_table) = Qnil;
@@ -586,6 +587,7 @@
b->begv_byte = b->base_buffer->begv_byte;
b->zv_byte = b->base_buffer->zv_byte;
+ b->excursions = NULL;
b->newline_cache = 0;
b->width_run_cache = 0;
BVAR (b, width_table) = Qnil;
@@ -4875,8 +4877,113 @@
UNBLOCK_INPUT;
}
-
-\f
+#if 1 /* NEW */
+
+/* Save current buffer state before entering Fsave_excursion. */
+
+Lisp_Object
+save_excursion_save (void)
+{
+ Lisp_Object buf;
+ struct excursion *ex;
+ struct window *w = XWINDOW (selected_window);
+ struct Lisp_Marker *m = XMARKER (BVAR (current_buffer, mark));
+
+ ex = xmalloc (sizeof *ex);
+ ex->window = w;
+ ex->visible = (XBUFFER (w->buffer) == current_buffer);
+ ex->active = !NILP (BVAR (current_buffer, mark_active));
+
+ /* We do not initialize type and gcmarkbit since this marker
+ is never referenced via Lisp_Object and invisible for GC. */
+ INIT_MARKER (&ex->point, current_buffer, PT, PT_BYTE, 0);
+ ex->point.type = Lisp_Misc_Marker;
+ ex->point.next = BUF_MARKERS (current_buffer);
+ BUF_MARKERS (current_buffer) = &ex->point;
+
+ /* Likewise. */
+ INIT_MARKER (&ex->mark, current_buffer, m->charpos,
+ m->bytepos, m->insertion_type);
+ ex->mark.type = Lisp_Misc_Marker;
+ ex->mark.next = BUF_MARKERS (current_buffer);
+ BUF_MARKERS (current_buffer) = &ex->mark;
+
+ ex->next = current_buffer->excursions;
+ current_buffer->excursions = ex;
+ XSETBUFFER (buf, current_buffer);
+ return buf;
+}
+
+/* Restore BUFFER's values before leaving Fsave_excursion. */
+
+Lisp_Object
+save_excursion_restore (Lisp_Object buffer)
+{
+ int active;
+ struct buffer *buf;
+ struct excursion *ex;
+ struct Lisp_Marker *m;
+ ptrdiff_t oldmark, newmark;
+
+ CHECK_BUFFER (buffer);
+ buf = XBUFFER (buffer);
+ eassert (!NILP (BVAR (buf, name)));
+ ex = buf->excursions;
+ eassert (ex != NULL);
+
+ /* Restore current buffer. */
+ set_buffer_internal (buf);
+
+ /* Restore buffer position. */
+ if (ex->point.charpos < BEGV)
+ SET_PT_BOTH (BEGV, BEGV_BYTE);
+ else if (ex->point.charpos > ZV)
+ SET_PT_BOTH (ZV, ZV_BYTE);
+ else
+ SET_PT_BOTH (ex->point.charpos, ex->point.bytepos);
+ unchain_marker (&ex->point);
+
+ /* Restore mark. */
+ m = XMARKER (BVAR (buf, mark));
+ oldmark = m->charpos;
+ if (BEGV <= ex->mark.charpos)
+ attach_marker (m, buf, ex->mark.charpos, ex->mark.bytepos);
+ newmark = ex->mark.charpos;
+ unchain_marker (&ex->mark);
+
+ /* If mark and region was active, restore them. */
+ active = !NILP (BVAR (buf, mark_active));
+ BVAR (buf, mark_active) = ex->active ? Qt : Qnil;
+
+ /* If mark is active now, and either was not active
+ or was at a different place, run the activate hook. */
+ if (ex->active && oldmark != newmark)
+ {
+ Lisp_Object tem = intern ("activate-mark-hook");
+ Frun_hooks (1, &tem);
+ }
+ /* If mark has ceased to be active, run deactivate hook. */
+ else if (active)
+ {
+ Lisp_Object tem = intern ("deactivate-mark-hook");
+ Frun_hooks (1, &tem);
+ }
+
+ /* If buffer was visible in a window, and a different window
+ was selected, and the old selected window is still showing
+ this buffer, restore point in that window. */
+ if (ex->visible
+ && ex->window != XWINDOW (selected_window)
+ && EQ (ex->window->buffer, buffer))
+ set_marker_restricted (ex->window->pointm, make_number (PT), buffer);
+
+ buf->excursions = ex->next;
+ xfree (ex);
+ return Qnil;
+}
+
+#endif /* NEW */
+
/***********************************************************************
Initialization
***********************************************************************/
=== modified file 'src/buffer.h'
--- src/buffer.h 2012-07-22 03:44:35 +0000
+++ src/buffer.h 2012-07-23 16:45:26 +0000
@@ -472,6 +472,18 @@
int inhibit_shrinking;
};
+/* Used to record buffer state for save_excursion. */
+
+struct excursion
+{
+ struct window *window;
+ unsigned visible : 1;
+ unsigned active : 1;
+ struct Lisp_Marker point;
+ struct Lisp_Marker mark;
+ struct excursion *next;
+};
+
/* Lisp fields in struct buffer are hidden from most code and accessed
via the BVAR macro, below. Only select pieces of code, like the GC,
are allowed to use BUFFER_INTERNAL_FIELD. */
@@ -856,6 +868,9 @@
/* Position where the overlay lists are centered. */
ptrdiff_t overlay_center;
+ /* List of recorded excursions. */
+ struct excursion *excursions;
+
/* Changes in the buffer are recorded here for undo, and t means
don't record anything. This information belongs to the base
buffer of an indirect buffer. But we can't store it in the
@@ -925,6 +940,8 @@
extern void set_buffer_temp (struct buffer *);
extern Lisp_Object buffer_local_value_1 (Lisp_Object, Lisp_Object);
extern void record_buffer (Lisp_Object);
+extern Lisp_Object save_excursion_save (void);
+extern Lisp_Object save_excursion_restore (Lisp_Object);
extern _Noreturn void buffer_slot_type_mismatch (Lisp_Object, int);
extern void fix_overlays_before (struct buffer *, ptrdiff_t, ptrdiff_t);
extern void mmap_set_vars (int);
=== modified file 'src/editfns.c'
--- src/editfns.c 2012-07-17 07:43:01 +0000
+++ src/editfns.c 2012-07-23 16:59:27 +0000
@@ -821,7 +821,8 @@
Qnil, Qt, Qnil);
}
-\f
+#if 0 /* OLD */
+
Lisp_Object
save_excursion_save (void)
{
@@ -922,6 +923,8 @@
return Qnil;
}
+#endif /* OLD */
+
DEFUN ("save-excursion", Fsave_excursion, Ssave_excursion, 0, UNEVALLED, 0,
doc: /* Save point, mark, and current buffer; execute BODY; restore those things.
Executes BODY just like `progn'.
=== modified file 'src/lisp.h'
--- src/lisp.h 2012-07-23 11:15:43 +0000
+++ src/lisp.h 2012-07-23 16:44:46 +0000
@@ -1283,6 +1283,12 @@
ptrdiff_t bytepos;
};
+/* Used to setup base fields of Lisp_Marker. */
+
+#define INIT_MARKER(mark, buf, cpos, bpos, itype) \
+ ((mark)->buffer = (buf), (mark)->charpos = (cpos), \
+ (mark)->bytepos = (bpos), (mark)->insertion_type = (itype), 1)
+
/* START and END are markers in the overlay's buffer, and
PLIST is the overlay's property list. */
struct Lisp_Overlay
@@ -2825,9 +2831,7 @@
extern Lisp_Object Qfield;
extern void insert1 (Lisp_Object);
extern Lisp_Object format2 (const char *, Lisp_Object, Lisp_Object);
-extern Lisp_Object save_excursion_save (void);
extern Lisp_Object save_restriction_save (void);
-extern Lisp_Object save_excursion_restore (Lisp_Object);
extern Lisp_Object save_restriction_restore (Lisp_Object);
extern _Noreturn void time_overflow (void);
extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, int);
@@ -2869,8 +2873,10 @@
extern Lisp_Object set_marker_restricted (Lisp_Object, Lisp_Object, Lisp_Object);
extern Lisp_Object set_marker_both (Lisp_Object, Lisp_Object, ptrdiff_t, ptrdiff_t);
extern Lisp_Object set_marker_restricted_both (Lisp_Object, Lisp_Object,
- ptrdiff_t, ptrdiff_t);
+ ptrdiff_t, ptrdiff_t);
extern Lisp_Object build_marker (struct buffer *, ptrdiff_t, ptrdiff_t);
+extern void attach_marker (struct Lisp_Marker *, struct buffer *,
+ ptrdiff_t, ptrdiff_t);
extern void syms_of_marker (void);
/* Defined in fileio.c */
=== modified file 'src/marker.c'
--- src/marker.c 2012-07-22 05:37:24 +0000
+++ src/marker.c 2012-07-23 16:31:21 +0000
@@ -427,7 +427,7 @@
/* Change M so it points to B at CHARPOS and BYTEPOS. */
-static inline void
+void
attach_marker (struct Lisp_Marker *m, struct buffer *b,
ptrdiff_t charpos, ptrdiff_t bytepos)
{
next reply other threads:[~2012-07-23 17:07 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-23 17:07 Dmitry Antipov [this message]
2012-07-23 23:45 ` [RFC, experimental] save_{excursion,restriction} Stefan Monnier
2012-07-24 5:16 ` Dmitry Antipov
2012-07-24 9:37 ` Stefan Monnier
2012-07-24 11:28 ` Dmitry Antipov
2012-07-24 22:05 ` Stefan Monnier
2012-07-25 9:38 ` Dmitry Antipov
2012-07-25 23:44 ` Stefan Monnier
2012-07-26 5:14 ` Dmitry Antipov
2012-07-26 23:24 ` Stefan Monnier
2012-07-24 6:31 ` Ivan Andrus
2012-07-24 9:14 ` Stefan Monnier
2012-07-27 3:51 ` Chong Yidong
2012-07-27 8:00 ` Dmitry Antipov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=500D84B6.50303@yandex.ru \
--to=dmantipov@yandex.ru \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).