use guile conses
[bpt/emacs.git] / src / eval.c
index d3fcec5..985abce 100644 (file)
@@ -1,6 +1,7 @@
 /* Evaluator for GNU Emacs Lisp interpreter.
 
-Copyright (C) 1985-1987, 1993-1995, 1999-2013 Free Software Foundation, Inc.
+Copyright (C) 1985-1987, 1993-1995, 1999-2014 Free Software Foundation,
+Inc.
 
 This file is part of GNU Emacs.
 
@@ -26,11 +27,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "commands.h"
 #include "keyboard.h"
 #include "dispextern.h"
-#include "frame.h"             /* For XFRAME.  */
-
-#if HAVE_X_WINDOWS
-#include "xterm.h"
-#endif
 
 /* Chain of condition and catch handlers currently in effect.  */
 
@@ -272,6 +268,8 @@ restore_stack_limits (Lisp_Object data)
   max_lisp_eval_depth = XINT (XCDR (data));
 }
 
+static void grow_specpdl (void);
+
 /* Call the Lisp debugger, giving it argument ARG.  */
 
 Lisp_Object
@@ -280,22 +278,29 @@ call_debugger (Lisp_Object arg)
   bool debug_while_redisplaying;
   ptrdiff_t count = SPECPDL_INDEX ();
   Lisp_Object val;
-  EMACS_INT old_max = max_specpdl_size;
-
-  /* Temporarily bump up the stack limits,
-     so the debugger won't run out of stack.  */
-
-  max_specpdl_size += 1;
-  record_unwind_protect (restore_stack_limits,
-                        Fcons (make_number (old_max),
-                               make_number (max_lisp_eval_depth)));
-  max_specpdl_size = old_max;
+  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);
 
   if (lisp_eval_depth + 40 > max_lisp_eval_depth)
     max_lisp_eval_depth = lisp_eval_depth + 40;
 
-  if (max_specpdl_size - 100 < SPECPDL_INDEX ())
-    max_specpdl_size = SPECPDL_INDEX () + 100;
+  /* 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),
+                               make_number (old_depth)));
 
 #ifdef HAVE_WINDOW_SYSTEM
   if (display_hourglass_p)
@@ -1163,7 +1168,6 @@ unwind_to_catch (struct handler *catch, Lisp_Object value)
 
   eassert (handlerlist == catch);
 
-  byte_stack_list = catch->byte_stack;
   gcprolist = catch->gcpro;
 #ifdef DEBUG_GCPRO
   gcpro_level = gcprolist ? gcprolist->level + 1 : 0;
@@ -1473,8 +1477,7 @@ See also the function `condition-case'.  */)
   struct handler *h;
 
   immediate_quit = 0;
-  abort_on_gc = 0;
-  if (gc_in_progress || waiting_for_input)
+  if (waiting_for_input)
     emacs_abort ();
 
 #if 0 /* rms: I don't know why this was here,
@@ -1532,8 +1535,8 @@ See also the function `condition-case'.  */)
          || NILP (clause)
          /* A `debug' symbol in the handler list disables the normal
             suppression of the debugger.  */
-         || (CONSP (clause) && CONSP (XCAR (clause))
-             && !NILP (Fmemq (Qdebug, XCAR (clause))))
+         || (CONSP (clause) && CONSP (clause)
+             && !NILP (Fmemq (Qdebug, clause)))
          /* Special handler that means "print a message and run debugger
             if requested".  */
          || EQ (h->tag_or_ch, Qerror)))
@@ -1875,12 +1878,6 @@ this does nothing and returns nil.  */)
       && !AUTOLOADP (XSYMBOL (function)->function))
     return Qnil;
 
-  if (!NILP (Vpurify_flag) && EQ (docstring, make_number (0)))
-    /* `read1' in lread.c has found the docstring starting with "\
-       and assumed the docstring will be provided by Snarf-documentation, so it
-       passed us 0 instead.  But that leads to accidental sharing in purecopy's
-       hash-consing, so we use a (hopefully) unique integer instead.  */
-    docstring = make_number (XHASH (function));
   return Fdefalias (function,
                    list5 (Qautoload, file, docstring, interactive, type),
                    Qnil);
@@ -2112,8 +2109,6 @@ eval_sub (Lisp_Object form)
       args_left = original_args;
       numargs = Flength (args_left);
 
-      check_cons_list ();
-
       if (XINT (numargs) < XSUBR (fun)->min_args
          || (XSUBR (fun)->max_args >= 0
              && XSUBR (fun)->max_args < XINT (numargs)))
@@ -2251,7 +2246,6 @@ eval_sub (Lisp_Object form)
       else
        xsignal1 (Qinvalid_function, original_fun);
     }
-  check_cons_list ();
 
   lisp_eval_depth--;
   if (backtrace_debug_on_exit (specpdl_ptr - 1))
@@ -2758,8 +2752,6 @@ usage: (funcall FUNCTION &rest ARGUMENTS)  */)
   if (debug_on_next_call)
     do_debug_on_call (Qlambda);
 
-  check_cons_list ();
-
   original_fun = args[0];
 
  retry:
@@ -2867,13 +2859,11 @@ usage: (funcall FUNCTION &rest ARGUMENTS)  */)
       else if (EQ (funcar, Qautoload))
        {
          Fautoload_do_load (fun, original_fun, Qnil);
-         check_cons_list ();
          goto retry;
        }
       else
        xsignal1 (Qinvalid_function, original_fun);
     }
-  check_cons_list ();
   lisp_eval_depth--;
   if (backtrace_debug_on_exit (specpdl_ptr - 1))
     val = call_debugger (list2 (Qexit, val));
@@ -3576,42 +3566,74 @@ NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'.
      from the debugger.  */
   return unbind_to (count, eval_sub (exp));
 }
-\f
-void
-mark_specpdl (void)
+
+DEFUN ("backtrace--locals", Fbacktrace__locals, Sbacktrace__locals, 1, 2, NULL,
+       doc: /* Return names and values of local variables of a stack frame.
+NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'.  */)
+  (Lisp_Object nframes, Lisp_Object base)
 {
-  union specbinding *pdl;
-  for (pdl = specpdl; pdl != specpdl_ptr; pdl++)
-    {
-      switch (pdl->kind)
-       {
-       case SPECPDL_UNWIND:
-         mark_object (specpdl_arg (pdl));
-         break;
+  union specbinding *frame = get_backtrace_frame (nframes, base);
+  union specbinding *prevframe
+    = get_backtrace_frame (make_number (XFASTINT (nframes) - 1), base);
+  ptrdiff_t distance = specpdl_ptr - frame;
+  Lisp_Object result = Qnil;
+  eassert (distance >= 0);
 
-       case SPECPDL_BACKTRACE:
+  if (!backtrace_p (prevframe))
+    error ("Activation frame not found!");
+  if (!backtrace_p (frame))
+    error ("Activation frame not found!");
+
+  /* The specpdl entries normally contain the symbol being bound along with its
+     `old_value', so it can be restored.  The new value to which it is bound is
+     available in one of two places: either in the current value of the
+     variable (if it hasn't been rebound yet) or in the `old_value' slot of the
+     next specpdl entry for it.
+     `backtrace_eval_unrewind' happens to swap the role of `old_value'
+     and "new value", so we abuse it here, to fetch the new value.
+     It's ugly (we'd rather not modify global data) and a bit inefficient,
+     but it does the job for now.  */
+  backtrace_eval_unrewind (distance);
+
+  /* Grab values.  */
+  {
+    union specbinding *tmp = prevframe;
+    for (; tmp > frame; tmp--)
+      {
+       switch (tmp->kind)
          {
-           ptrdiff_t nargs = backtrace_nargs (pdl);
-           mark_object (backtrace_function (pdl));
-           if (nargs == UNEVALLED)
-             nargs = 1;
-           while (nargs--)
-             mark_object (backtrace_args (pdl)[nargs]);
+         case SPECPDL_LET:
+         case SPECPDL_LET_DEFAULT:
+         case SPECPDL_LET_LOCAL:
+           {
+             Lisp_Object sym = specpdl_symbol (tmp);
+             Lisp_Object val = specpdl_old_value (tmp);
+             if (EQ (sym, Qinternal_interpreter_environment))
+               {
+                 Lisp_Object env = val;
+                 for (; CONSP (env); env = XCDR (env))
+                   {
+                     Lisp_Object binding = XCAR (env);
+                     if (CONSP (binding))
+                       result = Fcons (Fcons (XCAR (binding),
+                                              XCDR (binding)),
+                                       result);
+                   }
+               }
+             else
+               result = Fcons (Fcons (sym, val), result);
+           }
          }
-         break;
+      }
+  }
 
-       case SPECPDL_LET_DEFAULT:
-       case SPECPDL_LET_LOCAL:
-         mark_object (specpdl_where (pdl));
-         /* Fall through.  */
-       case SPECPDL_LET:
-         mark_object (specpdl_symbol (pdl));
-         mark_object (specpdl_old_value (pdl));
-         break;
-       }
-    }
+  /* Restore values from specpdl to original place.  */
+  backtrace_eval_unrewind (-distance);
+
+  return result;
 }
 
+\f
 void
 get_backtrace (Lisp_Object array)
 {
@@ -3646,7 +3668,9 @@ If Lisp code tries to increase the total number past this amount,
 an error is signaled.
 You can safely use a value considerably larger than the default value,
 if that proves inconveniently small.  However, if you increase it too far,
-Emacs could run out of memory trying to make the stack bigger.  */);
+Emacs could run out of memory trying to make the stack bigger.
+Note that this limit may be silently increased by the debugger
+if `debug-on-error' or `debug-on-quit' is set.  */);
 
   DEFVAR_INT ("max-lisp-eval-depth", max_lisp_eval_depth,
              doc: /* Limit on depth in `eval', `apply' and `funcall' before error.
@@ -3824,6 +3848,7 @@ alist of active lexical bindings.  */);
   defsubr (&Sbacktrace);
   defsubr (&Sbacktrace_frame);
   defsubr (&Sbacktrace_eval);
+  defsubr (&Sbacktrace__locals);
   defsubr (&Sspecial_variable_p);
   defsubr (&Sfunctionp);
 }