From aca938d1f4ec176a2d00a77693b231298b9c5c4e Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 14 Jun 2018 15:59:09 -0700 Subject: [PATCH] Avoid allocating Lisp_Save_Value for excursions * src/editfns.c (save_excursion_save): New arg PDL, specifying where to save the state. All uses changed. (save_excursion_restore): Args are now the marker and info rather than a pointer to a Lisp_Save_Value containing them. All uses changed. * src/eval.c (default_toplevel_binding, Fbacktrace__locals): Treat excursions like other miscellaneous pdl types. (record_unwind_protect_excursion): Save data directly into the pdl rather than creating an object on the heap. This avoids the need to allocate and free an object. (do_one_unbind, backtrace_eval_unrewind): Unwind excursions directly. (mark_specpdl): Mark excursions directly. * src/lisp.h (SPECPDL_UNWIND_EXCURSION): New constant. (union specbinding): New member unwind_excursion. --- src/editfns.c | 27 +++++++++++---------------- src/eval.c | 38 +++++++++++++++++++++++++++----------- src/lisp.h | 9 +++++++-- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/editfns.c b/src/editfns.c index e672c0eb74d..3147f9d1466 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -995,30 +995,24 @@ This function does not move point. */) Qnil, Qt, Qnil); } -/* Save current buffer state for `save-excursion' special form. - We (ab)use Lisp_Misc_Save_Value to allow explicit free and so - offload some work from GC. */ +/* Save current buffer state for save-excursion special form. */ -Lisp_Object -save_excursion_save (void) +void +save_excursion_save (union specbinding *pdl) { - return make_save_obj_obj_obj_obj - (Fpoint_marker (), - Qnil, - /* Selected window if current buffer is shown in it, nil otherwise. */ - (EQ (XWINDOW (selected_window)->contents, Fcurrent_buffer ()) - ? selected_window : Qnil), - Qnil); + eassert (pdl->unwind_excursion.kind == SPECPDL_UNWIND_EXCURSION); + pdl->unwind_excursion.marker = Fpoint_marker (); + /* Selected window if current buffer is shown in it, nil otherwise. */ + pdl->unwind_excursion.window + = (EQ (XWINDOW (selected_window)->contents, Fcurrent_buffer ()) + ? selected_window : Qnil); } /* Restore saved buffer before leaving `save-excursion' special form. */ void -save_excursion_restore (Lisp_Object info) +save_excursion_restore (Lisp_Object marker, Lisp_Object window) { - Lisp_Object marker = XSAVE_OBJECT (info, 0); - Lisp_Object window = XSAVE_OBJECT (info, 2); - free_misc (info); Lisp_Object buffer = Fmarker_buffer (marker); /* If we're unwinding to top level, saved buffer may be deleted. This means that all of its markers are unchained and so BUFFER is nil. */ @@ -1027,6 +1021,7 @@ save_excursion_restore (Lisp_Object info) Fset_buffer (buffer); + /* Point marker. */ Fgoto_char (marker); unchain_marker (XMARKER (marker)); diff --git a/src/eval.c b/src/eval.c index 5c7cb3196a6..dded16bed55 100644 --- a/src/eval.c +++ b/src/eval.c @@ -675,6 +675,7 @@ default_toplevel_binding (Lisp_Object symbol) case SPECPDL_UNWIND: case SPECPDL_UNWIND_PTR: case SPECPDL_UNWIND_INT: + case SPECPDL_UNWIND_EXCURSION: case SPECPDL_UNWIND_VOID: case SPECPDL_BACKTRACE: case SPECPDL_LET_LOCAL: @@ -3427,7 +3428,9 @@ record_unwind_protect_int (void (*function) (int), int arg) void record_unwind_protect_excursion (void) { - record_unwind_protect (save_excursion_restore, save_excursion_save ()); + specpdl_ptr->unwind_excursion.kind = SPECPDL_UNWIND_EXCURSION; + save_excursion_save (specpdl_ptr); + grow_specpdl (); } void @@ -3475,6 +3478,10 @@ do_one_unbind (union specbinding *this_binding, bool unwinding, case SPECPDL_UNWIND_VOID: this_binding->unwind_void.func (); break; + case SPECPDL_UNWIND_EXCURSION: + save_excursion_restore (this_binding->unwind_excursion.marker, + this_binding->unwind_excursion.window); + break; case SPECPDL_BACKTRACE: break; case SPECPDL_LET: @@ -3749,18 +3756,21 @@ backtrace_eval_unrewind (int distance) unwind_protect, but the problem is that we don't know how to rewind them afterwards. */ case SPECPDL_UNWIND: - { - Lisp_Object oldarg = tmp->unwind.arg; - if (tmp->unwind.func == set_buffer_if_live) + if (tmp->unwind.func == set_buffer_if_live) + { + Lisp_Object oldarg = tmp->unwind.arg; tmp->unwind.arg = Fcurrent_buffer (); - else if (tmp->unwind.func == save_excursion_restore) - tmp->unwind.arg = save_excursion_save (); - else - break; - tmp->unwind.func (oldarg); - break; + set_buffer_if_live (oldarg); + } + break; + case SPECPDL_UNWIND_EXCURSION: + { + Lisp_Object marker = tmp->unwind_excursion.marker; + Lisp_Object window = tmp->unwind_excursion.window; + save_excursion_save (tmp); + save_excursion_restore (marker, window); } - + break; case SPECPDL_UNWIND_PTR: case SPECPDL_UNWIND_INT: case SPECPDL_UNWIND_VOID: @@ -3895,6 +3905,7 @@ NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'. case SPECPDL_UNWIND: case SPECPDL_UNWIND_PTR: case SPECPDL_UNWIND_INT: + case SPECPDL_UNWIND_EXCURSION: case SPECPDL_UNWIND_VOID: case SPECPDL_BACKTRACE: break; @@ -3924,6 +3935,11 @@ mark_specpdl (union specbinding *first, union specbinding *ptr) mark_object (specpdl_arg (pdl)); break; + case SPECPDL_UNWIND_EXCURSION: + mark_object (pdl->unwind_excursion.marker); + mark_object (pdl->unwind_excursion.window); + break; + case SPECPDL_BACKTRACE: { ptrdiff_t nargs = backtrace_nargs (pdl); diff --git a/src/lisp.h b/src/lisp.h index b7e5d9e3761..af3f587222d 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3188,6 +3188,7 @@ enum specbind_tag { SPECPDL_UNWIND, /* An unwind_protect function on Lisp_Object. */ SPECPDL_UNWIND_PTR, /* Likewise, on void *. */ SPECPDL_UNWIND_INT, /* Likewise, on int. */ + SPECPDL_UNWIND_EXCURSION, /* Likewise, on an execursion. */ SPECPDL_UNWIND_VOID, /* Likewise, with no arg. */ SPECPDL_BACKTRACE, /* An element of the backtrace. */ SPECPDL_LET, /* A plain and simple dynamic let-binding. */ @@ -3214,6 +3215,10 @@ union specbinding void (*func) (int); int arg; } unwind_int; + struct { + ENUM_BF (specbind_tag) kind : CHAR_BIT; + Lisp_Object marker, window; + } unwind_excursion; struct { ENUM_BF (specbind_tag) kind : CHAR_BIT; void (*func) (void); @@ -4106,9 +4111,9 @@ extern void mark_threads (void); /* Defined in editfns.c. */ extern void insert1 (Lisp_Object); -extern Lisp_Object save_excursion_save (void); +extern void save_excursion_save (union specbinding *); +extern void save_excursion_restore (Lisp_Object, Lisp_Object); extern Lisp_Object save_restriction_save (void); -extern void save_excursion_restore (Lisp_Object); extern void save_restriction_restore (Lisp_Object); extern _Noreturn void time_overflow (void); extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, bool); -- 2.39.2