use libguile dynamic wind + c pseudo-closures
authorBT Templeton <bt@hcoop.net>
Fri, 19 Jul 2013 20:57:48 +0000 (16:57 -0400)
committerRobin Templeton <robin@terpri.org>
Sat, 18 Apr 2015 22:49:12 +0000 (18:49 -0400)
* src/eval.c (specpdl_arg): Remove.
  (set_catchlist, set_handlerlist, restore_catchtag): New functions.
  (internal_catch, internal_lisp_condition_case)
  (internal_condition_case, internal_condition_case_1)
  (internal_condition_case_2, internal_condition_case_n): Use
  `call_with_prompt'.
  (unwind_to_catch): Use `abort_to_prompt'.
  (set_lisp_eval_depth): New function.

  (record_in_backtrace): Set an unwind handler to remove the backtrace
  entry.

  (eval_sub, Ffuncall, specbind, record_unwind_protect_ptr_1): Use
  Guile unwind handlers.

  (call_void): New function.

  (record_unwind_protect_1, record_unwind_protect_int_1)
  (record_unwind_protect_void_1): Use `record_unwind_protect_ptr_1'.

  (unbind_once): Now static. Remove support for `SPECPDL_UNWIND',
  `SPECPDL_UNWIND_PTR', `SPECPDL_UNWIND_INT' and `SPECPDL_UNWIND_VOID'
  specpdl entries.

  (dynwind_begin): Use `scm_dynwind_begin'.
  (dynwind_end): Use `scm_dynwind_end'.

  (unbind_to_1, unbind_to): Remove.

  (backtrace_eval_unrewind): Remove support for `SPECPDL_UNWIND',
  `SPECPDL_UNWIND_PTR', `SPECPDL_UNWIND_INT' and `SPECPDL_UNWIND_VOID'
  specpdl entries.

  (abort_to_prompt, call_with_prompt, make_prompt_tag): New functions.

  (struct handler, struct catchtag): Moved from "lisp.h".

  src/keyboard.c (save_getcjmp, restore_getcjmp): Remove.

  (read_event_from_main_queue, read_decoded_event_from_main_queue)
  (read_char, read_char_1, quit_throw_to_read_char): Use delimited
  continuations instead of `setjmp' and `longjmp'.

* src/lisp.h (SPECPDL_FRAME, SPECPDL_UNWIND, SPECPDL_UNWIND_PTR)
  (SPECPDL_UNWIND_INT, SPECPDL_UNWIND_VOID): Remove. All references
  changed.

  (struct handler, struct catchtag): Move to "eval.c".

--------------------------------------------------

* src/emacs.c (main2): Call `init_guile'.

* src/eval.c (icc_thunk, icc_handler, icc_handler_n)
  (icc_lisp_handler): New functions.

  (internal_catch, internal_lisp_condition_case)
  (internal_condition_case, internal_condition_case_1)
  (internal_condition_case_2, internal_condition_case_n): Use
  `make_c_closure' and the above functions.

* src/guile.c: New file.
  (make_c_closure, apply_c_closure, init_guile): New functions.

* src/keyboard.c (read_char_thunk, read_char_handle_quit): New
  functions.
  (read_char): Use `make_c_closure' and the above functions.

src/Makefile.in
src/emacs.c
src/eval.c
src/guile.c [new file with mode: 0644]
src/guile.h [new file with mode: 0644]
src/keyboard.c
src/lisp.h

index b48f9d3..a572bbd 100644 (file)
@@ -366,6 +366,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
        region-cache.o sound.o atimer.o \
        doprnt.o intervals.o textprop.o composite.o xml.o $(NOTIFY_OBJ) \
        profiler.o decompress.o \
+       guile.o \
        $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \
        $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ)
 obj = $(base_obj) $(NS_OBJC_OBJ)
index bef3266..e29358d 100644 (file)
@@ -1159,6 +1159,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
   if (!initialized)
     {
       init_alloc_once ();
+      init_guile ();
       init_fns_once ();
       init_obarray ();
       init_eval_once ();
index d9434a9..d56a8ef 100644 (file)
@@ -27,6 +27,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "commands.h"
 #include "keyboard.h"
 #include "dispextern.h"
+#include "guile.h"
+
+static void unbind_once (void *ignore);
 
 /* Chain of condition and catch handlers currently in effect.  */
 
@@ -136,13 +139,6 @@ specpdl_where (union specbinding *pdl)
   return pdl->let.where;
 }
 
-static Lisp_Object
-specpdl_arg (union specbinding *pdl)
-{
-  eassert (pdl->kind == SPECPDL_UNWIND);
-  return pdl->unwind.arg;
-}
-
 Lisp_Object
 backtrace_function (union specbinding *pdl)
 {
@@ -218,6 +214,39 @@ backtrace_next (union specbinding *pdl)
   return pdl;
 }
 
+struct handler *
+make_catch_handler (Lisp_Object tag)
+{
+  struct handler *c = xmalloc (sizeof (*c));
+  c->type = CATCHER;
+  c->tag_or_ch = tag;
+  c->val = Qnil;
+  c->var = Qnil;
+  c->body = Qnil;
+  c->next = handlerlist;
+  c->lisp_eval_depth = lisp_eval_depth;
+  c->poll_suppress_count = poll_suppress_count;
+  c->interrupt_input_blocked = interrupt_input_blocked;
+  c->ptag = make_prompt_tag ();
+  return c;
+}
+
+struct handler *
+make_condition_handler (Lisp_Object tag)
+{
+  struct handler *c = xmalloc (sizeof (*c));
+  c->type = CONDITION_CASE;
+  c->tag_or_ch = tag;
+  c->val = Qnil;
+  c->var = Qnil;
+  c->body = Qnil;
+  c->next = handlerlist;
+  c->lisp_eval_depth = lisp_eval_depth;
+  c->poll_suppress_count = poll_suppress_count;
+  c->interrupt_input_blocked = interrupt_input_blocked;
+  c->ptag = make_prompt_tag ();
+  return c;
+}
 
 void
 init_eval_once (void)
@@ -233,22 +262,14 @@ init_eval_once (void)
   Vrun_hooks = Qnil;
 }
 
-static struct handler handlerlist_sentinel;
+static struct handler *handlerlist_sentinel;
 
 void
 init_eval (void)
 {
   specpdl_ptr = specpdl;
-  { /* Put a dummy catcher at top-level so that handlerlist is never NULL.
-       This is important since handlerlist->nextfree holds the freelist
-       which would otherwise leak every time we unwind back to top-level.   */
-    struct handler *c;
-    handlerlist = handlerlist_sentinel.nextfree = &handlerlist_sentinel;
-    PUSH_HANDLER (c, Qunbound, CATCHER);
-    eassert (c == &handlerlist_sentinel);
-    handlerlist_sentinel.nextfree = NULL;
-    handlerlist_sentinel.next = NULL;
-  }
+  handlerlist_sentinel = make_catch_handler (Qunbound);
+  handlerlist = handlerlist_sentinel;
   Vquit_flag = Qnil;
   debug_on_next_call = 0;
   lisp_eval_depth = 0;
@@ -280,23 +301,11 @@ call_debugger (Lisp_Object arg)
   Lisp_Object val;
   EMACS_INT old_depth = max_lisp_eval_depth;
   /* Do not allow max_specpdl_size less than actual depth (Bug#16603).  */
-  EMACS_INT old_max = max (max_specpdl_size, count);
+  EMACS_INT old_max = max_specpdl_size;
 
   if (lisp_eval_depth + 40 > max_lisp_eval_depth)
     max_lisp_eval_depth = lisp_eval_depth + 40;
 
-  /* While debugging Bug#16603, previous value of 100 was found
-     too small to avoid specpdl overflow in the debugger itself.  */
-  if (max_specpdl_size - 200 < count)
-    max_specpdl_size = count + 200;
-
-  if (old_max == count)
-    {
-      /* We can enter the debugger due to specpdl overflow (Bug#16603).  */
-      specpdl_ptr--;
-      grow_specpdl ();
-    }
-
   /* Restore limits after leaving the debugger.  */
   record_unwind_protect (restore_stack_limits,
                         Fcons (make_number (old_max),
@@ -1097,6 +1106,126 @@ usage: (catch TAG BODY...)  */)
 
 #define clobbered_eassert(E) ((void) 0)
 
+static void
+set_handlerlist (void *data)
+{
+  handlerlist = data;
+}
+
+static void
+restore_handler (void *data)
+{
+  struct handler *c = data;
+  set_poll_suppress_count (c->poll_suppress_count);
+  unblock_input_to (c->interrupt_input_blocked);
+  immediate_quit = 0;
+}
+
+struct icc_thunk_env
+{
+  enum { ICC_0, ICC_1, ICC_2, ICC_3, ICC_N } type;
+  union
+  {
+    Lisp_Object (*fun0) (void);
+    Lisp_Object (*fun1) (Lisp_Object);
+    Lisp_Object (*fun2) (Lisp_Object, Lisp_Object);
+    Lisp_Object (*fun3) (Lisp_Object, Lisp_Object, Lisp_Object);
+    Lisp_Object (*funn) (ptrdiff_t, Lisp_Object *);
+  };
+  union
+  {
+    struct
+    {
+      Lisp_Object arg1;
+      Lisp_Object arg2;
+      Lisp_Object arg3;
+    };
+    struct
+    {
+      ptrdiff_t nargs;
+      Lisp_Object *args;
+    };
+  };
+  struct handler *c;
+};
+
+static Lisp_Object
+icc_thunk (void *data)
+{
+  Lisp_Object tem;
+  struct icc_thunk_env *e = data;
+  scm_dynwind_begin (0);
+  scm_dynwind_unwind_handler (restore_handler, e->c, 0);
+  scm_dynwind_unwind_handler (set_handlerlist,
+                              handlerlist,
+                              SCM_F_WIND_EXPLICITLY);
+  handlerlist = e->c;
+  switch (e->type)
+    {
+    case ICC_0:
+      tem = e->fun0 ();
+      break;
+    case ICC_1:
+      tem = e->fun1 (e->arg1);
+      break;
+    case ICC_2:
+      tem = e->fun2 (e->arg1, e->arg2);
+      break;
+    case ICC_3:
+      tem = e->fun3 (e->arg1, e->arg2, e->arg3);
+      break;
+    case ICC_N:
+      tem = e->funn (e->nargs, e->args);
+      break;
+    default:
+      emacs_abort ();
+    }
+  scm_dynwind_end ();
+  return tem;
+}
+
+static Lisp_Object
+icc_handler (void *data, Lisp_Object k, Lisp_Object v)
+{
+  Lisp_Object (*f) (Lisp_Object) = data;
+  return f (v);
+}
+
+struct icc_handler_n_env
+{
+  Lisp_Object (*fun) (Lisp_Object, ptrdiff_t, Lisp_Object *);
+  ptrdiff_t nargs;
+  Lisp_Object *args;
+};
+
+static Lisp_Object
+icc_handler_n (void *data, Lisp_Object k, Lisp_Object v)
+{
+  struct icc_handler_n_env *e = data;
+  return e->fun (v, e->nargs, e->args);
+}
+
+static Lisp_Object
+icc_lisp_handler (void *data, Lisp_Object k, Lisp_Object val)
+{
+  Lisp_Object tem;
+  struct handler *h = data;
+  Lisp_Object var = h->var;
+  scm_dynwind_begin (0);
+  if (!NILP (var))
+    {
+      if (!NILP (Vinternal_interpreter_environment))
+        specbind (Qinternal_interpreter_environment,
+                  Fcons (Fcons (var, val),
+                         Vinternal_interpreter_environment));
+      else
+        specbind (var, val);
+    }
+  tem = Fprogn (h->body);
+  scm_dynwind_end ();
+  return tem;
+}
+
 /* Set up a catch, then call C function FUNC on argument ARG.
    FUNC should return a Lisp_Object.
    This is how catches are done from within C code.  */
@@ -1104,27 +1233,14 @@ usage: (catch TAG BODY...)  */)
 Lisp_Object
 internal_catch (Lisp_Object tag, Lisp_Object (*func) (Lisp_Object), Lisp_Object arg)
 {
-  /* This structure is made part of the chain `catchlist'.  */
-  struct handler *c;
-
-  /* Fill in the components of c, and put it on the list.  */
-  PUSH_HANDLER (c, tag, CATCHER);
-
-  /* Call FUNC.  */
-  if (! sys_setjmp (c->jmp))
-    {
-      Lisp_Object val = (*func) (arg);
-      clobbered_eassert (handlerlist == c);
-      handlerlist = handlerlist->next;
-      return val;
-    }
-  else
-    { /* Throw works by a longjmp that comes right here.  */
-      Lisp_Object val = handlerlist->val;
-      clobbered_eassert (handlerlist == c);
-      handlerlist = handlerlist->next;
-      return val;
-    }
+  struct handler *c = make_catch_handler (tag);
+  struct icc_thunk_env env = { .type = ICC_1,
+                               .fun1 = func,
+                               .arg1 = arg,
+                               .c = c };
+  return call_with_prompt (c->ptag,
+                           make_c_closure (icc_thunk, &env, 0, 0),
+                           make_c_closure (icc_handler, Fidentity, 2, 0));
 }
 
 /* Unwind the specbind, catch, and handler stacks back to CATCH, and
@@ -1148,38 +1264,7 @@ static Lisp_Object unbind_to_1 (ptrdiff_t, Lisp_Object, bool);
 static _Noreturn void
 unwind_to_catch (struct handler *catch, Lisp_Object value)
 {
-  bool last_time;
-
-  eassert (catch->next);
-
-  /* Save the value in the tag.  */
-  catch->val = value;
-
-  /* Restore certain special C variables.  */
-  set_poll_suppress_count (catch->poll_suppress_count);
-  unblock_input_to (catch->interrupt_input_blocked);
-  immediate_quit = 0;
-
-  do
-    {
-      /* Unwind the specpdl stack, and then restore the proper set of
-        handlers.  */
-      unbind_to_1 (handlerlist->pdlcount, Qnil, false);
-      last_time = handlerlist == catch;
-      if (! last_time)
-       handlerlist = handlerlist->next;
-    }
-  while (! last_time);
-
-  eassert (handlerlist == catch);
-
-  gcprolist = catch->gcpro;
-#ifdef DEBUG_GCPRO
-  gcpro_level = gcprolist ? gcprolist->level + 1 : 0;
-#endif
-  lisp_eval_depth = catch->lisp_eval_depth;
-
-  sys_longjmp (catch->jmp, 1);
+  abort_to_prompt (catch->ptag, scm_list_1 (value));
 }
 
 DEFUN ("throw", Fthrow, Sthrow, 2, 2, 0,
@@ -1251,6 +1336,35 @@ usage: (condition-case VAR BODYFORM &rest HANDLERS)  */)
   return internal_lisp_condition_case (var, bodyform, handlers);
 }
 
+static Lisp_Object
+ilcc1 (Lisp_Object var, Lisp_Object bodyform, Lisp_Object handlers)
+{
+  if (CONSP (handlers))
+    {
+      Lisp_Object clause = XCAR (handlers);
+      Lisp_Object condition = XCAR (clause);
+      Lisp_Object body = XCDR (clause);
+      if (!CONSP (condition))
+        condition = Fcons (condition, Qnil);
+      struct handler *c = make_condition_handler (condition);
+      c->var = var;
+      c->body = body;
+      struct icc_thunk_env env = { .type = ICC_3,
+                                   .fun3 = ilcc1,
+                                   .arg1 = var,
+                                   .arg2 = bodyform,
+                                   .arg3 = XCDR (handlers),
+                                   .c = c };
+      return call_with_prompt (c->ptag,
+                               make_c_closure (icc_thunk, &env, 0, 0),
+                               make_c_closure (icc_lisp_handler, c, 2, 0));
+    }
+  else
+    {
+      return eval_sub (bodyform);
+    }
+}
+
 /* Like Fcondition_case, but the args are separate
    rather than passed in a list.  Used by Fbyte_code.  */
 
@@ -1261,14 +1375,12 @@ internal_lisp_condition_case (volatile Lisp_Object var, Lisp_Object bodyform,
   Lisp_Object val;
   struct handler *c;
   struct handler *oldhandlerlist = handlerlist;
-  int clausenb = 0;
 
   CHECK_SYMBOL (var);
 
   for (val = handlers; CONSP (val); val = XCDR (val))
     {
       Lisp_Object tem = XCAR (val);
-      clausenb++;
       if (! (NILP (tem)
             || (CONSP (tem)
                 && (SYMBOLP (XCAR (tem))
@@ -1277,52 +1389,7 @@ internal_lisp_condition_case (volatile Lisp_Object var, Lisp_Object bodyform,
               SDATA (Fprin1_to_string (tem, Qt)));
     }
 
-  { /* The first clause is the one that should be checked first, so it should
-       be added to handlerlist last.  So we build in `clauses' a table that
-       contains `handlers' but in reverse order.  */
-    Lisp_Object *clauses = alloca (clausenb * sizeof (Lisp_Object *));
-    Lisp_Object *volatile clauses_volatile = clauses;
-    int i = clausenb;
-    for (val = handlers; CONSP (val); val = XCDR (val))
-      clauses[--i] = XCAR (val);
-    for (i = 0; i < clausenb; i++)
-      {
-       Lisp_Object clause = clauses[i];
-       Lisp_Object condition = XCAR (clause);
-       if (!CONSP (condition))
-         condition = Fcons (condition, Qnil);
-       PUSH_HANDLER (c, condition, CONDITION_CASE);
-       if (sys_setjmp (c->jmp))
-         {
-           ptrdiff_t count = SPECPDL_INDEX ();
-           Lisp_Object val = handlerlist->val;
-           Lisp_Object *chosen_clause = clauses_volatile;
-           for (c = handlerlist->next; c != oldhandlerlist; c = c->next)
-             chosen_clause++;
-           handlerlist = oldhandlerlist;
-           if (!NILP (var))
-             {
-               if (!NILP (Vinternal_interpreter_environment))
-                 specbind (Qinternal_interpreter_environment,
-                           Fcons (Fcons (var, val),
-                                  Vinternal_interpreter_environment));
-               else
-                 specbind (var, val);
-             }
-           val = Fprogn (XCDR (*chosen_clause));
-           /* Note that this just undoes the binding of var; whoever
-              longjumped to us unwound the stack to c.pdlcount before
-              throwing.  */
-           if (!NILP (var))
-             unbind_to (count, Qnil);
-           return val;
-         }
-      }
-    }
-
-  val = eval_sub (bodyform);
-  handlerlist = oldhandlerlist;
-  return val;
+  return ilcc1 (var, bodyform, Freverse (handlers));
 }
 
 /* Call the function BFUN with no arguments, catching errors within it
@@ -1340,21 +1407,12 @@ internal_condition_case (Lisp_Object (*bfun) (void), Lisp_Object handlers,
                         Lisp_Object (*hfun) (Lisp_Object))
 {
   Lisp_Object val;
-  struct handler *c;
+  struct handler *c = make_condition_handler (handlers);
 
-  PUSH_HANDLER (c, handlers, CONDITION_CASE);
-  if (sys_setjmp (c->jmp))
-    {
-      Lisp_Object val = handlerlist->val;
-      clobbered_eassert (handlerlist == c);
-      handlerlist = handlerlist->next;
-      return (*hfun) (val);
-    }
-
-  val = (*bfun) ();
-  clobbered_eassert (handlerlist == c);
-  handlerlist = handlerlist->next;
-  return val;
+  struct icc_thunk_env env = { .type = ICC_0, .fun0 = bfun, .c = c };
+  return call_with_prompt (c->ptag,
+                           make_c_closure (icc_thunk, &env, 0, 0),
+                           make_c_closure (icc_handler, hfun, 2, 0));
 }
 
 /* Like internal_condition_case but call BFUN with ARG as its argument.  */
@@ -1364,21 +1422,15 @@ internal_condition_case_1 (Lisp_Object (*bfun) (Lisp_Object), Lisp_Object arg,
                           Lisp_Object handlers, Lisp_Object (*hfun) (Lisp_Object))
 {
   Lisp_Object val;
-  struct handler *c;
+  struct handler *c = make_condition_handler (handlers);
 
-  PUSH_HANDLER (c, handlers, CONDITION_CASE);
-  if (sys_setjmp (c->jmp))
-    {
-      Lisp_Object val = handlerlist->val;
-      clobbered_eassert (handlerlist == c);
-      handlerlist = handlerlist->next;
-      return (*hfun) (val);
-    }
-
-  val = (*bfun) (arg);
-  clobbered_eassert (handlerlist == c);
-  handlerlist = handlerlist->next;
-  return val;
+  struct icc_thunk_env env = { .type = ICC_1,
+                               .fun1 = bfun,
+                               .arg1 = arg,
+                               .c = c };
+  return call_with_prompt (c->ptag,
+                           make_c_closure (icc_thunk, &env, 0, 0),
+                           make_c_closure (icc_handler, hfun, 2, 0));
 }
 
 /* Like internal_condition_case_1 but call BFUN with ARG1 and ARG2 as
@@ -1392,21 +1444,15 @@ internal_condition_case_2 (Lisp_Object (*bfun) (Lisp_Object, Lisp_Object),
                           Lisp_Object (*hfun) (Lisp_Object))
 {
   Lisp_Object val;
-  struct handler *c;
-
-  PUSH_HANDLER (c, handlers, CONDITION_CASE);
-  if (sys_setjmp (c->jmp))
-    {
-      Lisp_Object val = handlerlist->val;
-      clobbered_eassert (handlerlist == c);
-      handlerlist = handlerlist->next;
-      return (*hfun) (val);
-    }
-
-  val = (*bfun) (arg1, arg2);
-  clobbered_eassert (handlerlist == c);
-  handlerlist = handlerlist->next;
-  return val;
+  struct handler *c = make_condition_handler (handlers);
+  struct icc_thunk_env env = { .type = ICC_2,
+                               .fun2 = bfun,
+                               .arg1 = arg1,
+                               .arg2 = arg2,
+                               .c = c };
+  return call_with_prompt (c->ptag,
+                           make_c_closure (icc_thunk, &env, 0, 0),
+                           make_c_closure (icc_handler, hfun, 2, 0));
 }
 
 /* Like internal_condition_case but call BFUN with NARGS as first,
@@ -1422,21 +1468,17 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *),
                                                Lisp_Object *args))
 {
   Lisp_Object val;
-  struct handler *c;
+  struct handler *c = make_condition_handler (handlers);
 
-  PUSH_HANDLER (c, handlers, CONDITION_CASE);
-  if (sys_setjmp (c->jmp))
-    {
-      Lisp_Object val = handlerlist->val;
-      clobbered_eassert (handlerlist == c);
-      handlerlist = handlerlist->next;
-      return (*hfun) (val, nargs, args);
-    }
-
-  val = (*bfun) (nargs, args);
-  clobbered_eassert (handlerlist == c);
-  handlerlist = handlerlist->next;
-  return val;
+  struct icc_thunk_env env = { .type = ICC_N,
+                               .funn = bfun,
+                               .nargs = nargs,
+                               .args = args,
+                               .c = c };
+  struct icc_handler_n_env henv = { .fun = hfun, .nargs = nargs, .args = args };
+  return call_with_prompt (c->ptag,
+                           make_c_closure (icc_thunk, &env, 0, 0),
+                           make_c_closure (icc_handler_n, &henv, 2, 0));
 }
 
 \f
@@ -1564,7 +1606,7 @@ See also the function `condition-case'.  */)
     }
   else
     {
-      if (handlerlist != &handlerlist_sentinel)
+      if (handlerlist != handlerlist_sentinel)
        /* FIXME: This will come right back here if there's no `top-level'
           catcher.  A better solution would be to abort here, and instead
           add a catch-all condition handler so we never come here.  */
@@ -2048,6 +2090,14 @@ record_in_backtrace (Lisp_Object function, Lisp_Object *args, ptrdiff_t nargs)
   specpdl_ptr->bt.args = args;
   specpdl_ptr->bt.nargs = nargs;
   grow_specpdl ();
+  scm_dynwind_unwind_handler (unbind_once, NULL, SCM_F_WIND_EXPLICITLY);
+}
+
+static void
+set_lisp_eval_depth (void *data)
+{
+  EMACS_INT n = (EMACS_INT) data;
+  lisp_eval_depth = n;
 }
 
 /* Eval a sub-expression of the current expression (i.e. in the same
@@ -2083,6 +2133,11 @@ eval_sub (Lisp_Object form)
   maybe_gc ();
   UNGCPRO;
 
+  scm_dynwind_begin (0);
+  scm_dynwind_unwind_handler (set_lisp_eval_depth,
+                              (void *) lisp_eval_depth,
+                              SCM_F_WIND_EXPLICITLY);
+
   if (++lisp_eval_depth > max_lisp_eval_depth)
     {
       if (max_lisp_eval_depth < 100)
@@ -2259,10 +2314,9 @@ eval_sub (Lisp_Object form)
        xsignal1 (Qinvalid_function, original_fun);
     }
 
-  lisp_eval_depth--;
   if (backtrace_debug_on_exit (specpdl_ptr - 1))
     val = call_debugger (list2 (Qexit, val));
-  specpdl_ptr--;
+  scm_dynwind_end ();
 
   return val;
 }
@@ -2747,6 +2801,11 @@ usage: (funcall FUNCTION &rest ARGUMENTS)  */)
 
   QUIT;
 
+  scm_dynwind_begin (0);
+  scm_dynwind_unwind_handler (set_lisp_eval_depth,
+                              (void *) lisp_eval_depth,
+                              SCM_F_WIND_EXPLICITLY);
+
   if (++lisp_eval_depth > max_lisp_eval_depth)
     {
       if (max_lisp_eval_depth < 100)
@@ -2876,10 +2935,9 @@ usage: (funcall FUNCTION &rest ARGUMENTS)  */)
       else
        xsignal1 (Qinvalid_function, original_fun);
     }
-  lisp_eval_depth--;
   if (backtrace_debug_on_exit (specpdl_ptr - 1))
     val = call_debugger (list2 (Qexit, val));
-  specpdl_ptr--;
+  scm_dynwind_end ();
   return val;
 }
 \f
@@ -3175,7 +3233,7 @@ specbind (Lisp_Object symbol, Lisp_Object value)
                specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT;
                grow_specpdl ();
                Fset_default (symbol, value);
-               return;
+               goto done;
              }
          }
        else
@@ -3187,6 +3245,9 @@ specbind (Lisp_Object symbol, Lisp_Object value)
       }
     default: emacs_abort ();
     }
+
+ done:
+  scm_dynwind_unwind_handler (unbind_once, NULL, SCM_F_WIND_EXPLICITLY);
 }
 
 /* Push unwind-protect entries of various types.  */
@@ -3195,11 +3256,7 @@ void
 record_unwind_protect_1 (void (*function) (Lisp_Object), Lisp_Object arg,
                          bool wind_explicitly)
 {
-  specpdl_ptr->unwind.kind = SPECPDL_UNWIND;
-  specpdl_ptr->unwind.func = function;
-  specpdl_ptr->unwind.arg = arg;
-  specpdl_ptr->unwind.wind_explicitly = wind_explicitly;
-  grow_specpdl ();
+  record_unwind_protect_ptr_1 (function, arg, wind_explicitly);
 }
 
 void
@@ -3212,11 +3269,11 @@ void
 record_unwind_protect_ptr_1 (void (*function) (void *), void *arg,
                              bool wind_explicitly)
 {
-  specpdl_ptr->unwind_ptr.kind = SPECPDL_UNWIND_PTR;
-  specpdl_ptr->unwind_ptr.func = function;
-  specpdl_ptr->unwind_ptr.arg = arg;
-  specpdl_ptr->unwind_ptr.wind_explicitly = wind_explicitly;
-  grow_specpdl ();
+  scm_dynwind_unwind_handler (function,
+                              arg,
+                              (wind_explicitly
+                               ? SCM_F_WIND_EXPLICITLY
+                               : 0));
 }
 
 void
@@ -3229,11 +3286,7 @@ void
 record_unwind_protect_int_1 (void (*function) (int), int arg,
                              bool wind_explicitly)
 {
-  specpdl_ptr->unwind_int.kind = SPECPDL_UNWIND_INT;
-  specpdl_ptr->unwind_int.func = function;
-  specpdl_ptr->unwind_int.arg = arg;
-  specpdl_ptr->unwind_int.wind_explicitly = wind_explicitly;
-  grow_specpdl ();
+  record_unwind_protect_ptr_1 (function, arg, wind_explicitly);
 }
 
 void
@@ -3242,14 +3295,17 @@ record_unwind_protect_int (void (*function) (int), int arg)
   record_unwind_protect_int_1 (function, arg, true);
 }
 
+static void
+call_void (void *data)
+{
+  ((void (*) (void)) data) ();
+}
+
 void
 record_unwind_protect_void_1 (void (*function) (void),
                               bool wind_explicitly)
 {
-  specpdl_ptr->unwind_void.kind = SPECPDL_UNWIND_VOID;
-  specpdl_ptr->unwind_void.func = function;
-  specpdl_ptr->unwind_void.wind_explicitly = wind_explicitly;
-  grow_specpdl ();
+  record_unwind_protect_ptr_1 (call_void, function, wind_explicitly);
 }
 
 void
@@ -3258,8 +3314,8 @@ record_unwind_protect_void (void (*function) (void))
   record_unwind_protect_void_1 (function, true);
 }
 
-void
-unbind_once (bool explicit)
+static void
+unbind_once (void *ignore)
 {
   /* Decrement specpdl_ptr before we do the work to unbind it, so
      that an error in unbinding won't try to unbind the same entry
@@ -3270,22 +3326,6 @@ unbind_once (bool explicit)
 
   switch (specpdl_ptr->kind)
     {
-    case SPECPDL_UNWIND:
-      if (specpdl_ptr->unwind.wind_explicitly || ! explicit)
-        specpdl_ptr->unwind.func (specpdl_ptr->unwind.arg);
-      break;
-    case SPECPDL_UNWIND_PTR:
-      if (specpdl_ptr->unwind_ptr.wind_explicitly || ! explicit)
-        specpdl_ptr->unwind_ptr.func (specpdl_ptr->unwind_ptr.arg);
-      break;
-    case SPECPDL_UNWIND_INT:
-      if (specpdl_ptr->unwind_int.wind_explicitly || ! explicit)
-        specpdl_ptr->unwind_int.func (specpdl_ptr->unwind_int.arg);
-      break;
-    case SPECPDL_UNWIND_VOID:
-      if (specpdl_ptr->unwind_void.wind_explicitly || ! explicit)
-        specpdl_ptr->unwind_void.func ();
-      break;
     case SPECPDL_BACKTRACE:
       break;
     case SPECPDL_LET:
@@ -3327,52 +3367,13 @@ unbind_once (bool explicit)
 void
 dynwind_begin (void)
 {
-  specpdl_ptr->kind = SPECPDL_FRAME;
-  grow_specpdl ();
+  scm_dynwind_begin (0);
 }
 
 void
 dynwind_end (void)
 {
-  enum specbind_tag last;
-  Lisp_Object quitf = Vquit_flag;
-  union specbinding *pdl = specpdl_ptr;
-
-  Vquit_flag = Qnil;
-
-  do
-    pdl--;
-  while (pdl->kind != SPECPDL_FRAME);
-
-  while (specpdl_ptr != pdl)
-    unbind_once (true);
-
-  Vquit_flag = quitf;
-}
-
-static Lisp_Object
-unbind_to_1 (ptrdiff_t count, Lisp_Object value, bool explicit)
-{
-  Lisp_Object quitf = Vquit_flag;
-  struct gcpro gcpro1, gcpro2;
-
-  GCPRO2 (value, quitf);
-  Vquit_flag = Qnil;
-
-  while (specpdl_ptr != specpdl + count)
-    unbind_once (explicit);
-
-  if (NILP (Vquit_flag) && !NILP (quitf))
-    Vquit_flag = quitf;
-
-  UNGCPRO;
-  return value;
-}
-
-Lisp_Object
-unbind_to (ptrdiff_t count, Lisp_Object value)
-{
-  return unbind_to_1 (count, value, true);
+  scm_dynwind_end ();
 }
 
 DEFUN ("special-variable-p", Fspecial_variable_p, Sspecial_variable_p, 1, 1, 0,
@@ -3525,13 +3526,6 @@ backtrace_eval_unrewind (int distance)
       /*  */
       switch (tmp->kind)
        {
-         /* FIXME: Ideally we'd like to "temporarily unwind" (some of) those
-            unwind_protect, but the problem is that we don't know how to
-            rewind them afterwards.  */
-       case SPECPDL_UNWIND:
-       case SPECPDL_UNWIND_PTR:
-       case SPECPDL_UNWIND_INT:
-       case SPECPDL_UNWIND_VOID:
        case SPECPDL_BACKTRACE:
          break;
        case SPECPDL_LET:
@@ -3696,7 +3690,38 @@ Lisp_Object backtrace_top_function (void)
   union specbinding *pdl = backtrace_top ();
   return (backtrace_p (pdl) ? backtrace_function (pdl) : Qnil);
 }
+\f
+_Noreturn SCM
+abort_to_prompt (SCM tag, SCM arglst)
+{
+  static SCM var = SCM_UNDEFINED;
+  if (SCM_UNBNDP (var))
+    var = scm_c_public_lookup ("guile", "abort-to-prompt");
 
+  scm_apply_1 (scm_variable_ref (var), tag, arglst);
+  emacs_abort ();
+}
+
+SCM
+call_with_prompt (SCM tag, SCM thunk, SCM handler)
+{
+  static SCM var = SCM_UNDEFINED;
+  if (SCM_UNBNDP (var))
+    var = scm_c_public_lookup ("guile", "call-with-prompt");
+
+  return scm_call_3 (scm_variable_ref (var), tag, thunk, handler);
+}
+
+SCM
+make_prompt_tag (void)
+{
+  static SCM var = SCM_UNDEFINED;
+  if (SCM_UNBNDP (var))
+    var = scm_c_public_lookup ("guile", "make-prompt-tag");
+
+  return scm_call_0 (scm_variable_ref (var));
+}
+\f
 void
 syms_of_eval (void)
 {
diff --git a/src/guile.c b/src/guile.c
new file mode 100644 (file)
index 0000000..24fd55b
--- /dev/null
@@ -0,0 +1,92 @@
+/* Guile utilities.
+
+Copyright (C) 2013 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include "lisp.h"
+
+scm_t_bits c_closure_tag;
+
+typedef SCM (*c_closure_0_t) (void *);
+typedef SCM (*c_closure_1_t) (void *, SCM);
+typedef SCM (*c_closure_2_t) (void *, SCM, SCM);
+typedef SCM (*c_closure_3_t) (void *, SCM, SCM, SCM);
+typedef SCM (*c_closure_4_t) (void *, SCM, SCM, SCM, SCM);
+typedef SCM (*c_closure_5_t) (void *, SCM, SCM, SCM, SCM, SCM);
+typedef SCM (*c_closure_6_t) (void *, SCM, SCM, SCM, SCM, SCM, SCM);
+typedef SCM (*c_closure_7_t) (void *, SCM, SCM, SCM, SCM, SCM, SCM, SCM);
+
+SCM
+make_c_closure (SCM (*func) (), void *data, int req, int opt)
+{
+  SCM smob;
+
+  if (req > 3 || opt > 1)
+    emacs_abort ();
+
+  SCM_NEWSMOB2 (smob, c_closure_tag, func, data);
+  SCM_SET_SMOB_FLAGS (smob, req | (opt << 2));
+  return smob;
+}
+
+static SCM
+apply_c_closure (SCM c_closure, SCM args)
+{
+  int req, opt;
+  SCM cargs[7];
+  long nargs = scm_to_long (scm_length (args));
+  scm_t_bits flags = SCM_SMOB_FLAGS (c_closure);
+  scm_t_bits func = SCM_SMOB_DATA (c_closure);
+  void *data = (void *) SCM_SMOB_DATA_2 (c_closure);
+
+  req = flags & 3;
+  opt = (flags >> 2) & 1;
+
+  for (int i = 0; i < req + opt; i++)
+    {
+      if (scm_is_pair (args))
+        {
+          cargs[i] = scm_car (args);
+          args = scm_cdr (args);
+        }
+      else if (opt)
+        {
+          cargs[i] = SCM_UNDEFINED;
+        }
+      else
+        scm_wrong_num_args (c_closure);
+    }
+
+  switch (req + opt)
+    {
+    case 0: return ((c_closure_0_t) func) (data);
+    case 1: return ((c_closure_1_t) func) (data, cargs[0]);
+    case 2: return ((c_closure_2_t) func) (data, cargs[0], cargs[1]);
+    case 3: return ((c_closure_3_t) func) (data, cargs[0], cargs[1], cargs[2]);
+    case 4: return ((c_closure_4_t) func) (data, cargs[0], cargs[1], cargs[2], cargs[3]);
+    default:
+      emacs_abort ();
+    }
+}
+
+void
+init_guile (void)
+{
+  c_closure_tag = scm_make_smob_type ("c-closure", 0);
+  scm_set_smob_apply (c_closure_tag, apply_c_closure, 0, 0, 1);
+}
diff --git a/src/guile.h b/src/guile.h
new file mode 100644 (file)
index 0000000..df55036
--- /dev/null
@@ -0,0 +1,2 @@
+SCM make_c_closure (SCM (*) (), void *, int, int);
+void init_guile (void);
index 20498d0..5a04956 100644 (file)
@@ -43,6 +43,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "systime.h"
 #include "atimer.h"
 #include "process.h"
+#include "guile.h"
 #include <errno.h>
 
 #ifdef HAVE_PTHREAD
@@ -137,7 +138,7 @@ static ptrdiff_t before_command_echo_length;
 
 /* For longjmp to where kbd input is being done.  */
 
-static sys_jmp_buf getcjmp;
+static Lisp_Object getctag;
 
 /* True while doing kbd input.  */
 bool waiting_for_input;
@@ -417,8 +418,6 @@ static Lisp_Object make_lispy_focus_in (Lisp_Object);
 static Lisp_Object make_lispy_focus_out (Lisp_Object);
 #endif /* HAVE_WINDOW_SYSTEM */
 static bool help_char_p (Lisp_Object);
-static void save_getcjmp (sys_jmp_buf *);
-static void restore_getcjmp (sys_jmp_buf *);
 static Lisp_Object apply_modifiers (int, Lisp_Object);
 static void clear_event (struct input_event *);
 static void restore_kboard_configuration (int);
@@ -1683,7 +1682,7 @@ Lisp_Object
 read_menu_command (void)
 {
   Lisp_Object keybuf[30];
-  ptrdiff_t count = SPECPDL_INDEX ();
+  scm_dynwind_begin (0);
   int i;
 
   /* We don't want to echo the keystrokes while navigating the
@@ -1693,7 +1692,7 @@ read_menu_command (void)
   i = read_key_sequence (keybuf, ARRAYELTS (keybuf),
                         Qnil, 0, 1, 1, 1);
 
-  unbind_to (count, Qnil);
+  scm_dynwind_end ();
 
   if (! FRAME_LIVE_P (XFRAME (selected_frame)))
     Fkill_emacs (Qnil);
@@ -2213,10 +2212,11 @@ do { if (polling_stopped_here) start_polling ();        \
 
 static Lisp_Object
 read_event_from_main_queue (struct timespec *end_time,
-                            sys_jmp_buf *local_getcjmp,
+                            Lisp_Object local_tag,
                             bool *used_mouse_menu)
 {
   Lisp_Object c = Qnil;
+  Lisp_Object save_tag = Qnil;
   sys_jmp_buf *save_jump = xmalloc (sizeof *save_jump);
   KBOARD *kb IF_LINT (= NULL);
 
@@ -2229,12 +2229,12 @@ read_event_from_main_queue (struct timespec *end_time,
     return c;
 
   /* Actually read a character, waiting if necessary.  */
-  save_getcjmp (save_jump);
-  restore_getcjmp (local_getcjmp);
+  save_tag = getctag;
+  getctag = local_tag;
   if (!end_time)
        timer_start_idle ();
   c = kbd_buffer_get_event (&kb, used_mouse_menu, end_time);
-  restore_getcjmp (save_jump);
+  getctag = save_tag;
 
   if (! NILP (c) && (kb != current_kboard))
     {
@@ -2287,7 +2287,7 @@ read_event_from_main_queue (struct timespec *end_time,
    to tty input.  */
 static Lisp_Object
 read_decoded_event_from_main_queue (struct timespec *end_time,
-                                    sys_jmp_buf *local_getcjmp,
+                                    Lisp_Object local_getcjmp,
                                     Lisp_Object prev_event,
                                     bool *used_mouse_menu)
 {
@@ -2408,9 +2408,9 @@ struct read_char_state
   bool *used_mouse_menu;
   struct timespec *end_time;
   Lisp_Object c;
-  ptrdiff_t jmpcount;
-  sys_jmp_buf *local_getcjmp;
-  sys_jmp_buf *save_jump;
+  Lisp_Object tag;
+  Lisp_Object local_tag;
+  Lisp_Object save_tag;
   Lisp_Object previous_echo_area_message;
   Lisp_Object also_record;
   bool reread;
@@ -2420,13 +2420,65 @@ struct read_char_state
 
 static Lisp_Object read_char_1 (bool, volatile struct read_char_state *);
 
+static Lisp_Object
+read_char_thunk (void *data)
+{
+  return read_char_1 (false, data);
+}
+
+static Lisp_Object
+read_char_handle_quit (void *data, Lisp_Object k)
+{
+  struct read_char_state *state = data;
+  /* Handle quits while reading the keyboard.  */
+  /* We must have saved the outer value of getcjmp here,
+     so restore it now.  */
+  getctag = state->save_tag;
+  XSETINT (state->c, quit_char);
+  internal_last_event_frame = selected_frame;
+  Vlast_event_frame = internal_last_event_frame;
+  /* If we report the quit char as an event,
+     don't do so more than once.  */
+  if (!NILP (Vinhibit_quit))
+    Vquit_flag = Qnil;
+
+  {
+    KBOARD *kb = FRAME_KBOARD (XFRAME (selected_frame));
+    if (kb != current_kboard)
+      {
+        Lisp_Object last = KVAR (kb, kbd_queue);
+        /* We shouldn't get here if we were in single-kboard mode!  */
+        if (single_kboard)
+          emacs_abort ();
+        if (CONSP (last))
+          {
+            while (CONSP (XCDR (last)))
+              last = XCDR (last);
+            if (!NILP (XCDR (last)))
+              emacs_abort ();
+          }
+        if (!CONSP (last))
+          kset_kbd_queue (kb, list1 (state->c));
+        else
+          XSETCDR (last, list1 (state->c));
+        kb->kbd_queue_has_data = 1;
+        current_kboard = kb;
+        /* This is going to exit from read_char
+           so we had better get rid of this frame's stuff.  */
+        UNGCPRO;
+        return make_number (-2); /* wrong_kboard_jmpbuf */
+      }
+  }
+  return read_char_1 (true, state);
+}
+
 /* {{coccinelle:skip_start}} */
 Lisp_Object
 read_char (int commandflag, Lisp_Object map,
           Lisp_Object prev_event,
           bool *used_mouse_menu, struct timespec *end_time)
 {
-  volatile struct read_char_state *state = xmalloc (sizeof *state);
+  struct read_char_state *state = xmalloc (sizeof *state);
 
   state->commandflag = commandflag;
   state->map = map;
@@ -2434,8 +2486,8 @@ read_char (int commandflag, Lisp_Object map,
   state->used_mouse_menu = used_mouse_menu;
   state->end_time = end_time;
   state->c = Qnil;
-  state->local_getcjmp = xmalloc (sizeof (*state->local_getcjmp));
-  state->save_jump = xmalloc (sizeof (*state->save_jump));
+  state->local_tag = Qnil;
+  state->save_tag = Qnil;
   state->previous_echo_area_message = Qnil;
   state->also_record = Qnil;
   state->reread = false;
@@ -2448,54 +2500,11 @@ read_char (int commandflag, Lisp_Object map,
      around any call to sit_for or kbd_buffer_get_event;
      it *must not* be in effect when we call redisplay.  */
 
-  state->jmpcount = SPECPDL_INDEX ();
-  if (sys_setjmp (*state->local_getcjmp))
-    {
-      /* Handle quits while reading the keyboard.  */
-      /* We must have saved the outer value of getcjmp here,
-        so restore it now.  */
-      restore_getcjmp (state->save_jump);
-      pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
-      unbind_to (state->jmpcount, Qnil);
-      XSETINT (state->c, quit_char);
-      internal_last_event_frame = selected_frame;
-      Vlast_event_frame = internal_last_event_frame;
-      /* If we report the quit char as an event,
-        don't do so more than once.  */
-      if (!NILP (Vinhibit_quit))
-       Vquit_flag = Qnil;
-
-      {
-       KBOARD *kb = FRAME_KBOARD (XFRAME (selected_frame));
-       if (kb != current_kboard)
-         {
-           Lisp_Object last = KVAR (kb, kbd_queue);
-           /* We shouldn't get here if we were in single-kboard mode!  */
-           if (single_kboard)
-             emacs_abort ();
-           if (CONSP (last))
-             {
-               while (CONSP (XCDR (last)))
-                 last = XCDR (last);
-               if (!NILP (XCDR (last)))
-                 emacs_abort ();
-             }
-           if (!CONSP (last))
-             kset_kbd_queue (kb, list1 (state->c));
-           else
-             XSETCDR (last, list1 (state->c));
-           kb->kbd_queue_has_data = 1;
-           current_kboard = kb;
-           /* This is going to exit from read_char
-              so we had better get rid of this frame's stuff.  */
-           UNGCPRO;
-            return make_number (-2); /* wrong_kboard_jmpbuf */
-         }
-      }
-      return read_char_1 (true, state);
-    }
+  state->tag = state->local_tag = make_prompt_tag ();
 
-  return read_char_1 (false, state);
+  return call_with_prompt (state->tag,
+                           make_c_closure (read_char_thunk, state, 0, 0),
+                           make_c_closure (read_char_handle_quit, state, 1, 0));
 }
 
 static Lisp_Object
@@ -2508,13 +2517,15 @@ read_char_1 (bool jump, volatile struct read_char_state *state)
 #define end_time state->end_time
 #define c state->c
 #define jmpcount state->jmpcount
-#define local_getcjmp state->local_getcjmp
-#define save_jump state->save_jump
+#define local_getcjmp state->local_tag
+#define save_jump state->save_tag
 #define previous_echo_area_message state->previous_echo_area_message
 #define also_record state->also_record
 #define reread state->reread
 #define polling_stopped_here state->polling_stopped_here
 #define orig_kboard state->orig_kboard
+#define save_getcjmp(x) (x = getctag)
+#define restore_getcjmp(x) (getctag = x)
   Lisp_Object tem, save;
 
   if (jump)
@@ -3284,6 +3295,8 @@ read_char_1 (bool jump, volatile struct read_char_state *state)
 #undef reread
 #undef polling_stopped_here
 #undef orig_kboard
+#undef save_getcjmp
+#undef restore_getcjmp
 }
 /* {{coccinelle:skip_end}} */
 
@@ -3471,23 +3484,6 @@ record_char (Lisp_Object c)
       unblock_input ();
     }
 }
-
-/* Copy out or in the info on where C-g should throw to.
-   This is used when running Lisp code from within get_char,
-   in case get_char is called recursively.
-   See read_process_output.  */
-
-static void
-save_getcjmp (sys_jmp_buf *temp)
-{
-  memcpy (*temp, getcjmp, sizeof getcjmp);
-}
-
-static void
-restore_getcjmp (sys_jmp_buf *temp)
-{
-  memcpy (getcjmp, *temp, sizeof getcjmp);
-}
 \f
 /* Low level keyboard/mouse input.
    kbd_buffer_store_event places events in kbd_buffer, and
@@ -10512,7 +10508,7 @@ quit_throw_to_read_char (bool from_signal)
     do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
                     0, 0, Qnil);
 
-  sys_longjmp (getcjmp, 1);
+  abort_to_prompt (getctag, SCM_EOL);
 }
 \f
 DEFUN ("set-input-interrupt-mode", Fset_input_interrupt_mode,
index 2ceab5f..6cf9df4 100644 (file)
@@ -2543,11 +2543,6 @@ typedef jmp_buf sys_jmp_buf;
    union specbinding.  But only eval.c should access it.  */
 
 enum specbind_tag {
-  SPECPDL_FRAME = 1,
-  SPECPDL_UNWIND,              /* An unwind_protect function on Lisp_Object.  */
-  SPECPDL_UNWIND_PTR,          /* Likewise, on void *.  */
-  SPECPDL_UNWIND_INT,          /* Likewise, on int.  */
-  SPECPDL_UNWIND_VOID,         /* Likewise, with no arg.  */
   SPECPDL_BACKTRACE,           /* An element of the backtrace.  */
   SPECPDL_LET,                 /* A plain and simple dynamic let-binding.  */
   /* Tags greater than SPECPDL_LET must be "subkinds" of LET.  */
@@ -2633,53 +2628,17 @@ enum handlertype { CATCHER, CONDITION_CASE };
 struct handler
 {
   enum handlertype type;
+  Lisp_Object ptag;
   Lisp_Object tag_or_ch;
   Lisp_Object val;
+  Lisp_Object var;
+  Lisp_Object body;
   struct handler *next;
-  struct handler *nextfree;
-
-  /* The bytecode interpreter can have several handlers active at the same
-     time, so when we longjmp to one of them, it needs to know which handler
-     this was and what was the corresponding internal state.  This is stored
-     here, and when we longjmp we make sure that handlerlist points to the
-     proper handler.  */
-  Lisp_Object *bytecode_top;
-  int bytecode_dest;
-
-  /* Most global vars are reset to their value via the specpdl mechanism,
-     but a few others are handled by storing their value here.  */
-#if true /* GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS, but defined later.  */
-  struct gcpro *gcpro;
-#endif
-  sys_jmp_buf jmp;
   EMACS_INT lisp_eval_depth;
-  ptrdiff_t pdlcount;
   int poll_suppress_count;
   int interrupt_input_blocked;
 };
 
-/* Fill in the components of c, and put it on the list.  */
-#define PUSH_HANDLER(c, tag_ch_val, handlertype)       \
-  if (handlerlist->nextfree)                           \
-    (c) = handlerlist->nextfree;                       \
-  else                                                 \
-    {                                                  \
-      (c) = xmalloc (sizeof (struct handler));         \
-      (c)->nextfree = NULL;                            \
-      handlerlist->nextfree = (c);                     \
-    }                                                  \
-  (c)->type = (handlertype);                           \
-  (c)->tag_or_ch = (tag_ch_val);                       \
-  (c)->val = Qnil;                                     \
-  (c)->next = handlerlist;                             \
-  (c)->lisp_eval_depth = lisp_eval_depth;              \
-  (c)->pdlcount = SPECPDL_INDEX ();                    \
-  (c)->poll_suppress_count = poll_suppress_count;      \
-  (c)->interrupt_input_blocked = interrupt_input_blocked;\
-  (c)->gcpro = gcprolist;                              \
-  handlerlist = (c);
-
-
 extern Lisp_Object memory_signal_data;
 
 /* Check quit-flag and quit if it is non-nil.
@@ -3456,7 +3415,6 @@ extern void record_unwind_protect_void_1 (void (*) (void), bool);
 extern void record_unwind_protect_void (void (*) (void));
 extern void dynwind_begin (void);
 extern void dynwind_end (void);
-extern Lisp_Object unbind_to (ptrdiff_t, Lisp_Object);
 extern _Noreturn void error (const char *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2);
 extern _Noreturn void verror (const char *, va_list)
   ATTRIBUTE_FORMAT_PRINTF (1, 0);
@@ -3476,6 +3434,9 @@ extern void get_backtrace (Lisp_Object array);
 Lisp_Object backtrace_top_function (void);
 extern bool let_shadows_buffer_binding_p (struct Lisp_Symbol *symbol);
 extern bool let_shadows_global_binding_p (Lisp_Object symbol);
+extern _Noreturn SCM abort_to_prompt (SCM, SCM);
+extern SCM call_with_prompt (SCM, SCM, SCM);
+extern SCM make_prompt_tag (void);
 
 
 /* Defined in editfns.c.  */
@@ -4077,5 +4038,4 @@ functionp (Lisp_Object object)
 }
 
 INLINE_HEADER_END
-
 #endif /* EMACS_LISP_H */