summaryrefslogtreecommitdiff
path: root/src/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c1921
1 files changed, 1116 insertions, 805 deletions
diff --git a/src/eval.c b/src/eval.c
index acda64e7f04..7da1d8fb989 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1,6 +1,6 @@
/* Evaluator for GNU Emacs Lisp interpreter.
-Copyright (C) 1985-1987, 1993-1995, 1999-2017 Free Software Foundation,
+Copyright (C) 1985-1987, 1993-1995, 1999-2022 Free Software Foundation,
Inc.
This file is part of GNU Emacs.
@@ -21,7 +21,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <config.h>
#include <limits.h>
-#include <stdio.h>
#include <stdlib.h>
#include "lisp.h"
#include "blockinput.h"
@@ -29,6 +28,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "keyboard.h"
#include "dispextern.h"
#include "buffer.h"
+#include "pdumper.h"
+#include "atimer.h"
/* CACHEABLE is ordinarily nothing, except it is 'volatile' if
necessary to cajole GCC into not warning incorrectly that a
@@ -39,10 +40,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
# define CACHEABLE /* empty */
#endif
-/* Chain of condition and catch handlers currently in effect. */
-
-/* struct handler *handlerlist; */
-
/* Non-nil means record all fset's and provide's, to be undone
if the file being autoloaded is not fully loaded.
They are recorded by being consed onto the front of Vautoload_queue:
@@ -55,43 +52,16 @@ Lisp_Object Vautoload_queue;
is shutting down. */
Lisp_Object Vrun_hooks;
-/* The commented-out variables below are macros defined in thread.h. */
-
-/* Current number of specbindings allocated in specpdl, not counting
- the dummy entry specpdl[-1]. */
-
-/* ptrdiff_t specpdl_size; */
-
-/* Pointer to beginning of specpdl. A dummy entry specpdl[-1] exists
- only so that its address can be taken. */
-
-/* union specbinding *specpdl; */
-
-/* Pointer to first unused element in specpdl. */
-
-/* union specbinding *specpdl_ptr; */
-
-/* Depth in Lisp evaluations and function calls. */
-
-/* static EMACS_INT lisp_eval_depth; */
-
-/* The value of num_nonmacro_input_events as of the last time we
- started to enter the debugger. If we decide to enter the debugger
- again when this is still equal to num_nonmacro_input_events, then we
- know that the debugger itself has an error, and we should just
- signal the error instead of entering an infinite loop of debugger
- invocations. */
-
-static EMACS_INT when_entered_debugger;
-
/* The function from which the last `signal' was called. Set in
Fsignal. */
/* FIXME: We should probably get rid of this! */
Lisp_Object Vsignaling_function;
-/* If non-nil, Lisp code must not be run since some part of Emacs is in
- an inconsistent state. Currently unused. */
-Lisp_Object inhibit_lisp_code;
+/* The handler structure which will catch errors in Lisp hooks called
+ from redisplay. We do not use it for this; we compare it with the
+ handler which is about to be used in signal_or_quit, and if it
+ matches, cause a backtrace to be generated. */
+static struct handler *redisplay_deep_handler;
/* These would ordinarily be static, but they need to be visible to GDB. */
bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE;
@@ -101,7 +71,7 @@ union specbinding *backtrace_next (union specbinding *) EXTERNALLY_VISIBLE;
union specbinding *backtrace_top (void) EXTERNALLY_VISIBLE;
static Lisp_Object funcall_lambda (Lisp_Object, ptrdiff_t, Lisp_Object *);
-static Lisp_Object apply_lambda (Lisp_Object, Lisp_Object, ptrdiff_t);
+static Lisp_Object apply_lambda (Lisp_Object, Lisp_Object, specpdl_ref);
static Lisp_Object lambda_arity (Lisp_Object);
static Lisp_Object
@@ -140,13 +110,6 @@ specpdl_where (union specbinding *pdl)
}
static Lisp_Object
-specpdl_saved_value (union specbinding *pdl)
-{
- eassert (pdl->kind >= SPECPDL_LET);
- return pdl->let.saved_value;
-}
-
-static Lisp_Object
specpdl_arg (union specbinding *pdl)
{
eassert (pdl->kind == SPECPDL_UNWIND);
@@ -174,13 +137,6 @@ backtrace_args (union specbinding *pdl)
return pdl->bt.args;
}
-static bool
-backtrace_debug_on_exit (union specbinding *pdl)
-{
- eassert (pdl->kind == SPECPDL_BACKTRACE);
- return pdl->bt.debug_on_exit;
-}
-
/* Functions to modify slots of backtrace records. */
static void
@@ -202,17 +158,36 @@ set_backtrace_debug_on_exit (union specbinding *pdl, bool doe)
bool
backtrace_p (union specbinding *pdl)
-{ return pdl >= specpdl; }
+{ return specpdl ? pdl >= specpdl : false; }
+
+static bool
+backtrace_thread_p (struct thread_state *tstate, union specbinding *pdl)
+{ return pdl >= tstate->m_specpdl; }
union specbinding *
backtrace_top (void)
{
+ /* This is so "xbacktrace" doesn't crash in pdumped Emacs if they
+ invoke the command before init_eval_once_for_pdumper initializes
+ specpdl machinery. See also backtrace_p above. */
+ if (!specpdl)
+ return NULL;
+
union specbinding *pdl = specpdl_ptr - 1;
while (backtrace_p (pdl) && pdl->kind != SPECPDL_BACKTRACE)
pdl--;
return pdl;
}
+static union specbinding *
+backtrace_thread_top (struct thread_state *tstate)
+{
+ union specbinding *pdl = tstate->m_specpdl_ptr - 1;
+ while (backtrace_thread_p (tstate, pdl) && pdl->kind != SPECPDL_BACKTRACE)
+ pdl--;
+ return pdl;
+}
+
union specbinding *
backtrace_next (union specbinding *pdl)
{
@@ -222,21 +197,34 @@ backtrace_next (union specbinding *pdl)
return pdl;
}
+static void init_eval_once_for_pdumper (void);
+
+static union specbinding *
+backtrace_thread_next (struct thread_state *tstate, union specbinding *pdl)
+{
+ pdl--;
+ while (backtrace_thread_p (tstate, pdl) && pdl->kind != SPECPDL_BACKTRACE)
+ pdl--;
+ return pdl;
+}
+
void
init_eval_once (void)
{
- enum { size = 50 };
- union specbinding *pdlvec = xmalloc ((size + 1) * sizeof *specpdl);
- specpdl_size = size;
- specpdl = specpdl_ptr = pdlvec + 1;
- /* Don't forget to update docs (lispref node "Local Variables"). */
- max_specpdl_size = 1300; /* 1000 is not enough for CEDET's c-by.el. */
- max_lisp_eval_depth = 800;
-
+ /* Don't forget to update docs (lispref node "Eval"). */
+ max_lisp_eval_depth = 1600;
Vrun_hooks = Qnil;
+ pdumper_do_now_and_after_load (init_eval_once_for_pdumper);
}
-/* static struct handler handlerlist_sentinel; */
+static void
+init_eval_once_for_pdumper (void)
+{
+ enum { size = 50 };
+ union specbinding *pdlvec = malloc ((size + 1) * sizeof *specpdl);
+ specpdl = specpdl_ptr = pdlvec + 1;
+ specpdl_end = specpdl + size;
+}
void
init_eval (void)
@@ -257,6 +245,17 @@ init_eval (void)
lisp_eval_depth = 0;
/* This is less than the initial value of num_nonmacro_input_events. */
when_entered_debugger = -1;
+ redisplay_deep_handler = NULL;
+}
+
+/* Ensure that *M is at least A + B if possible, or is its maximum
+ value otherwise. */
+
+static void
+max_ensure_room (intmax_t *m, intmax_t a, intmax_t b)
+{
+ intmax_t sum = INT_ADD_WRAPV (a, b, &sum) ? INTMAX_MAX : sum;
+ *m = max (*m, sum);
}
/* Unwind-protect function used by call_debugger. */
@@ -264,43 +263,27 @@ init_eval (void)
static void
restore_stack_limits (Lisp_Object data)
{
- max_specpdl_size = XINT (XCAR (data));
- max_lisp_eval_depth = XINT (XCDR (data));
+ integer_to_intmax (data, &max_lisp_eval_depth);
}
-static void grow_specpdl (void);
-
/* Call the Lisp debugger, giving it argument ARG. */
Lisp_Object
call_debugger (Lisp_Object arg)
{
bool debug_while_redisplaying;
- ptrdiff_t count = SPECPDL_INDEX ();
+ specpdl_ref count = SPECPDL_INDEX ();
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);
-
- if (lisp_eval_depth + 40 > max_lisp_eval_depth)
- max_lisp_eval_depth = lisp_eval_depth + 40;
+ intmax_t old_depth = max_lisp_eval_depth;
- /* 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 ();
- }
+ /* The previous value of 40 is too small now that the debugger
+ prints using cl-prin1 instead of prin1. Printing lists nested 8
+ deep (which is the value of print-level used in the debugger)
+ currently requires 77 additional frames. See bug#31919. */
+ max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100);
/* Restore limits after leaving the debugger. */
- record_unwind_protect (restore_stack_limits,
- Fcons (make_number (old_max),
- make_number (old_depth)));
+ record_unwind_protect (restore_stack_limits, make_int (old_depth));
#ifdef HAVE_WINDOW_SYSTEM
if (display_hourglass_p)
@@ -334,23 +317,21 @@ call_debugger (Lisp_Object arg)
/* Interrupting redisplay and resuming it later is not safe under
all circumstances. So, when the debugger returns, abort the
interrupted redisplay by going back to the top-level. */
- if (debug_while_redisplaying)
+ if (debug_while_redisplaying
+ && !EQ (Vdebugger, Qdebug_early))
Ftop_level ();
return unbind_to (count, val);
}
-static void
-do_debug_on_call (Lisp_Object code, ptrdiff_t count)
+void
+do_debug_on_call (Lisp_Object code, specpdl_ref count)
{
debug_on_next_call = 0;
- set_backtrace_debug_on_exit (specpdl + count, true);
+ set_backtrace_debug_on_exit (specpdl_ref_to_ptr (count), true);
call_debugger (list1 (code));
}
-/* NOTE!!! Every function that can call EVAL must protect its args
- and temporaries from garbage collection while it needs them.
- The definition of `For' shows what you have to do. */
DEFUN ("or", For, Sor, 0, UNEVALLED, 0,
doc: /* Eval args until one of them yields non-nil, then return that value.
@@ -446,7 +427,7 @@ DEFUN ("progn", Fprogn, Sprogn, 0, UNEVALLED, 0,
usage: (progn BODY...) */)
(Lisp_Object body)
{
- Lisp_Object val = Qnil;
+ Lisp_Object CACHEABLE val = Qnil;
while (CONSP (body))
{
@@ -478,17 +459,6 @@ usage: (prog1 FIRST BODY...) */)
return val;
}
-DEFUN ("prog2", Fprog2, Sprog2, 2, UNEVALLED, 0,
- doc: /* Eval FORM1, FORM2 and BODY sequentially; return value from FORM2.
-The value of FORM2 is saved during the evaluation of the
-remaining args, whose values are discarded.
-usage: (prog2 FORM1 FORM2 BODY...) */)
- (Lisp_Object args)
-{
- eval_sub (XCAR (args));
- return Fprog1 (XCDR (args));
-}
-
DEFUN ("setq", Fsetq, Ssetq, 0, UNEVALLED, 0,
doc: /* Set each SYM to the value of its VAL.
The symbols SYM are variables; they are literal (not evaluated).
@@ -504,19 +474,21 @@ usage: (setq [SYM VAL]...) */)
for (EMACS_INT nargs = 0; CONSP (tail); nargs += 2)
{
- Lisp_Object sym = XCAR (tail), lex_binding;
+ Lisp_Object sym = XCAR (tail);
tail = XCDR (tail);
if (!CONSP (tail))
- xsignal2 (Qwrong_number_of_arguments, Qsetq, make_number (nargs + 1));
+ xsignal2 (Qwrong_number_of_arguments, Qsetq, make_fixnum (nargs + 1));
Lisp_Object arg = XCAR (tail);
tail = XCDR (tail);
val = eval_sub (arg);
/* Like for eval_sub, we do not check declared_special here since
it's been done when let-binding. */
- if (!NILP (Vinternal_interpreter_environment) /* Mere optimization! */
- && SYMBOLP (sym)
- && !NILP (lex_binding
- = Fassq (sym, Vinternal_interpreter_environment)))
+ Lisp_Object lex_binding
+ = ((!NILP (Vinternal_interpreter_environment) /* Mere optimization! */
+ && SYMBOLP (sym))
+ ? Fassq (sym, Vinternal_interpreter_environment)
+ : Qnil);
+ if (!NILP (lex_binding))
XSETCDR (lex_binding, val); /* SYM is lexically bound. */
else
Fset (sym, val); /* SYM is dynamically bound. */
@@ -545,8 +517,11 @@ usage: (quote ARG) */)
DEFUN ("function", Ffunction, Sfunction, 1, UNEVALLED, 0,
doc: /* Like `quote', but preferred for objects which are functions.
-In byte compilation, `function' causes its argument to be compiled.
-`quote' cannot do that.
+In byte compilation, `function' causes its argument to be handled by
+the byte compiler. Similarly, when expanding macros and expressions,
+ARG can be examined and possibly expanded. If `quote' is used
+instead, this doesn't happen.
+
usage: (function ARG) */)
(Lisp_Object args)
{
@@ -569,6 +544,10 @@ usage: (function ARG) */)
{ /* Handle the special (:documentation <form>) to build the docstring
dynamically. */
Lisp_Object docstring = eval_sub (Fcar (XCDR (tmp)));
+ if (SYMBOLP (docstring) && !NILP (docstring))
+ /* Hack for OClosures: Allow the docstring to be a symbol
+ * (the OClosure's type). */
+ docstring = Fsymbol_name (docstring);
CHECK_STRING (docstring);
cdr = Fcons (XCAR (cdr), Fcons (docstring, XCDR (XCDR (cdr))));
}
@@ -599,16 +578,19 @@ The return value is BASE-VARIABLE. */)
if (SYMBOL_CONSTANT_P (new_alias))
/* Making it an alias effectively changes its value. */
- error ("Cannot make a constant an alias");
+ error ("Cannot make a constant an alias: %s",
+ SDATA (SYMBOL_NAME (new_alias)));
sym = XSYMBOL (new_alias);
- switch (sym->redirect)
+ switch (sym->u.s.redirect)
{
case SYMBOL_FORWARDED:
- error ("Cannot make an internal variable an alias");
+ error ("Cannot make a built-in variable an alias: %s",
+ SDATA (SYMBOL_NAME (new_alias)));
case SYMBOL_LOCALIZED:
- error ("Don't know how to make a localized variable an alias");
+ error ("Don't know how to make a buffer-local variable an alias: %s",
+ SDATA (SYMBOL_NAME (new_alias)));
case SYMBOL_PLAINVAL:
case SYMBOL_VARALIAS:
break;
@@ -616,30 +598,41 @@ The return value is BASE-VARIABLE. */)
emacs_abort ();
}
- /* https://lists.gnu.org/archive/html/emacs-devel/2008-04/msg00834.html
+ /* https://lists.gnu.org/r/emacs-devel/2008-04/msg00834.html
If n_a is bound, but b_v is not, set the value of b_v to n_a,
so that old-code that affects n_a before the aliasing is setup
still works. */
if (NILP (Fboundp (base_variable)))
set_internal (base_variable, find_symbol_value (new_alias),
Qnil, SET_INTERNAL_BIND);
+ else if (!NILP (Fboundp (new_alias))
+ && !EQ (find_symbol_value (new_alias),
+ find_symbol_value (base_variable)))
+ call2 (intern ("display-warning"),
+ list3 (Qdefvaralias, intern ("losing-value"), new_alias),
+ CALLN (Fformat_message,
+ build_string
+ ("Overwriting value of `%s' by aliasing to `%s'"),
+ new_alias, base_variable));
+
{
union specbinding *p;
for (p = specpdl_ptr; p > specpdl; )
if ((--p)->kind >= SPECPDL_LET
&& (EQ (new_alias, specpdl_symbol (p))))
- error ("Don't know how to make a let-bound variable an alias");
+ error ("Don't know how to make a let-bound variable an alias: %s",
+ SDATA (SYMBOL_NAME (new_alias)));
}
- if (sym->trapped_write == SYMBOL_TRAPPED_WRITE)
+ if (sym->u.s.trapped_write == SYMBOL_TRAPPED_WRITE)
notify_variable_watchers (new_alias, base_variable, Qdefvaralias, Qnil);
- sym->declared_special = 1;
- XSYMBOL (base_variable)->declared_special = 1;
- sym->redirect = SYMBOL_VARALIAS;
+ sym->u.s.declared_special = true;
+ XSYMBOL (base_variable)->u.s.declared_special = true;
+ sym->u.s.redirect = SYMBOL_VARALIAS;
SET_SYMBOL_ALIAS (sym, XSYMBOL (base_variable));
- sym->trapped_write = XSYMBOL (base_variable)->trapped_write;
+ sym->u.s.trapped_write = XSYMBOL (base_variable)->u.s.trapped_write;
LOADHIST_ATTACH (new_alias);
/* Even if docstring is nil: remove old docstring. */
Fput (new_alias, Qvariable_documentation, docstring);
@@ -662,19 +655,37 @@ default_toplevel_binding (Lisp_Object symbol)
binding = pdl;
break;
- case SPECPDL_UNWIND:
- case SPECPDL_UNWIND_PTR:
- case SPECPDL_UNWIND_INT:
- case SPECPDL_UNWIND_VOID:
- case SPECPDL_BACKTRACE:
- case SPECPDL_LET_LOCAL:
+ default: break;
+ }
+ }
+ return binding;
+}
+
+/* Look for a lexical-binding of SYMBOL somewhere up the stack.
+ This will only find bindings created with interpreted code, since once
+ compiled names of lexical variables are basically gone anyway. */
+static bool
+lexbound_p (Lisp_Object symbol)
+{
+ union specbinding *pdl = specpdl_ptr;
+ while (pdl > specpdl)
+ {
+ switch ((--pdl)->kind)
+ {
+ case SPECPDL_LET_DEFAULT:
+ case SPECPDL_LET:
+ if (EQ (specpdl_symbol (pdl), Qinternal_interpreter_environment))
+ {
+ Lisp_Object env = specpdl_old_value (pdl);
+ if (CONSP (env) && !NILP (Fassq (symbol, env)))
+ return true;
+ }
break;
- default:
- emacs_abort ();
+ default: break;
}
}
- return binding;
+ return false;
}
DEFUN ("default-toplevel-value", Fdefault_toplevel_value, Sdefault_toplevel_value, 1, 1, 0,
@@ -685,7 +696,7 @@ DEFUN ("default-toplevel-value", Fdefault_toplevel_value, Sdefault_toplevel_valu
union specbinding *binding = default_toplevel_binding (symbol);
Lisp_Object value
= binding ? specpdl_old_value (binding) : Fdefault_value (symbol);
- if (!EQ (value, Qunbound))
+ if (!BASE_EQ (value, Qunbound))
return value;
xsignal1 (Qvoid_variable, symbol);
}
@@ -704,6 +715,63 @@ DEFUN ("set-default-toplevel-value", Fset_default_toplevel_value,
return Qnil;
}
+DEFUN ("internal--define-uninitialized-variable",
+ Finternal__define_uninitialized_variable,
+ Sinternal__define_uninitialized_variable, 1, 2, 0,
+ doc: /* Define SYMBOL as a variable, with DOC as its docstring.
+This is like `defvar' and `defconst' but without affecting the variable's
+value. */)
+ (Lisp_Object symbol, Lisp_Object doc)
+{
+ if (!XSYMBOL (symbol)->u.s.declared_special
+ && lexbound_p (symbol))
+ /* This test tries to catch the situation where we do
+ (let ((<foo-var> ...)) ...(<foo-function> ...)....)
+ and where the `foo` package only gets loaded when <foo-function>
+ is called, so the outer `let` incorrectly made the binding lexical
+ because the <foo-var> wasn't yet declared as dynamic at that point. */
+ xsignal2 (Qerror,
+ build_string ("Defining as dynamic an already lexical var"),
+ symbol);
+
+ XSYMBOL (symbol)->u.s.declared_special = true;
+ if (!NILP (doc))
+ {
+ if (!NILP (Vpurify_flag))
+ doc = Fpurecopy (doc);
+ Fput (symbol, Qvariable_documentation, doc);
+ }
+ LOADHIST_ATTACH (symbol);
+ return Qnil;
+}
+
+static Lisp_Object
+defvar (Lisp_Object sym, Lisp_Object initvalue, Lisp_Object docstring, bool eval)
+{
+ Lisp_Object tem;
+
+ CHECK_SYMBOL (sym);
+
+ tem = Fdefault_boundp (sym);
+
+ /* Do it before evaluating the initial value, for self-references. */
+ Finternal__define_uninitialized_variable (sym, docstring);
+
+ if (NILP (tem))
+ Fset_default (sym, eval ? eval_sub (initvalue) : initvalue);
+ else
+ { /* Check if there is really a global binding rather than just a let
+ binding that shadows the global unboundness of the var. */
+ union specbinding *binding = default_toplevel_binding (sym);
+ if (binding && BASE_EQ (specpdl_old_value (binding), Qunbound))
+ {
+ set_specpdl_old_value (binding,
+ eval ? eval_sub (initvalue) : initvalue);
+ }
+ }
+ return sym;
+}
+
DEFUN ("defvar", Fdefvar, Sdefvar, 1, UNEVALLED, 0,
doc: /* Define SYMBOL as a variable, and return SYMBOL.
You are not required to define a variable in order to use it, but
@@ -718,58 +786,37 @@ value. If SYMBOL is buffer-local, its default value is what is set;
buffer-local values are not affected. If INITVALUE is missing,
SYMBOL's value is not set.
-If SYMBOL has a local binding, then this form affects the local
-binding. This is usually not what you want. Thus, if you need to
-load a file defining variables, with this form or with `defconst' or
-`defcustom', you should always load that file _outside_ any bindings
-for these variables. (`defconst' and `defcustom' behave similarly in
-this respect.)
+If SYMBOL is let-bound, then this form does not affect the local let
+binding but the toplevel default binding instead, like
+`set-toplevel-default-binding`.
+(`defcustom' behaves similarly in this respect.)
The optional argument DOCSTRING is a documentation string for the
variable.
To define a user option, use `defcustom' instead of `defvar'.
+
+To define a buffer-local variable, use `defvar-local'.
usage: (defvar SYMBOL &optional INITVALUE DOCSTRING) */)
(Lisp_Object args)
{
- Lisp_Object sym, tem, tail;
+ Lisp_Object sym, tail;
sym = XCAR (args);
tail = XCDR (args);
+ CHECK_SYMBOL (sym);
+
if (!NILP (tail))
{
if (!NILP (XCDR (tail)) && !NILP (XCDR (XCDR (tail))))
error ("Too many arguments");
-
- tem = Fdefault_boundp (sym);
-
- /* Do it before evaluating the initial value, for self-references. */
- XSYMBOL (sym)->declared_special = 1;
-
- if (NILP (tem))
- Fset_default (sym, eval_sub (XCAR (tail)));
- else
- { /* Check if there is really a global binding rather than just a let
- binding that shadows the global unboundness of the var. */
- union specbinding *binding = default_toplevel_binding (sym);
- if (binding && EQ (specpdl_old_value (binding), Qunbound))
- {
- set_specpdl_old_value (binding, eval_sub (XCAR (tail)));
- }
- }
+ Lisp_Object exp = XCAR (tail);
tail = XCDR (tail);
- tem = Fcar (tail);
- if (!NILP (tem))
- {
- if (!NILP (Vpurify_flag))
- tem = Fpurecopy (tem);
- Fput (sym, Qvariable_documentation, tem);
- }
- LOADHIST_ATTACH (sym);
+ return defvar (sym, exp, CAR (tail), true);
}
else if (!NILP (Vinternal_interpreter_environment)
- && !XSYMBOL (sym)->declared_special)
+ && (SYMBOLP (sym) && !XSYMBOL (sym)->u.s.declared_special))
/* A simple (defvar foo) with lexical scoping does "nothing" except
declare that var to be dynamically scoped *locally* (i.e. within
the current file or let-block). */
@@ -785,6 +832,14 @@ usage: (defvar SYMBOL &optional INITVALUE DOCSTRING) */)
return sym;
}
+DEFUN ("defvar-1", Fdefvar_1, Sdefvar_1, 2, 3, 0,
+ doc: /* Like `defvar' but as a function.
+More specifically behaves like (defvar SYM 'INITVALUE DOCSTRING). */)
+ (Lisp_Object sym, Lisp_Object initvalue, Lisp_Object docstring)
+{
+ return defvar (sym, initvalue, docstring, false);
+}
+
DEFUN ("defconst", Fdefconst, Sdefconst, 2, UNEVALLED, 0,
doc: /* Define SYMBOL as a constant variable.
This declares that neither programs nor users should ever change the
@@ -806,6 +861,7 @@ usage: (defconst SYMBOL INITVALUE [DOCSTRING]) */)
Lisp_Object sym, tem;
sym = XCAR (args);
+ CHECK_SYMBOL (sym);
Lisp_Object docstring = Qnil;
if (!NILP (XCDR (XCDR (args))))
{
@@ -813,20 +869,22 @@ usage: (defconst SYMBOL INITVALUE [DOCSTRING]) */)
error ("Too many arguments");
docstring = XCAR (XCDR (XCDR (args)));
}
-
tem = eval_sub (XCAR (XCDR (args)));
+ return Fdefconst_1 (sym, tem, docstring);
+}
+
+DEFUN ("defconst-1", Fdefconst_1, Sdefconst_1, 2, 3, 0,
+ doc: /* Like `defconst' but as a function.
+More specifically, behaves like (defconst SYM 'INITVALUE DOCSTRING). */)
+ (Lisp_Object sym, Lisp_Object initvalue, Lisp_Object docstring)
+{
+ CHECK_SYMBOL (sym);
+ Lisp_Object tem = initvalue;
+ Finternal__define_uninitialized_variable (sym, docstring);
if (!NILP (Vpurify_flag))
tem = Fpurecopy (tem);
- Fset_default (sym, tem);
- XSYMBOL (sym)->declared_special = 1;
- if (!NILP (docstring))
- {
- if (!NILP (Vpurify_flag))
- docstring = Fpurecopy (docstring);
- Fput (sym, Qvariable_documentation, docstring);
- }
- Fput (sym, Qrisky_local_variable, Qt);
- LOADHIST_ATTACH (sym);
+ Fset_default (sym, tem); /* FIXME: set-default-toplevel-value? */
+ Fput (sym, Qrisky_local_variable, Qt); /* FIXME: Why? */
return sym;
}
@@ -837,7 +895,7 @@ DEFUN ("internal-make-var-non-special", Fmake_var_non_special,
(Lisp_Object symbol)
{
CHECK_SYMBOL (symbol);
- XSYMBOL (symbol)->declared_special = 0;
+ XSYMBOL (symbol)->u.s.declared_special = false;
return Qnil;
}
@@ -852,17 +910,14 @@ usage: (let* VARLIST BODY...) */)
(Lisp_Object args)
{
Lisp_Object var, val, elt, lexenv;
- ptrdiff_t count = SPECPDL_INDEX ();
+ specpdl_ref count = SPECPDL_INDEX ();
lexenv = Vinternal_interpreter_environment;
Lisp_Object varlist = XCAR (args);
- while (CONSP (varlist))
+ FOR_EACH_TAIL (varlist)
{
- maybe_quit ();
-
elt = XCAR (varlist);
- varlist = XCDR (varlist);
if (SYMBOLP (elt))
{
var = elt;
@@ -877,7 +932,7 @@ usage: (let* VARLIST BODY...) */)
}
if (!NILP (lexenv) && SYMBOLP (var)
- && !XSYMBOL (var)->declared_special
+ && !XSYMBOL (var)->u.s.declared_special
&& NILP (Fmemq (var, Vinternal_interpreter_environment)))
/* Lexically bind VAR by adding it to the interpreter's binding
alist. */
@@ -911,16 +966,15 @@ usage: (let VARLIST BODY...) */)
(Lisp_Object args)
{
Lisp_Object *temps, tem, lexenv;
- Lisp_Object elt, varlist;
- ptrdiff_t count = SPECPDL_INDEX ();
+ Lisp_Object elt;
+ specpdl_ref count = SPECPDL_INDEX ();
ptrdiff_t argnum;
USE_SAFE_ALLOCA;
- varlist = XCAR (args);
- CHECK_LIST (varlist);
+ Lisp_Object varlist = XCAR (args);
/* Make space to hold the values to give the bound variables. */
- EMACS_INT varlist_len = XFASTINT (Flength (varlist));
+ EMACS_INT varlist_len = list_length (varlist);
SAFE_ALLOCA_LISP (temps, varlist_len);
ptrdiff_t nvars = varlist_len;
@@ -953,7 +1007,7 @@ usage: (let VARLIST BODY...) */)
tem = temps[argnum];
if (!NILP (lexenv) && SYMBOLP (var)
- && !XSYMBOL (var)->declared_special
+ && !XSYMBOL (var)->u.s.declared_special
&& NILP (Fmemq (var, Vinternal_interpreter_environment)))
/* Lexically bind VAR by adding it to the lexenv alist. */
lexenv = Fcons (Fcons (var, tem), lexenv);
@@ -967,14 +1021,16 @@ usage: (let VARLIST BODY...) */)
specbind (Qinternal_interpreter_environment, lexenv);
elt = Fprogn (XCDR (args));
- SAFE_FREE ();
- return unbind_to (count, elt);
+ return SAFE_FREE_UNBIND_TO (count, elt);
}
DEFUN ("while", Fwhile, Swhile, 1, UNEVALLED, 0,
doc: /* If TEST yields non-nil, eval BODY... and repeat.
The order of execution is thus TEST, BODY, TEST, BODY and so on
until TEST returns nil.
+
+The value of a `while' form is always nil.
+
usage: (while TEST BODY...) */)
(Lisp_Object args)
{
@@ -991,6 +1047,47 @@ usage: (while TEST BODY...) */)
return Qnil;
}
+static void
+with_delayed_message_display (struct atimer *timer)
+{
+ message3 (build_string (timer->client_data));
+}
+
+static void
+with_delayed_message_cancel (void *timer)
+{
+ xfree (((struct atimer *) timer)->client_data);
+ cancel_atimer (timer);
+}
+
+DEFUN ("funcall-with-delayed-message",
+ Ffuncall_with_delayed_message, Sfuncall_with_delayed_message,
+ 3, 3, 0,
+ doc: /* Like `funcall', but display MESSAGE if FUNCTION takes longer than TIMEOUT.
+TIMEOUT is a number of seconds, and can be an integer or a floating
+point number.
+
+If FUNCTION takes less time to execute than TIMEOUT seconds, MESSAGE
+is not displayed. */)
+ (Lisp_Object timeout, Lisp_Object message, Lisp_Object function)
+{
+ specpdl_ref count = SPECPDL_INDEX ();
+
+ CHECK_NUMBER (timeout);
+ CHECK_STRING (message);
+
+ /* Set up the atimer. */
+ struct timespec interval = dtotimespec (XFLOATINT (timeout));
+ struct atimer *timer = start_atimer (ATIMER_RELATIVE, interval,
+ with_delayed_message_display,
+ xstrdup (SSDATA (message)));
+ record_unwind_protect_ptr (with_delayed_message_cancel, timer);
+
+ Lisp_Object result = CALLN (Ffuncall, function);
+
+ return unbind_to (count, result);
+}
+
DEFUN ("macroexpand", Fmacroexpand, Smacroexpand, 1, 2, 0,
doc: /* Return result of expanding macros at top level of FORM.
If FORM is not a macro call, it is returned unchanged.
@@ -1022,7 +1119,7 @@ definitions to shadow the loaded ones for use in file byte-compilation. */)
tem = Fassq (sym, environment);
if (NILP (tem))
{
- def = XSYMBOL (sym)->function;
+ def = XSYMBOL (sym)->u.s.function;
if (!NILP (def))
continue;
}
@@ -1124,20 +1221,29 @@ internal_catch (Lisp_Object tag,
This is used for correct unwinding in Fthrow and Fsignal. */
-static _Noreturn void
-unwind_to_catch (struct handler *catch, Lisp_Object value)
+static AVOID
+unwind_to_catch (struct handler *catch, enum nonlocal_exit type,
+ Lisp_Object value)
{
bool last_time;
eassert (catch->next);
/* Save the value in the tag. */
+ catch->nonlocal_exit = type;
catch->val = value;
/* Restore certain special C variables. */
set_poll_suppress_count (catch->poll_suppress_count);
unblock_input_to (catch->interrupt_input_blocked);
+#ifdef HAVE_X_WINDOWS
+ /* Restore the X error handler stack. This is important because
+ otherwise a display disconnect won't unwind the stack of error
+ traps to the right depth. */
+ x_unwind_errors_to (catch->x_error_handler_depth);
+#endif
+
do
{
/* Unwind the specpdl stack, and then restore the proper set of
@@ -1152,6 +1258,7 @@ unwind_to_catch (struct handler *catch, Lisp_Object value)
eassert (handlerlist == catch);
lisp_eval_depth = catch->f_lisp_eval_depth;
+ set_act_rec (current_thread, catch->act_rec);
sys_longjmp (catch->jmp, 1);
}
@@ -1168,9 +1275,9 @@ Both TAG and VALUE are evalled. */
for (c = handlerlist; c; c = c->next)
{
if (c->type == CATCHER_ALL)
- unwind_to_catch (c, Fcons (tag, value));
- if (c->type == CATCHER && EQ (c->tag_or_ch, tag))
- unwind_to_catch (c, value);
+ unwind_to_catch (c, NONLOCAL_EXIT_THROW, Fcons (tag, value));
+ if (c->type == CATCHER && EQ (c->tag_or_ch, tag))
+ unwind_to_catch (c, NONLOCAL_EXIT_THROW, value);
}
xsignal2 (Qno_catch, tag, value);
}
@@ -1185,7 +1292,7 @@ usage: (unwind-protect BODYFORM UNWINDFORMS...) */)
(Lisp_Object args)
{
Lisp_Object val;
- ptrdiff_t count = SPECPDL_INDEX ();
+ specpdl_ref count = SPECPDL_INDEX ();
record_unwind_protect (prog_ignore, XCDR (args));
val = eval_sub (XCAR (args));
@@ -1196,17 +1303,19 @@ DEFUN ("condition-case", Fcondition_case, Scondition_case, 2, UNEVALLED, 0,
doc: /* Regain control when an error is signaled.
Executes BODYFORM and returns its value if no error happens.
Each element of HANDLERS looks like (CONDITION-NAME BODY...)
-where the BODY is made of Lisp expressions.
+or (:success BODY...), where the BODY is made of Lisp expressions.
-A handler is applicable to an error
-if CONDITION-NAME is one of the error's condition names.
-If an error happens, the first applicable handler is run.
+A handler is applicable to an error if CONDITION-NAME is one of the
+error's condition names. Handlers may also apply when non-error
+symbols are signaled (e.g., `quit'). A CONDITION-NAME of t applies to
+any symbol, including non-error symbols. If multiple handlers are
+applicable, only the first one runs.
The car of a handler may be a list of condition names instead of a
single condition name; then it handles all of them. If the special
condition name `debug' is present in this list, it allows another
condition in the list to run the debugger if `debug-on-error' and the
-other usual mechanisms says it should (otherwise, `condition-case'
+other usual mechanisms say it should (otherwise, `condition-case'
suppresses the debugger).
When a handler handles an error, control returns to the `condition-case'
@@ -1216,6 +1325,10 @@ with VAR bound to (ERROR-SYMBOL . SIGNAL-DATA) from the error.
Then the value of the last BODY form is returned from the `condition-case'
expression.
+The special handler (:success BODY...) is invoked if BODYFORM terminated
+without signalling an error. BODY is then evaluated with VAR bound to
+the value returned by BODYFORM.
+
See also the function `signal' for more info.
usage: (condition-case VAR BODYFORM &rest HANDLERS) */)
(Lisp_Object args)
@@ -1239,16 +1352,21 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform,
CHECK_SYMBOL (var);
+ Lisp_Object success_handler = Qnil;
+
for (Lisp_Object tail = handlers; CONSP (tail); tail = XCDR (tail))
{
Lisp_Object tem = XCAR (tail);
- clausenb++;
if (! (NILP (tem)
|| (CONSP (tem)
&& (SYMBOLP (XCAR (tem))
|| CONSP (XCAR (tem))))))
error ("Invalid condition handler: %s",
- SDATA (Fprin1_to_string (tem, Qt)));
+ SDATA (Fprin1_to_string (tem, Qt, Qnil)));
+ if (CONSP (tem) && EQ (XCAR (tem), QCsuccess))
+ success_handler = XCDR (tem);
+ else
+ clausenb++;
}
/* The first clause is the one that should be checked first, so it
@@ -1262,7 +1380,11 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform,
Lisp_Object volatile *clauses = alloca (clausenb * sizeof *clauses);
clauses += clausenb;
for (Lisp_Object tail = handlers; CONSP (tail); tail = XCDR (tail))
- *--clauses = XCAR (tail);
+ {
+ Lisp_Object tem = XCAR (tail);
+ if (!(CONSP (tem) && EQ (XCAR (tem), QCsuccess)))
+ *--clauses = tem;
+ }
for (ptrdiff_t i = 0; i < clausenb; i++)
{
Lisp_Object clause = clauses[i];
@@ -1294,14 +1416,31 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform,
/* Bind HANDLER_VAR to VAL while evaluating HANDLER_BODY.
The unbind_to undoes just this binding; whoever longjumped
to us unwound the stack to C->pdlcount before throwing. */
- ptrdiff_t count = SPECPDL_INDEX ();
+ specpdl_ref count = SPECPDL_INDEX ();
specbind (handler_var, val);
return unbind_to (count, Fprogn (handler_body));
}
}
- Lisp_Object result = eval_sub (bodyform);
+ Lisp_Object CACHEABLE result = eval_sub (bodyform);
handlerlist = oldhandlerlist;
+ if (!NILP (success_handler))
+ {
+ if (NILP (var))
+ return Fprogn (success_handler);
+
+ Lisp_Object handler_var = var;
+ if (!NILP (Vinternal_interpreter_environment))
+ {
+ result = Fcons (Fcons (var, result),
+ Vinternal_interpreter_environment);
+ handler_var = Qinternal_interpreter_environment;
+ }
+
+ specpdl_ref count = SPECPDL_INDEX ();
+ specbind (handler_var, result);
+ return unbind_to (count, Fprogn (success_handler));
+ }
return result;
}
@@ -1399,12 +1538,16 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *),
ptrdiff_t nargs,
Lisp_Object *args))
{
+ struct handler *old_deep = redisplay_deep_handler;
struct handler *c = push_handler (handlers, CONDITION_CASE);
+ if (redisplaying_p)
+ redisplay_deep_handler = c;
if (sys_setjmp (c->jmp))
{
Lisp_Object val = handlerlist->val;
clobbered_eassert (handlerlist == c);
handlerlist = handlerlist->next;
+ redisplay_deep_handler = old_deep;
return hfun (val, nargs, args);
}
else
@@ -1412,8 +1555,40 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *),
Lisp_Object val = bfun (nargs, args);
eassert (handlerlist == c);
handlerlist = c->next;
+ redisplay_deep_handler = old_deep;
+ return val;
+ }
+}
+
+static Lisp_Object Qcatch_all_memory_full;
+
+/* Like a combination of internal_condition_case_1 and internal_catch.
+ Catches all signals and throws. Never exits nonlocally; returns
+ Qcatch_all_memory_full if no handler could be allocated. */
+
+Lisp_Object
+internal_catch_all (Lisp_Object (*function) (void *), void *argument,
+ Lisp_Object (*handler) (enum nonlocal_exit, Lisp_Object))
+{
+ struct handler *c = push_handler_nosignal (Qt, CATCHER_ALL);
+ if (c == NULL)
+ return Qcatch_all_memory_full;
+
+ if (sys_setjmp (c->jmp) == 0)
+ {
+ Lisp_Object val = function (argument);
+ eassert (handlerlist == c);
+ handlerlist = c->next;
return val;
}
+ else
+ {
+ eassert (handlerlist == c);
+ enum nonlocal_exit type = c->nonlocal_exit;
+ Lisp_Object val = c->val;
+ handlerlist = c->next;
+ return handler (type, val);
+ }
}
struct handler *
@@ -1445,8 +1620,12 @@ push_handler_nosignal (Lisp_Object tag_ch_val, enum handlertype handlertype)
c->next = handlerlist;
c->f_lisp_eval_depth = lisp_eval_depth;
c->pdlcount = SPECPDL_INDEX ();
+ c->act_rec = get_act_rec (current_thread);
c->poll_suppress_count = poll_suppress_count;
c->interrupt_input_blocked = interrupt_input_blocked;
+#ifdef HAVE_X_WINDOWS
+ c->x_error_handler_depth = x_error_message_count;
+#endif
handlerlist = c;
return c;
}
@@ -1463,30 +1642,14 @@ process_quit_flag (void)
Lisp_Object flag = Vquit_flag;
Vquit_flag = Qnil;
if (EQ (flag, Qkill_emacs))
- Fkill_emacs (Qnil);
+ Fkill_emacs (Qnil, Qnil);
if (EQ (Vthrow_on_input, flag))
Fthrow (Vthrow_on_input, Qt);
quit ();
}
-/* Check quit-flag and quit if it is non-nil. Typing C-g does not
- directly cause a quit; it only sets Vquit_flag. So the program
- needs to call maybe_quit at times when it is safe to quit. Every
- loop that might run for a long time or might not exit ought to call
- maybe_quit at least once, at a safe place. Unless that is
- impossible, of course. But it is very desirable to avoid creating
- loops where maybe_quit is impossible.
-
- If quit-flag is set to `kill-emacs' the SIGINT handler has received
- a request to exit Emacs when it is safe to do.
-
- When not quitting, process any pending signals.
-
- If you change this function, also adapt module_should_quit in
- emacs-module.c. */
-
void
-maybe_quit (void)
+probably_quit (void)
{
if (!NILP (Vquit_flag) && NILP (Vinhibit_quit))
process_quit_flag ();
@@ -1499,7 +1662,7 @@ DEFUN ("signal", Fsignal, Ssignal, 2, 2, 0,
This function does not return.
An error symbol is a symbol with an `error-conditions' property
-that is a list of condition names.
+that is a list of condition names. The symbol should be non-nil.
A handler for any of those names will get to handle this signal.
The symbol `error' should normally be one of them.
@@ -1511,6 +1674,9 @@ See also the function `condition-case'. */
attributes: noreturn)
(Lisp_Object error_symbol, Lisp_Object data)
{
+ /* If they call us with nonsensical arguments, produce "peculiar error". */
+ if (NILP (error_symbol) && NILP (data))
+ error_symbol = Qerror;
signal_or_quit (error_symbol, data, false);
eassume (false);
}
@@ -1522,6 +1688,11 @@ quit (void)
return signal_or_quit (Qquit, Qnil, true);
}
+/* Has an error in redisplay giving rise to a backtrace occurred as
+ yet in the current command? This gets reset in the command
+ loop. */
+bool backtrace_yet = false;
+
/* Signal an error, or quit. ERROR_SYMBOL and DATA are as with Fsignal.
If KEYBOARD_QUIT, this is a quit; ERROR_SYMBOL should be
Qquit and DATA should be Qnil, and this function may return.
@@ -1553,14 +1724,13 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
/* This hook is used by edebug. */
if (! NILP (Vsignal_hook_function)
- && ! NILP (error_symbol))
+ && ! NILP (error_symbol)
+ /* Don't try to call a lisp function if we've already overflowed
+ the specpdl stack. */
+ && specpdl_ptr < specpdl_end)
{
/* Edebug takes care of restoring these variables when it exits. */
- if (lisp_eval_depth + 20 > max_lisp_eval_depth)
- max_lisp_eval_depth = lisp_eval_depth + 20;
-
- if (SPECPDL_INDEX () + 40 > max_specpdl_size)
- max_specpdl_size = SPECPDL_INDEX () + 40;
+ max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 20);
call2 (Vsignal_hook_function, error_symbol, data);
}
@@ -1583,6 +1753,11 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
for (h = handlerlist; h; h = h->next)
{
+ if (h->type == CATCHER_ALL)
+ {
+ clause = Qt;
+ break;
+ }
if (h->type != CONDITION_CASE)
continue;
clause = find_handler_clause (h->tag_or_ch, conditions);
@@ -1590,6 +1765,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
break;
}
+ bool debugger_called = false;
if (/* Don't run the debugger for a memory-full error.
(There is no room in memory to do that!) */
!NILP (error_symbol)
@@ -1603,7 +1779,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
if requested". */
|| EQ (h->tag_or_ch, Qerror)))
{
- bool debugger_called
+ debugger_called
= maybe_call_debugger (conditions, error_symbol, data);
/* We can't return values to code which signaled an error, but we
can continue code which has signaled a quit. */
@@ -1611,12 +1787,61 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
return Qnil;
}
+ /* If we're in batch mode, print a backtrace unconditionally to help
+ with debugging. Make sure to use `debug-early' unconditionally
+ to not interfere with ERT or other packages that install custom
+ debuggers. */
+ if (!debugger_called && !NILP (error_symbol)
+ && (NILP (clause) || EQ (h->tag_or_ch, Qerror))
+ && noninteractive && backtrace_on_error_noninteractive
+ && NILP (Vinhibit_debugger)
+ && !NILP (Ffboundp (Qdebug_early)))
+ {
+ max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100);
+ specpdl_ref count = SPECPDL_INDEX ();
+ specbind (Qdebugger, Qdebug_early);
+ call_debugger (list2 (Qerror, Fcons (error_symbol, data)));
+ unbind_to (count, Qnil);
+ }
+
+ /* If an error is signalled during a Lisp hook in redisplay, write a
+ backtrace into the buffer *Redisplay-trace*. */
+ if (!debugger_called && !NILP (error_symbol)
+ && backtrace_on_redisplay_error
+ && (NILP (clause) || h == redisplay_deep_handler)
+ && NILP (Vinhibit_debugger)
+ && !NILP (Ffboundp (Qdebug_early)))
+ {
+ max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100);
+ specpdl_ref count = SPECPDL_INDEX ();
+ AUTO_STRING (redisplay_trace, "*Redisplay_trace*");
+ Lisp_Object redisplay_trace_buffer;
+ AUTO_STRING (gap, "\n\n\n\n"); /* Separates things in *Redisplay-trace* */
+ Lisp_Object delayed_warning;
+ redisplay_trace_buffer = Fget_buffer_create (redisplay_trace, Qnil);
+ current_buffer = XBUFFER (redisplay_trace_buffer);
+ if (!backtrace_yet) /* Are we on the first backtrace of the command? */
+ Ferase_buffer ();
+ else
+ Finsert (1, &gap);
+ backtrace_yet = true;
+ specbind (Qstandard_output, redisplay_trace_buffer);
+ specbind (Qdebugger, Qdebug_early);
+ call_debugger (list2 (Qerror, Fcons (error_symbol, data)));
+ unbind_to (count, Qnil);
+ delayed_warning = make_string
+ ("Error in a redisplay Lisp hook. See buffer *Redisplay_trace*", 61);
+
+ Vdelayed_warnings_list = Fcons (list2 (Qerror, delayed_warning),
+ Vdelayed_warnings_list);
+ }
+
if (!NILP (clause))
{
Lisp_Object unwind_data
= (NILP (error_symbol) ? data : Fcons (error_symbol, data));
- unwind_to_catch (h, unwind_data);
+ unwind_to_catch (h, NONLOCAL_EXIT_SIGNAL, unwind_data);
}
else
{
@@ -1661,33 +1886,25 @@ xsignal3 (Lisp_Object error_symbol, Lisp_Object arg1, Lisp_Object arg2, Lisp_Obj
}
/* Signal `error' with message S, and additional arg ARG.
- If ARG is not a genuine list, make it a one-element list. */
+ If ARG is not a proper list, make it a one-element list. */
void
signal_error (const char *s, Lisp_Object arg)
{
- Lisp_Object tortoise, hare;
-
- hare = tortoise = arg;
- while (CONSP (hare))
- {
- hare = XCDR (hare);
- if (!CONSP (hare))
- break;
-
- hare = XCDR (hare);
- tortoise = XCDR (tortoise);
-
- if (EQ (hare, tortoise))
- break;
- }
-
- if (!NILP (hare))
+ if (NILP (Fproper_list_p (arg)))
arg = list1 (arg);
xsignal (Qerror, Fcons (build_string (s), arg));
}
+/* Use this for arithmetic overflow, e.g., when an integer result is
+ too large even for a bignum. */
+void
+overflow_error (void)
+{
+ xsignal0 (Qoverflow_error);
+}
+
/* Return true if LIST is a non-nil atom or
a list containing one of CONDITIONS. */
@@ -1750,6 +1967,18 @@ skip_debugger (Lisp_Object conditions, Lisp_Object data)
return 0;
}
+/* Say whether SIGNAL is a `quit' symbol (or inherits from it). */
+bool
+signal_quit_p (Lisp_Object signal)
+{
+ Lisp_Object list;
+
+ return EQ (signal, Qquit)
+ || (!NILP (Fsymbolp (signal))
+ && CONSP (list = Fget (signal, Qerror_conditions))
+ && !NILP (Fmemq (Qquit, list)));
+}
+
/* Call the debugger if calling it is currently enabled for CONDITIONS.
SIG and DATA describe the signal. There are two ways to pass them:
= SIG is the error symbol, and DATA is the rest of the data.
@@ -1768,11 +1997,12 @@ maybe_call_debugger (Lisp_Object conditions, Lisp_Object sig, Lisp_Object data)
! input_blocked_p ()
&& NILP (Vinhibit_debugger)
/* Does user want to enter debugger for this kind of error? */
- && (EQ (sig, Qquit)
+ && (signal_quit_p (sig)
? debug_on_quit
: wants_debugger (Vdebug_on_error, conditions))
&& ! skip_debugger (conditions, combined_data)
- /* RMS: What's this for? */
+ /* See commentary on definition of
+ `internal-when-entered-debugger'. */
&& when_entered_debugger < num_nonmacro_input_events)
{
call_debugger (list2 (Qerror, combined_data));
@@ -1799,7 +2029,9 @@ find_handler_clause (Lisp_Object handlers, Lisp_Object conditions)
for (h = handlers; CONSP (h); h = XCDR (h))
{
Lisp_Object handler = XCAR (h);
- if (!NILP (Fmemq (handler, conditions)))
+ if (!NILP (Fmemq (handler, conditions))
+ /* t is also used as a catch-all by Lisp code. */
+ || EQ (handler, Qt))
return handlers;
}
@@ -1836,7 +2068,6 @@ verror (const char *m, va_list ap)
/* Dump an error message; called like printf. */
-/* VARARGS 1 */
void
error (const char *m, ...)
{
@@ -1863,8 +2094,7 @@ then strings and vectors are not accepted. */)
(Lisp_Object function, Lisp_Object for_call_interactively)
{
register Lisp_Object fun;
- register Lisp_Object funcar;
- Lisp_Object if_prop = Qnil;
+ bool genfun = false; /* If true, we should consult `interactive-form'. */
fun = function;
@@ -1872,43 +2102,89 @@ then strings and vectors are not accepted. */)
if (NILP (fun))
return Qnil;
- /* Check an `interactive-form' property if present, analogous to the
- function-documentation property. */
- fun = function;
- while (SYMBOLP (fun))
- {
- Lisp_Object tmp = Fget (fun, Qinteractive_form);
- if (!NILP (tmp))
- if_prop = Qt;
- fun = Fsymbol_function (fun);
- }
-
/* Emacs primitives are interactive if their DEFUN specifies an
interactive spec. */
if (SUBRP (fun))
- return XSUBR (fun)->intspec ? Qt : if_prop;
-
+ {
+ if (XSUBR (fun)->intspec.string)
+ return Qt;
+ }
/* Bytecode objects are interactive if they are long enough to
have an element whose index is COMPILED_INTERACTIVE, which is
where the interactive spec is stored. */
else if (COMPILEDP (fun))
- return (PVSIZE (fun) > COMPILED_INTERACTIVE ? Qt : if_prop);
+ {
+ if (PVSIZE (fun) > COMPILED_INTERACTIVE)
+ return Qt;
+ else if (PVSIZE (fun) > COMPILED_DOC_STRING)
+ {
+ Lisp_Object doc = AREF (fun, COMPILED_DOC_STRING);
+ /* An invalid "docstring" is a sign that we have an OClosure. */
+ genfun = !(NILP (doc) || VALID_DOCSTRING_P (doc));
+ }
+ }
+
+#ifdef HAVE_MODULES
+ /* Module functions are interactive if their `interactive_form'
+ field is non-nil. */
+ else if (MODULE_FUNCTIONP (fun))
+ {
+ if (!NILP (module_function_interactive_form (XMODULE_FUNCTION (fun))))
+ return Qt;
+ }
+#endif
/* Strings and vectors are keyboard macros. */
- if (STRINGP (fun) || VECTORP (fun))
+ else if (STRINGP (fun) || VECTORP (fun))
return (NILP (for_call_interactively) ? Qt : Qnil);
/* Lists may represent commands. */
- if (!CONSP (fun))
+ else if (!CONSP (fun))
return Qnil;
- funcar = XCAR (fun);
- if (EQ (funcar, Qclosure))
- return (!NILP (Fassq (Qinteractive, Fcdr (Fcdr (XCDR (fun)))))
- ? Qt : if_prop);
- else if (EQ (funcar, Qlambda))
- return !NILP (Fassq (Qinteractive, Fcdr (XCDR (fun)))) ? Qt : if_prop;
- else if (EQ (funcar, Qautoload))
- return !NILP (Fcar (Fcdr (Fcdr (XCDR (fun))))) ? Qt : if_prop;
+ else
+ {
+ Lisp_Object funcar = XCAR (fun);
+ if (EQ (funcar, Qautoload))
+ {
+ if (!NILP (Fcar (Fcdr (Fcdr (XCDR (fun))))))
+ return Qt;
+ }
+ else
+ {
+ Lisp_Object body = CDR_SAFE (XCDR (fun));
+ if (EQ (funcar, Qclosure))
+ body = CDR_SAFE (body);
+ else if (!EQ (funcar, Qlambda))
+ return Qnil;
+ if (!NILP (Fassq (Qinteractive, body)))
+ return Qt;
+ else if (VALID_DOCSTRING_P (CAR_SAFE (body)))
+ /* A "docstring" is a sign that we may have an OClosure. */
+ genfun = true;
+ }
+ }
+
+ /* By now, if it's not a function we already returned nil. */
+
+ /* Check an `interactive-form' property if present, analogous to the
+ function-documentation property. */
+ fun = function;
+ while (SYMBOLP (fun))
+ {
+ Lisp_Object tmp = Fget (fun, Qinteractive_form);
+ if (!NILP (tmp))
+ error ("Found an 'interactive-form' property!");
+ fun = Fsymbol_function (fun);
+ }
+
+ /* If there's no immediate interactive form but it's an OClosure,
+ then delegate to the generic-function in case it has
+ a type-specific interactive-form. */
+ if (genfun)
+ {
+ Lisp_Object iform = call1 (Qinteractive_form, fun);
+ return NILP (iform) ? Qnil : Qt;
+ }
else
return Qnil;
}
@@ -1916,14 +2192,21 @@ then strings and vectors are not accepted. */)
DEFUN ("autoload", Fautoload, Sautoload, 2, 5, 0,
doc: /* Define FUNCTION to autoload from FILE.
FUNCTION is a symbol; FILE is a file name string to pass to `load'.
+
Third arg DOCSTRING is documentation for the function.
-Fourth arg INTERACTIVE if non-nil says function can be called interactively.
+
+Fourth arg INTERACTIVE if non-nil says function can be called
+interactively. If INTERACTIVE is a list, it is interpreted as a list
+of modes the function is applicable for.
+
Fifth arg TYPE indicates the type of the object:
nil or omitted says FUNCTION is a function,
`keymap' says FUNCTION is really a keymap, and
`macro' or t says FUNCTION is really a macro.
+
Third through fifth args give info about the real definition.
They default to nil.
+
If FUNCTION is already defined other than as an autoload,
this does nothing and returns nil. */)
(Lisp_Object function, Lisp_Object file, Lisp_Object docstring, Lisp_Object interactive, Lisp_Object type)
@@ -1932,43 +2215,65 @@ this does nothing and returns nil. */)
CHECK_STRING (file);
/* If function is defined and not as an autoload, don't override. */
- if (!NILP (XSYMBOL (function)->function)
- && !AUTOLOADP (XSYMBOL (function)->function))
+ if (!NILP (XSYMBOL (function)->u.s.function)
+ && !AUTOLOADP (XSYMBOL (function)->u.s.function))
return Qnil;
- if (!NILP (Vpurify_flag) && EQ (docstring, make_number (0)))
+ if (!NILP (Vpurify_flag) && BASE_EQ (docstring, make_fixnum (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));
+ docstring = make_ufixnum (XHASH (function));
return Fdefalias (function,
list5 (Qautoload, file, docstring, interactive, type),
Qnil);
}
-void
+static void
un_autoload (Lisp_Object oldqueue)
{
- Lisp_Object queue, first, second;
-
/* Queue to unwind is current value of Vautoload_queue.
oldqueue is the shadowed value to leave in Vautoload_queue. */
- queue = Vautoload_queue;
+ Lisp_Object queue = Vautoload_queue;
Vautoload_queue = oldqueue;
while (CONSP (queue))
{
- first = XCAR (queue);
- second = Fcdr (first);
- first = Fcar (first);
- if (EQ (first, make_number (0)))
- Vfeatures = second;
+ Lisp_Object first = XCAR (queue);
+ if (CONSP (first) && BASE_EQ (XCAR (first), make_fixnum (0)))
+ Vfeatures = XCDR (first);
else
- Ffset (first, second);
+ Ffset (first, Fcar (Fcdr (Fget (first, Qfunction_history))));
queue = XCDR (queue);
}
}
+Lisp_Object
+load_with_autoload_queue
+ (Lisp_Object file, Lisp_Object noerror, Lisp_Object nomessage,
+ Lisp_Object nosuffix, Lisp_Object must_suffix)
+{
+ specpdl_ref count = SPECPDL_INDEX ();
+
+ /* If autoloading gets an error (which includes the error of failing
+ to define the function being called), we use Vautoload_queue
+ to undo function definitions and `provide' calls made by
+ the function. We do this in the specific case of autoloading
+ because autoloading is not an explicit request "load this file",
+ but rather a request to "call this function".
+
+ The value saved here is to be restored into Vautoload_queue. */
+ record_unwind_protect (un_autoload, Vautoload_queue);
+ Vautoload_queue = Qt;
+ Lisp_Object tem
+ = save_match_data_load (file, noerror, nomessage, nosuffix, must_suffix);
+
+ /* Once loading finishes, don't undo it. */
+ Vautoload_queue = Qt;
+ unbind_to (count, Qnil);
+ return tem;
+}
+
/* Load an autoloaded function.
FUNNAME is the symbol which is the function's name.
FUNDEF is the autoload definition (a list). */
@@ -1981,48 +2286,35 @@ If equal to `macro', MACRO-ONLY specifies that FUNDEF should only be loaded if
it defines a macro. */)
(Lisp_Object fundef, Lisp_Object funname, Lisp_Object macro_only)
{
- ptrdiff_t count = SPECPDL_INDEX ();
-
if (!CONSP (fundef) || !EQ (Qautoload, XCAR (fundef)))
return fundef;
- if (EQ (macro_only, Qmacro))
- {
- Lisp_Object kind = Fnth (make_number (4), fundef);
- if (! (EQ (kind, Qt) || EQ (kind, Qmacro)))
- return fundef;
- }
+ Lisp_Object kind = Fnth (make_fixnum (4), fundef);
+ if (EQ (macro_only, Qmacro)
+ && !(EQ (kind, Qt) || EQ (kind, Qmacro)))
+ return fundef;
/* This is to make sure that loadup.el gives a clear picture
of what files are preloaded and when. */
- if (! NILP (Vpurify_flag))
- error ("Attempt to autoload %s while preparing to dump",
- SDATA (SYMBOL_NAME (funname)));
+ if (will_dump_p () && !will_bootstrap_p ())
+ {
+ /* Avoid landing here recursively while outputting the
+ backtrace from the error. */
+ gflags.will_dump_ = false;
+ error ("Attempt to autoload %s while preparing to dump",
+ SDATA (SYMBOL_NAME (funname)));
+ }
CHECK_SYMBOL (funname);
- /* Preserve the match data. */
- record_unwind_save_match_data ();
-
- /* If autoloading gets an error (which includes the error of failing
- to define the function being called), we use Vautoload_queue
- to undo function definitions and `provide' calls made by
- the function. We do this in the specific case of autoloading
- because autoloading is not an explicit request "load this file",
- but rather a request to "call this function".
-
- The value saved here is to be restored into Vautoload_queue. */
- record_unwind_protect (un_autoload, Vautoload_queue);
- Vautoload_queue = Qt;
- /* If `macro_only', assume this autoload to be a "best-effort",
+ /* If `macro_only' is set and fundef isn't a macro, assume this autoload to
+ be a "best-effort" (e.g. to try and find a compiler macro),
so don't signal an error if autoloading fails. */
- Fload (Fcar (Fcdr (fundef)), macro_only, Qt, Qnil, Qt);
-
- /* Once loading finishes, don't undo it. */
- Vautoload_queue = Qt;
- unbind_to (count, Qnil);
+ Lisp_Object ignore_errors
+ = (EQ (kind, Qt) || EQ (kind, Qmacro)) ? Qnil : macro_only;
+ load_with_autoload_queue (Fcar (Fcdr (fundef)), ignore_errors, Qt, Qnil, Qt);
- if (NILP (funname))
+ if (NILP (funname) || !NILP (ignore_errors))
return Qnil;
else
{
@@ -2045,62 +2337,28 @@ LEXICAL can also be an actual lexical environment, in the form of an
alist mapping symbols to their value. */)
(Lisp_Object form, Lisp_Object lexical)
{
- ptrdiff_t count = SPECPDL_INDEX ();
+ specpdl_ref count = SPECPDL_INDEX ();
specbind (Qinternal_interpreter_environment,
CONSP (lexical) || NILP (lexical) ? lexical : list1 (Qt));
return unbind_to (count, eval_sub (form));
}
-/* Grow the specpdl stack by one entry.
- The caller should have already initialized the entry.
- Signal an error on stack overflow.
-
- Make sure that there is always one unused entry past the top of the
- stack, so that the just-initialized entry is safely unwound if
- memory exhausted and an error is signaled here. Also, allocate a
- never-used entry just before the bottom of the stack; sometimes its
- address is taken. */
-
-static void
-grow_specpdl (void)
-{
- specpdl_ptr++;
-
- if (specpdl_ptr == specpdl + specpdl_size)
- {
- ptrdiff_t count = SPECPDL_INDEX ();
- ptrdiff_t max_size = min (max_specpdl_size, PTRDIFF_MAX - 1000);
- union specbinding *pdlvec = specpdl - 1;
- ptrdiff_t pdlvecsize = specpdl_size + 1;
- if (max_size <= specpdl_size)
- {
- if (max_specpdl_size < 400)
- max_size = max_specpdl_size = 400;
- if (max_size <= specpdl_size)
- signal_error ("Variable binding depth exceeds max-specpdl-size",
- Qnil);
- }
- pdlvec = xpalloc (pdlvec, &pdlvecsize, 1, max_size + 1, sizeof *specpdl);
- specpdl = pdlvec + 1;
- specpdl_size = pdlvecsize - 1;
- specpdl_ptr = specpdl + count;
- }
-}
-
-ptrdiff_t
-record_in_backtrace (Lisp_Object function, Lisp_Object *args, ptrdiff_t nargs)
+void
+grow_specpdl_allocation (void)
{
- ptrdiff_t count = SPECPDL_INDEX ();
-
- eassert (nargs >= UNEVALLED);
- specpdl_ptr->bt.kind = SPECPDL_BACKTRACE;
- specpdl_ptr->bt.debug_on_exit = false;
- specpdl_ptr->bt.function = function;
- current_thread->stack_top = specpdl_ptr->bt.args = args;
- specpdl_ptr->bt.nargs = nargs;
- grow_specpdl ();
+ eassert (specpdl_ptr == specpdl_end);
- return count;
+ specpdl_ref count = SPECPDL_INDEX ();
+ ptrdiff_t max_size = PTRDIFF_MAX - 1000;
+ union specbinding *pdlvec = specpdl - 1;
+ ptrdiff_t size = specpdl_end - specpdl;
+ ptrdiff_t pdlvecsize = size + 1;
+ if (max_size <= size)
+ xsignal0 (Qexcessive_variable_binding); /* Can't happen, essentially. */
+ pdlvec = xpalloc (pdlvec, &pdlvecsize, 1, max_size + 1, sizeof *specpdl);
+ specpdl = pdlvec + 1;
+ specpdl_end = specpdl + pdlvecsize - 1;
+ specpdl_ptr = specpdl_ref_to_ptr (count);
}
/* Eval a sub-expression of the current expression (i.e. in the same
@@ -2108,27 +2366,16 @@ record_in_backtrace (Lisp_Object function, Lisp_Object *args, ptrdiff_t nargs)
Lisp_Object
eval_sub (Lisp_Object form)
{
- Lisp_Object fun, val, original_fun, original_args;
- Lisp_Object funcar;
- ptrdiff_t count;
-
- /* Declare here, as this array may be accessed by call_debugger near
- the end of this function. See Bug#21245. */
- Lisp_Object argvals[8];
-
if (SYMBOLP (form))
{
/* Look up its binding in the lexical environment.
We do not pay attention to the declared_special flag here, since we
already did that when let-binding the variable. */
Lisp_Object lex_binding
- = !NILP (Vinternal_interpreter_environment) /* Mere optimization! */
- ? Fassq (form, Vinternal_interpreter_environment)
- : Qnil;
- if (CONSP (lex_binding))
- return XCDR (lex_binding);
- else
- return Fsymbol_value (form);
+ = (!NILP (Vinternal_interpreter_environment) /* Mere optimization! */
+ ? Fassq (form, Vinternal_interpreter_environment)
+ : Qnil);
+ return !NILP (lex_binding) ? XCDR (lex_binding) : Fsymbol_value (form);
}
if (!CONSP (form))
@@ -2143,41 +2390,44 @@ eval_sub (Lisp_Object form)
if (max_lisp_eval_depth < 100)
max_lisp_eval_depth = 100;
if (lisp_eval_depth > max_lisp_eval_depth)
- error ("Lisp nesting exceeds `max-lisp-eval-depth'");
+ xsignal0 (Qexcessive_lisp_nesting);
}
- original_fun = XCAR (form);
- original_args = XCDR (form);
+ Lisp_Object original_fun = XCAR (form);
+ Lisp_Object original_args = XCDR (form);
CHECK_LIST (original_args);
/* This also protects them from gc. */
- count = record_in_backtrace (original_fun, &original_args, UNEVALLED);
+ specpdl_ref count
+ = record_in_backtrace (original_fun, &original_args, UNEVALLED);
if (debug_on_next_call)
do_debug_on_call (Qt, count);
- /* At this point, only original_fun and original_args
- have values that will be used below. */
+ Lisp_Object fun, val, funcar;
+ /* Declare here, as this array may be accessed by call_debugger near
+ the end of this function. See Bug#21245. */
+ Lisp_Object argvals[8];
+
retry:
/* Optimize for no indirection. */
fun = original_fun;
if (!SYMBOLP (fun))
- fun = Ffunction (Fcons (fun, Qnil));
- else if (!NILP (fun) && (fun = XSYMBOL (fun)->function, SYMBOLP (fun)))
+ fun = Ffunction (list1 (fun));
+ else if (!NILP (fun) && (fun = XSYMBOL (fun)->u.s.function, SYMBOLP (fun)))
fun = indirect_function (fun);
- if (SUBRP (fun))
+ if (SUBRP (fun) && !SUBR_NATIVE_COMPILED_DYNP (fun))
{
Lisp_Object args_left = original_args;
- Lisp_Object numargs = Flength (args_left);
-
- check_cons_list ();
+ ptrdiff_t numargs = list_length (args_left);
- if (XINT (numargs) < XSUBR (fun)->min_args
+ if (numargs < XSUBR (fun)->min_args
|| (XSUBR (fun)->max_args >= 0
- && XSUBR (fun)->max_args < XINT (numargs)))
- xsignal2 (Qwrong_number_of_arguments, original_fun, numargs);
+ && XSUBR (fun)->max_args < numargs))
+ xsignal2 (Qwrong_number_of_arguments, original_fun,
+ make_fixnum (numargs));
else if (XSUBR (fun)->max_args == UNEVALLED)
val = (XSUBR (fun)->function.aUNEVALLED) (args_left);
@@ -2188,23 +2438,22 @@ eval_sub (Lisp_Object form)
ptrdiff_t argnum = 0;
USE_SAFE_ALLOCA;
- SAFE_ALLOCA_LISP (vals, XINT (numargs));
+ SAFE_ALLOCA_LISP (vals, numargs);
- while (CONSP (args_left) && argnum < XINT (numargs))
+ while (CONSP (args_left) && argnum < numargs)
{
Lisp_Object arg = XCAR (args_left);
args_left = XCDR (args_left);
vals[argnum++] = eval_sub (arg);
}
- set_backtrace_args (specpdl + count, vals, argnum);
+ set_backtrace_args (specpdl_ref_to_ptr (count), vals, argnum);
val = XSUBR (fun)->function.aMANY (argnum, vals);
- check_cons_list ();
lisp_eval_depth--;
/* Do the debug-on-exit now, while VALS still exists. */
- if (backtrace_debug_on_exit (specpdl + count))
+ if (backtrace_debug_on_exit (specpdl_ref_to_ptr (count)))
val = call_debugger (list2 (Qexit, val));
SAFE_FREE ();
specpdl_ptr--;
@@ -2220,7 +2469,7 @@ eval_sub (Lisp_Object form)
args_left = Fcdr (args_left);
}
- set_backtrace_args (specpdl + count, argvals, XINT (numargs));
+ set_backtrace_args (specpdl_ref_to_ptr (count), argvals, numargs);
switch (i)
{
@@ -2272,7 +2521,9 @@ eval_sub (Lisp_Object form)
}
}
}
- else if (COMPILEDP (fun) || MODULE_FUNCTIONP (fun))
+ else if (COMPILEDP (fun)
+ || SUBR_NATIVE_COMPILED_DYNP (fun)
+ || MODULE_FUNCTIONP (fun))
return apply_lambda (fun, original_args, count);
else
{
@@ -2290,15 +2541,28 @@ eval_sub (Lisp_Object form)
}
if (EQ (funcar, Qmacro))
{
- ptrdiff_t count1 = SPECPDL_INDEX ();
+ specpdl_ref count1 = SPECPDL_INDEX ();
Lisp_Object exp;
/* Bind lexical-binding during expansion of the macro, so the
macro can know reliably if the code it outputs will be
interpreted using lexical-binding or not. */
specbind (Qlexical_binding,
NILP (Vinternal_interpreter_environment) ? Qnil : Qt);
+
+ /* Make the macro aware of any defvar declarations in scope. */
+ Lisp_Object dynvars = Vmacroexp__dynvars;
+ for (Lisp_Object p = Vinternal_interpreter_environment;
+ !NILP (p); p = XCDR(p))
+ {
+ Lisp_Object e = XCAR (p);
+ if (SYMBOLP (e))
+ dynvars = Fcons(e, dynvars);
+ }
+ if (!EQ (dynvars, Vmacroexp__dynvars))
+ specbind (Qmacroexp__dynvars, dynvars);
+
exp = apply1 (Fcdr (fun), original_args);
- unbind_to (count1, Qnil);
+ exp = unbind_to (count1, exp);
val = eval_sub (exp);
}
else if (EQ (funcar, Qlambda)
@@ -2307,10 +2571,9 @@ eval_sub (Lisp_Object form)
else
xsignal1 (Qinvalid_function, original_fun);
}
- check_cons_list ();
lisp_eval_depth--;
- if (backtrace_debug_on_exit (specpdl + count))
+ if (backtrace_debug_on_exit (specpdl_ref_to_ptr (count)))
val = call_debugger (list2 (Qexit, val));
specpdl_ptr--;
@@ -2320,23 +2583,22 @@ eval_sub (Lisp_Object form)
DEFUN ("apply", Fapply, Sapply, 1, MANY, 0,
doc: /* Call FUNCTION with our remaining args, using our last arg as list of args.
Then return the value FUNCTION returns.
+With a single argument, call the argument's first element using the
+other elements as args.
Thus, (apply \\='+ 1 2 \\='(3 4)) returns 10.
usage: (apply FUNCTION &rest ARGUMENTS) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
- ptrdiff_t i, numargs, funcall_nargs;
- register Lisp_Object *funcall_args = NULL;
- register Lisp_Object spread_arg = args[nargs - 1];
+ ptrdiff_t i, funcall_nargs;
+ Lisp_Object *funcall_args = NULL;
+ Lisp_Object spread_arg = args[nargs - 1];
Lisp_Object fun = args[0];
- Lisp_Object retval;
USE_SAFE_ALLOCA;
- CHECK_LIST (spread_arg);
-
- numargs = XINT (Flength (spread_arg));
+ ptrdiff_t numargs = list_length (spread_arg);
if (numargs == 0)
- return Ffuncall (nargs - 1, args);
+ return Ffuncall (max (1, nargs - 1), args);
else if (numargs == 1)
{
args [nargs - 1] = XCAR (spread_arg);
@@ -2347,7 +2609,7 @@ usage: (apply FUNCTION &rest ARGUMENTS) */)
/* Optimize for no indirection. */
if (SYMBOLP (fun) && !NILP (fun)
- && (fun = XSYMBOL (fun)->function, SYMBOLP (fun)))
+ && (fun = XSYMBOL (fun)->u.s.function, SYMBOLP (fun)))
{
fun = indirect_function (fun);
if (NILP (fun))
@@ -2383,7 +2645,7 @@ usage: (apply FUNCTION &rest ARGUMENTS) */)
spread_arg = XCDR (spread_arg);
}
- retval = Ffuncall (funcall_nargs, funcall_args);
+ Lisp_Object retval = Ffuncall (funcall_nargs, funcall_args);
SAFE_FREE ();
return retval;
@@ -2527,7 +2789,7 @@ run_hook_with_args (ptrdiff_t nargs, Lisp_Object *args,
sym = args[0];
val = find_symbol_value (sym);
- if (EQ (val, Qunbound) || NILP (val))
+ if (BASE_EQ (val, Qunbound) || NILP (val))
return ret;
else if (!CONSP (val) || FUNCTIONP (val))
{
@@ -2602,86 +2864,14 @@ apply1 (Lisp_Object fn, Lisp_Object arg)
return NILP (arg) ? Ffuncall (1, &fn) : CALLN (Fapply, fn, arg);
}
-/* Call function fn on no arguments. */
-Lisp_Object
-call0 (Lisp_Object fn)
-{
- return Ffuncall (1, &fn);
-}
-
-/* Call function fn with 1 argument arg1. */
-/* ARGSUSED */
-Lisp_Object
-call1 (Lisp_Object fn, Lisp_Object arg1)
-{
- return CALLN (Ffuncall, fn, arg1);
-}
-
-/* Call function fn with 2 arguments arg1, arg2. */
-/* ARGSUSED */
-Lisp_Object
-call2 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2)
-{
- return CALLN (Ffuncall, fn, arg1, arg2);
-}
-
-/* Call function fn with 3 arguments arg1, arg2, arg3. */
-/* ARGSUSED */
-Lisp_Object
-call3 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3)
-{
- return CALLN (Ffuncall, fn, arg1, arg2, arg3);
-}
-
-/* Call function fn with 4 arguments arg1, arg2, arg3, arg4. */
-/* ARGSUSED */
-Lisp_Object
-call4 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
- Lisp_Object arg4)
-{
- return CALLN (Ffuncall, fn, arg1, arg2, arg3, arg4);
-}
-
-/* Call function fn with 5 arguments arg1, arg2, arg3, arg4, arg5. */
-/* ARGSUSED */
-Lisp_Object
-call5 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
- Lisp_Object arg4, Lisp_Object arg5)
-{
- return CALLN (Ffuncall, fn, arg1, arg2, arg3, arg4, arg5);
-}
-
-/* Call function fn with 6 arguments arg1, arg2, arg3, arg4, arg5, arg6. */
-/* ARGSUSED */
-Lisp_Object
-call6 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
- Lisp_Object arg4, Lisp_Object arg5, Lisp_Object arg6)
-{
- return CALLN (Ffuncall, fn, arg1, arg2, arg3, arg4, arg5, arg6);
-}
-
-/* Call function fn with 7 arguments arg1, arg2, arg3, arg4, arg5, arg6, arg7. */
-/* ARGSUSED */
-Lisp_Object
-call7 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
- Lisp_Object arg4, Lisp_Object arg5, Lisp_Object arg6, Lisp_Object arg7)
-{
- return CALLN (Ffuncall, fn, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
-}
+DEFUN ("functionp", Ffunctionp, Sfunctionp, 1, 1, 0,
+ doc: /* Return t if OBJECT is a function.
-/* Call function fn with 8 arguments arg1, arg2, arg3, arg4, arg5,
- arg6, arg7, arg8. */
-/* ARGSUSED */
-Lisp_Object
-call8 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
- Lisp_Object arg4, Lisp_Object arg5, Lisp_Object arg6, Lisp_Object arg7,
- Lisp_Object arg8)
-{
- return CALLN (Ffuncall, fn, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
-}
+An object is a function if it is callable via `funcall'; this includes
+symbols with function bindings, but excludes macros and special forms.
-DEFUN ("functionp", Ffunctionp, Sfunctionp, 1, 1, 0,
- doc: /* Non-nil if OBJECT is a function. */)
+Ordinarily return nil if OBJECT is not a function, although t might be
+returned in rare cases. */)
(Lisp_Object object)
{
if (FUNCTIONP (object))
@@ -2720,6 +2910,44 @@ FUNCTIONP (Lisp_Object object)
return false;
}
+Lisp_Object
+funcall_general (Lisp_Object fun, ptrdiff_t numargs, Lisp_Object *args)
+{
+ Lisp_Object original_fun = fun;
+ retry:
+ if (SYMBOLP (fun) && !NILP (fun)
+ && (fun = XSYMBOL (fun)->u.s.function, SYMBOLP (fun)))
+ fun = indirect_function (fun);
+
+ if (SUBRP (fun) && !SUBR_NATIVE_COMPILED_DYNP (fun))
+ return funcall_subr (XSUBR (fun), numargs, args);
+ else if (COMPILEDP (fun)
+ || SUBR_NATIVE_COMPILED_DYNP (fun)
+ || MODULE_FUNCTIONP (fun))
+ return funcall_lambda (fun, numargs, args);
+ else
+ {
+ if (NILP (fun))
+ xsignal1 (Qvoid_function, original_fun);
+ if (!CONSP (fun))
+ xsignal1 (Qinvalid_function, original_fun);
+ Lisp_Object funcar = XCAR (fun);
+ if (!SYMBOLP (funcar))
+ xsignal1 (Qinvalid_function, original_fun);
+ if (EQ (funcar, Qlambda)
+ || EQ (funcar, Qclosure))
+ return funcall_lambda (fun, numargs, args);
+ else if (EQ (funcar, Qautoload))
+ {
+ Fautoload_do_load (fun, original_fun, Qnil);
+ fun = original_fun;
+ goto retry;
+ }
+ else
+ xsignal1 (Qinvalid_function, original_fun);
+ }
+}
+
DEFUN ("funcall", Ffuncall, Sfuncall, 1, MANY, 0,
doc: /* Call first argument as a function, passing remaining arguments to it.
Return the value that function returns.
@@ -2727,11 +2955,7 @@ Thus, (funcall \\='cons \\='x \\='y) returns (x . y).
usage: (funcall FUNCTION &rest ARGUMENTS) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
- Lisp_Object fun, original_fun;
- Lisp_Object funcar;
- ptrdiff_t numargs = nargs - 1;
- Lisp_Object val;
- ptrdiff_t count;
+ specpdl_ref count;
maybe_quit ();
@@ -2740,7 +2964,7 @@ usage: (funcall FUNCTION &rest ARGUMENTS) */)
if (max_lisp_eval_depth < 100)
max_lisp_eval_depth = 100;
if (lisp_eval_depth > max_lisp_eval_depth)
- error ("Lisp nesting exceeds `max-lisp-eval-depth'");
+ xsignal0 (Qexcessive_lisp_nesting);
}
count = record_in_backtrace (args[0], &args[1], nargs - 1);
@@ -2750,46 +2974,10 @@ usage: (funcall FUNCTION &rest ARGUMENTS) */)
if (debug_on_next_call)
do_debug_on_call (Qlambda, count);
- check_cons_list ();
-
- original_fun = args[0];
+ Lisp_Object val = funcall_general (args[0], nargs - 1, args + 1);
- retry:
-
- /* Optimize for no indirection. */
- fun = original_fun;
- if (SYMBOLP (fun) && !NILP (fun)
- && (fun = XSYMBOL (fun)->function, SYMBOLP (fun)))
- fun = indirect_function (fun);
-
- if (SUBRP (fun))
- val = funcall_subr (XSUBR (fun), numargs, args + 1);
- else if (COMPILEDP (fun) || MODULE_FUNCTIONP (fun))
- val = funcall_lambda (fun, numargs, args + 1);
- else
- {
- if (NILP (fun))
- xsignal1 (Qvoid_function, original_fun);
- if (!CONSP (fun))
- xsignal1 (Qinvalid_function, original_fun);
- funcar = XCAR (fun);
- if (!SYMBOLP (funcar))
- xsignal1 (Qinvalid_function, original_fun);
- if (EQ (funcar, Qlambda)
- || EQ (funcar, Qclosure))
- val = funcall_lambda (fun, numargs, args + 1);
- 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 + count))
+ if (backtrace_debug_on_exit (specpdl_ref_to_ptr (count)))
val = call_debugger (list2 (Qexit, val));
specpdl_ptr--;
return val;
@@ -2802,110 +2990,104 @@ usage: (funcall FUNCTION &rest ARGUMENTS) */)
Lisp_Object
funcall_subr (struct Lisp_Subr *subr, ptrdiff_t numargs, Lisp_Object *args)
{
- if (numargs < subr->min_args
- || (subr->max_args >= 0 && subr->max_args < numargs))
+ eassume (numargs >= 0);
+ if (numargs >= subr->min_args)
{
- Lisp_Object fun;
- XSETSUBR (fun, subr);
- xsignal2 (Qwrong_number_of_arguments, fun, make_number (numargs));
- }
+ /* Conforming call to finite-arity subr. */
+ if (numargs <= subr->max_args)
+ {
+ Lisp_Object argbuf[8];
+ Lisp_Object *a;
+ if (numargs < subr->max_args)
+ {
+ eassume (subr->max_args <= ARRAYELTS (argbuf));
+ a = argbuf;
+ memcpy (a, args, numargs * word_size);
+ memclear (a + numargs, (subr->max_args - numargs) * word_size);
+ }
+ else
+ a = args;
+ switch (subr->max_args)
+ {
+ case 0:
+ return subr->function.a0 ();
+ case 1:
+ return subr->function.a1 (a[0]);
+ case 2:
+ return subr->function.a2 (a[0], a[1]);
+ case 3:
+ return subr->function.a3 (a[0], a[1], a[2]);
+ case 4:
+ return subr->function.a4 (a[0], a[1], a[2], a[3]);
+ case 5:
+ return subr->function.a5 (a[0], a[1], a[2], a[3], a[4]);
+ case 6:
+ return subr->function.a6 (a[0], a[1], a[2], a[3], a[4], a[5]);
+ case 7:
+ return subr->function.a7 (a[0], a[1], a[2], a[3], a[4], a[5],
+ a[6]);
+ case 8:
+ return subr->function.a8 (a[0], a[1], a[2], a[3], a[4], a[5],
+ a[6], a[7]);
+ default:
+ /* If a subr takes more than 8 arguments without using MANY
+ or UNEVALLED, we need to extend this function to support it.
+ Until this is done, there is no way to call the function. */
+ emacs_abort ();
+ }
+ }
- else if (subr->max_args == UNEVALLED)
- {
- Lisp_Object fun;
- XSETSUBR (fun, subr);
- xsignal1 (Qinvalid_function, fun);
+ /* Call to n-adic subr. */
+ if (subr->max_args == MANY)
+ return subr->function.aMANY (numargs, args);
}
- else if (subr->max_args == MANY)
- return (subr->function.aMANY) (numargs, args);
+ /* Anything else is an error. */
+ Lisp_Object fun;
+ XSETSUBR (fun, subr);
+ if (subr->max_args == UNEVALLED)
+ xsignal1 (Qinvalid_function, fun);
else
- {
- Lisp_Object internal_argbuf[8];
- Lisp_Object *internal_args;
- if (subr->max_args > numargs)
- {
- eassert (subr->max_args <= ARRAYELTS (internal_argbuf));
- internal_args = internal_argbuf;
- memcpy (internal_args, args, numargs * word_size);
- memclear (internal_args + numargs,
- (subr->max_args - numargs) * word_size);
- }
- else
- internal_args = args;
- switch (subr->max_args)
- {
- case 0:
- return (subr->function.a0 ());
- case 1:
- return (subr->function.a1 (internal_args[0]));
- case 2:
- return (subr->function.a2
- (internal_args[0], internal_args[1]));
- case 3:
- return (subr->function.a3
- (internal_args[0], internal_args[1], internal_args[2]));
- case 4:
- return (subr->function.a4
- (internal_args[0], internal_args[1], internal_args[2],
- internal_args[3]));
- case 5:
- return (subr->function.a5
- (internal_args[0], internal_args[1], internal_args[2],
- internal_args[3], internal_args[4]));
- case 6:
- return (subr->function.a6
- (internal_args[0], internal_args[1], internal_args[2],
- internal_args[3], internal_args[4], internal_args[5]));
- case 7:
- return (subr->function.a7
- (internal_args[0], internal_args[1], internal_args[2],
- internal_args[3], internal_args[4], internal_args[5],
- internal_args[6]));
- case 8:
- return (subr->function.a8
- (internal_args[0], internal_args[1], internal_args[2],
- internal_args[3], internal_args[4], internal_args[5],
- internal_args[6], internal_args[7]));
-
- default:
-
- /* If a subr takes more than 8 arguments without using MANY
- or UNEVALLED, we need to extend this function to support it.
- Until this is done, there is no way to call the function. */
- emacs_abort ();
- }
- }
+ xsignal2 (Qwrong_number_of_arguments, fun, make_fixnum (numargs));
}
+/* Call the compiled Lisp function FUN. If we have not yet read FUN's
+ bytecode string and constants vector, fetch them from the file first. */
+
static Lisp_Object
-apply_lambda (Lisp_Object fun, Lisp_Object args, ptrdiff_t count)
+fetch_and_exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
+ ptrdiff_t nargs, Lisp_Object *args)
+{
+ if (CONSP (AREF (fun, COMPILED_BYTECODE)))
+ Ffetch_bytecode (fun);
+
+ return exec_byte_code (fun, args_template, nargs, args);
+}
+
+static Lisp_Object
+apply_lambda (Lisp_Object fun, Lisp_Object args, specpdl_ref count)
{
- Lisp_Object args_left;
- ptrdiff_t i;
- EMACS_INT numargs;
Lisp_Object *arg_vector;
Lisp_Object tem;
USE_SAFE_ALLOCA;
- numargs = XFASTINT (Flength (args));
+ ptrdiff_t numargs = list_length (args);
SAFE_ALLOCA_LISP (arg_vector, numargs);
- args_left = args;
+ Lisp_Object args_left = args;
- for (i = 0; i < numargs; )
+ for (ptrdiff_t i = 0; i < numargs; i++)
{
tem = Fcar (args_left), args_left = Fcdr (args_left);
tem = eval_sub (tem);
- arg_vector[i++] = tem;
+ arg_vector[i] = tem;
}
- set_backtrace_args (specpdl + count, arg_vector, i);
+ set_backtrace_args (specpdl_ref_to_ptr (count), arg_vector, numargs);
tem = funcall_lambda (fun, numargs, arg_vector);
- check_cons_list ();
lisp_eval_depth--;
/* Do the debug-on-exit now, while arg_vector still exists. */
- if (backtrace_debug_on_exit (specpdl + count))
+ if (backtrace_debug_on_exit (specpdl_ref_to_ptr (count)))
tem = call_debugger (list2 (Qexit, tem));
SAFE_FREE ();
specpdl_ptr--;
@@ -2922,7 +3104,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
register Lisp_Object *arg_vector)
{
Lisp_Object val, syms_left, next, lexenv;
- ptrdiff_t count = SPECPDL_INDEX ();
+ specpdl_ref count = SPECPDL_INDEX ();
ptrdiff_t i;
bool optional, rest;
@@ -2946,41 +3128,34 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
}
else if (COMPILEDP (fun))
{
- ptrdiff_t size = PVSIZE (fun);
- if (size <= COMPILED_STACK_DEPTH)
- xsignal1 (Qinvalid_function, fun);
syms_left = AREF (fun, COMPILED_ARGLIST);
- if (INTEGERP (syms_left))
- /* A byte-code object with an integer args template means we
- shouldn't bind any arguments, instead just call the byte-code
- interpreter directly; it will push arguments as necessary.
-
- Byte-code objects with a nil args template (the default)
- have dynamically-bound arguments, and use the
- argument-binding code below instead (as do all interpreted
- functions, even lexically bound ones). */
- {
- /* If we have not actually read the bytecode string
- and constants vector yet, fetch them from the file. */
- if (CONSP (AREF (fun, COMPILED_BYTECODE)))
- Ffetch_bytecode (fun);
- return exec_byte_code (AREF (fun, COMPILED_BYTECODE),
- AREF (fun, COMPILED_CONSTANTS),
- AREF (fun, COMPILED_STACK_DEPTH),
- syms_left,
- nargs, arg_vector);
- }
+ /* Bytecode objects using lexical binding have an integral
+ ARGLIST slot value: pass the arguments to the byte-code
+ engine directly. */
+ if (FIXNUMP (syms_left))
+ return fetch_and_exec_byte_code (fun, XFIXNUM (syms_left),
+ nargs, arg_vector);
+ /* Otherwise the bytecode object uses dynamic binding and the
+ ARGLIST slot contains a standard formal argument list whose
+ variables are bound dynamically below. */
lexenv = Qnil;
}
#ifdef HAVE_MODULES
else if (MODULE_FUNCTIONP (fun))
return funcall_module (fun, nargs, arg_vector);
#endif
+#ifdef HAVE_NATIVE_COMP
+ else if (SUBR_NATIVE_COMPILED_DYNP (fun))
+ {
+ syms_left = XSUBR (fun)->lambda_list;
+ lexenv = Qnil;
+ }
+#endif
else
emacs_abort ();
i = optional = rest = 0;
- bool previous_optional_or_rest = false;
+ bool previous_rest = false;
for (; CONSP (syms_left); syms_left = XCDR (syms_left))
{
maybe_quit ();
@@ -2991,17 +3166,16 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
if (EQ (next, Qand_rest))
{
- if (rest || previous_optional_or_rest)
+ if (rest || previous_rest)
xsignal1 (Qinvalid_function, fun);
rest = 1;
- previous_optional_or_rest = true;
+ previous_rest = true;
}
else if (EQ (next, Qand_optional))
{
- if (optional || rest || previous_optional_or_rest)
+ if (optional || rest || previous_rest)
xsignal1 (Qinvalid_function, fun);
optional = 1;
- previous_optional_or_rest = true;
}
else
{
@@ -3014,7 +3188,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
else if (i < nargs)
arg = arg_vector[i++];
else if (!optional)
- xsignal2 (Qwrong_number_of_arguments, fun, make_number (nargs));
+ xsignal2 (Qwrong_number_of_arguments, fun, make_fixnum (nargs));
else
arg = Qnil;
@@ -3025,14 +3199,14 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
else
/* Dynamically bind NEXT. */
specbind (next, arg);
- previous_optional_or_rest = false;
+ previous_rest = false;
}
}
- if (!NILP (syms_left) || previous_optional_or_rest)
+ if (!NILP (syms_left) || previous_rest)
xsignal1 (Qinvalid_function, fun);
else if (i < nargs)
- xsignal2 (Qwrong_number_of_arguments, fun, make_number (nargs));
+ xsignal2 (Qwrong_number_of_arguments, fun, make_fixnum (nargs));
if (!EQ (lexenv, Vinternal_interpreter_environment))
/* Instantiate a new lexical environment. */
@@ -3040,17 +3214,15 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
if (CONSP (fun))
val = Fprogn (XCDR (XCDR (fun)));
- else
+ else if (SUBR_NATIVE_COMPILEDP (fun))
{
- /* If we have not actually read the bytecode string
- and constants vector yet, fetch them from the file. */
- if (CONSP (AREF (fun, COMPILED_BYTECODE)))
- Ffetch_bytecode (fun);
- val = exec_byte_code (AREF (fun, COMPILED_BYTECODE),
- AREF (fun, COMPILED_CONSTANTS),
- AREF (fun, COMPILED_STACK_DEPTH),
- Qnil, 0, 0);
+ eassert (SUBR_NATIVE_COMPILED_DYNP (fun));
+ /* No need to use funcall_subr as we have zero arguments by
+ construction. */
+ val = XSUBR (fun)->function.a0 ();
}
+ else
+ val = fetch_and_exec_byte_code (fun, 0, 0, NULL);
return unbind_to (count, val);
}
@@ -3075,7 +3247,7 @@ function with `&rest' args, or `unevalled' for a special form. */)
function = original;
if (SYMBOLP (function) && !NILP (function))
{
- function = XSYMBOL (function)->function;
+ function = XSYMBOL (function)->u.s.function;
if (SYMBOLP (function))
function = indirect_function (function);
}
@@ -3135,11 +3307,8 @@ lambda_arity (Lisp_Object fun)
}
else if (COMPILEDP (fun))
{
- ptrdiff_t size = PVSIZE (fun);
- if (size <= COMPILED_STACK_DEPTH)
- xsignal1 (Qinvalid_function, fun);
syms_left = AREF (fun, COMPILED_ARGLIST);
- if (INTEGERP (syms_left))
+ if (FIXNUMP (syms_left))
return get_byte_code_arity (syms_left);
}
else
@@ -3154,7 +3323,7 @@ lambda_arity (Lisp_Object fun)
xsignal1 (Qinvalid_function, fun);
if (EQ (next, Qand_rest))
- return Fcons (make_number (minargs), Qmany);
+ return Fcons (make_fixnum (minargs), Qmany);
else if (EQ (next, Qand_optional))
optional = true;
else
@@ -3168,7 +3337,7 @@ lambda_arity (Lisp_Object fun)
if (!NILP (syms_left))
xsignal1 (Qinvalid_function, fun);
- return Fcons (make_number (minargs), make_number (maxargs));
+ return Fcons (make_fixnum (minargs), make_fixnum (maxargs));
}
DEFUN ("fetch-bytecode", Ffetch_bytecode, Sfetch_bytecode,
@@ -3180,13 +3349,11 @@ DEFUN ("fetch-bytecode", Ffetch_bytecode, Sfetch_bytecode,
if (COMPILEDP (object))
{
- ptrdiff_t size = PVSIZE (object);
- if (size <= COMPILED_STACK_DEPTH)
- xsignal1 (Qinvalid_function, object);
if (CONSP (AREF (object, COMPILED_BYTECODE)))
{
tem = read_doc_string (AREF (object, COMPILED_BYTECODE));
- if (!CONSP (tem))
+ if (! (CONSP (tem) && STRINGP (XCAR (tem))
+ && VECTORP (XCDR (tem))))
{
tem = AREF (object, COMPILED_BYTECODE);
if (CONSP (tem) && STRINGP (XCAR (tem)))
@@ -3194,7 +3361,20 @@ DEFUN ("fetch-bytecode", Ffetch_bytecode, Sfetch_bytecode,
else
error ("Invalid byte code");
}
- ASET (object, COMPILED_BYTECODE, XCAR (tem));
+
+ Lisp_Object bytecode = XCAR (tem);
+ if (STRING_MULTIBYTE (bytecode))
+ {
+ /* BYTECODE must have been produced by Emacs 20.2 or earlier
+ because it produced a raw 8-bit string for byte-code and now
+ such a byte-code string is loaded as multibyte with raw 8-bit
+ characters converted to multibyte form. Convert them back to
+ the original unibyte form. */
+ bytecode = Fstring_as_unibyte (bytecode);
+ }
+
+ pin_string (bytecode);
+ ASET (object, COMPILED_BYTECODE, bytecode);
ASET (object, COMPILED_CONSTANTS, XCDR (tem));
}
}
@@ -3214,7 +3394,7 @@ let_shadows_buffer_binding_p (struct Lisp_Symbol *symbol)
if ((--p)->kind > SPECPDL_LET)
{
struct Lisp_Symbol *let_bound_symbol = XSYMBOL (specpdl_symbol (p));
- eassert (let_bound_symbol->redirect != SYMBOL_VARALIAS);
+ eassert (let_bound_symbol->u.s.redirect != SYMBOL_VARALIAS);
if (symbol == let_bound_symbol
&& EQ (specpdl_where (p), buf))
return 1;
@@ -3227,10 +3407,10 @@ static void
do_specbind (struct Lisp_Symbol *sym, union specbinding *bind,
Lisp_Object value, enum Set_Internal_Bind bindflag)
{
- switch (sym->redirect)
+ switch (sym->u.s.redirect)
{
case SYMBOL_PLAINVAL:
- if (!sym->trapped_write)
+ if (!sym->u.s.trapped_write)
SET_SYMBOL_VAL (sym, value);
else
set_internal (specpdl_symbol (bind), value, Qnil, bindflag);
@@ -3274,7 +3454,7 @@ specbind (Lisp_Object symbol, Lisp_Object value)
sym = XSYMBOL (symbol);
start:
- switch (sym->redirect)
+ switch (sym->u.s.redirect)
{
case SYMBOL_VARALIAS:
sym = indirect_variable (sym); XSETSYMBOL (symbol, sym); goto start;
@@ -3284,9 +3464,6 @@ specbind (Lisp_Object symbol, Lisp_Object value)
specpdl_ptr->let.kind = SPECPDL_LET;
specpdl_ptr->let.symbol = symbol;
specpdl_ptr->let.old_value = SYMBOL_VAL (sym);
- specpdl_ptr->let.saved_value = Qnil;
- grow_specpdl ();
- do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
break;
case SYMBOL_LOCALIZED:
case SYMBOL_FORWARDED:
@@ -3296,12 +3473,11 @@ specbind (Lisp_Object symbol, Lisp_Object value)
specpdl_ptr->let.symbol = symbol;
specpdl_ptr->let.old_value = ovalue;
specpdl_ptr->let.where = Fcurrent_buffer ();
- specpdl_ptr->let.saved_value = Qnil;
- eassert (sym->redirect != SYMBOL_LOCALIZED
- || (EQ (SYMBOL_BLV (sym)->where, Fcurrent_buffer ())));
+ eassert (sym->u.s.redirect != SYMBOL_LOCALIZED
+ || (BASE_EQ (SYMBOL_BLV (sym)->where, Fcurrent_buffer ())));
- if (sym->redirect == SYMBOL_LOCALIZED)
+ if (sym->u.s.redirect == SYMBOL_LOCALIZED)
{
if (!blv_found (SYMBOL_BLV (sym)))
specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT;
@@ -3314,22 +3490,17 @@ specbind (Lisp_Object symbol, Lisp_Object value)
having their own value. This is consistent with what
happens with other buffer-local variables. */
if (NILP (Flocal_variable_p (symbol, Qnil)))
- {
- specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT;
- grow_specpdl ();
- do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
- return;
- }
+ specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT;
}
else
specpdl_ptr->let.kind = SPECPDL_LET;
- grow_specpdl ();
- do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
break;
}
default: emacs_abort ();
}
+ grow_specpdl ();
+ do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
}
/* Push unwind-protect entries of various types. */
@@ -3340,6 +3511,16 @@ record_unwind_protect (void (*function) (Lisp_Object), Lisp_Object arg)
specpdl_ptr->unwind.kind = SPECPDL_UNWIND;
specpdl_ptr->unwind.func = function;
specpdl_ptr->unwind.arg = arg;
+ specpdl_ptr->unwind.eval_depth = lisp_eval_depth;
+ grow_specpdl ();
+}
+
+void
+record_unwind_protect_array (Lisp_Object *array, ptrdiff_t nelts)
+{
+ specpdl_ptr->unwind_array.kind = SPECPDL_UNWIND_ARRAY;
+ specpdl_ptr->unwind_array.array = array;
+ specpdl_ptr->unwind_array.nelts = nelts;
grow_specpdl ();
}
@@ -3349,6 +3530,20 @@ record_unwind_protect_ptr (void (*function) (void *), void *arg)
specpdl_ptr->unwind_ptr.kind = SPECPDL_UNWIND_PTR;
specpdl_ptr->unwind_ptr.func = function;
specpdl_ptr->unwind_ptr.arg = arg;
+ specpdl_ptr->unwind_ptr.mark = NULL;
+ grow_specpdl ();
+}
+
+/* Like `record_unwind_protect_ptr', but also specifies a function
+ for GC-marking Lisp objects only reachable through ARG. */
+void
+record_unwind_protect_ptr_mark (void (*function) (void *), void *arg,
+ void (*mark) (void *))
+{
+ specpdl_ptr->unwind_ptr.kind = SPECPDL_UNWIND_PTR;
+ specpdl_ptr->unwind_ptr.func = function;
+ specpdl_ptr->unwind_ptr.arg = arg;
+ specpdl_ptr->unwind_ptr.mark = mark;
grow_specpdl ();
}
@@ -3362,6 +3557,23 @@ record_unwind_protect_int (void (*function) (int), int arg)
}
void
+record_unwind_protect_intmax (void (*function) (intmax_t), intmax_t arg)
+{
+ specpdl_ptr->unwind_intmax.kind = SPECPDL_UNWIND_INTMAX;
+ specpdl_ptr->unwind_intmax.func = function;
+ specpdl_ptr->unwind_intmax.arg = arg;
+ grow_specpdl ();
+}
+
+void
+record_unwind_protect_excursion (void)
+{
+ specpdl_ptr->unwind_excursion.kind = SPECPDL_UNWIND_EXCURSION;
+ save_excursion_save (specpdl_ptr);
+ grow_specpdl ();
+}
+
+void
record_unwind_protect_void (void (*function) (void))
{
specpdl_ptr->unwind_void.kind = SPECPDL_UNWIND_VOID;
@@ -3370,21 +3582,13 @@ record_unwind_protect_void (void (*function) (void))
}
void
-rebind_for_thread_switch (void)
+record_unwind_protect_module (enum specbind_tag kind, void *ptr)
{
- union specbinding *bind;
-
- for (bind = specpdl; bind != specpdl_ptr; ++bind)
- {
- if (bind->kind >= SPECPDL_LET)
- {
- Lisp_Object value = specpdl_saved_value (bind);
- Lisp_Object sym = specpdl_symbol (bind);
- bind->let.saved_value = Qnil;
- do_specbind (XSYMBOL (sym), bind, value,
- SET_INTERNAL_THREAD_SWITCH);
- }
- }
+ specpdl_ptr->kind = kind;
+ specpdl_ptr->unwind_ptr.func = NULL;
+ specpdl_ptr->unwind_ptr.arg = ptr;
+ specpdl_ptr->unwind_ptr.mark = NULL;
+ grow_specpdl ();
}
static void
@@ -3395,26 +3599,46 @@ do_one_unbind (union specbinding *this_binding, bool unwinding,
switch (this_binding->kind)
{
case SPECPDL_UNWIND:
+ lisp_eval_depth = this_binding->unwind.eval_depth;
this_binding->unwind.func (this_binding->unwind.arg);
break;
+ case SPECPDL_UNWIND_ARRAY:
+ xfree (this_binding->unwind_array.array);
+ break;
case SPECPDL_UNWIND_PTR:
this_binding->unwind_ptr.func (this_binding->unwind_ptr.arg);
break;
case SPECPDL_UNWIND_INT:
this_binding->unwind_int.func (this_binding->unwind_int.arg);
break;
+ case SPECPDL_UNWIND_INTMAX:
+ this_binding->unwind_intmax.func (this_binding->unwind_intmax.arg);
+ break;
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:
+ case SPECPDL_NOP:
+ break;
+#ifdef HAVE_MODULES
+ case SPECPDL_MODULE_RUNTIME:
+ finalize_runtime_unwind (this_binding->unwind_ptr.arg);
+ break;
+ case SPECPDL_MODULE_ENVIRONMENT:
+ finalize_environment_unwind (this_binding->unwind_ptr.arg);
break;
+#endif
case SPECPDL_LET:
{ /* If variable has a trivial value (no forwarding), and isn't
trapped, we can just set it. */
Lisp_Object sym = specpdl_symbol (this_binding);
- if (SYMBOLP (sym) && XSYMBOL (sym)->redirect == SYMBOL_PLAINVAL)
+ if (SYMBOLP (sym) && XSYMBOL (sym)->u.s.redirect == SYMBOL_PLAINVAL)
{
- if (XSYMBOL (sym)->trapped_write == SYMBOL_UNTRAPPED_WRITE)
+ if (XSYMBOL (sym)->u.s.trapped_write == SYMBOL_UNTRAPPED_WRITE)
SET_SYMBOL_VAL (XSYMBOL (sym), specpdl_old_value (this_binding));
else
set_internal (sym, specpdl_old_value (this_binding),
@@ -3463,9 +3687,9 @@ record_unwind_protect_nothing (void)
It need not be at the top of the stack. */
void
-clear_unwind_protect (ptrdiff_t count)
+clear_unwind_protect (specpdl_ref count)
{
- union specbinding *p = specpdl + count;
+ union specbinding *p = specpdl_ref_to_ptr (count);
p->unwind_void.kind = SPECPDL_UNWIND_VOID;
p->unwind_void.func = do_nothing;
}
@@ -3475,35 +3699,37 @@ clear_unwind_protect (ptrdiff_t count)
previous value without invoking it. */
void
-set_unwind_protect (ptrdiff_t count, void (*func) (Lisp_Object),
+set_unwind_protect (specpdl_ref count, void (*func) (Lisp_Object),
Lisp_Object arg)
{
- union specbinding *p = specpdl + count;
+ union specbinding *p = specpdl_ref_to_ptr (count);
p->unwind.kind = SPECPDL_UNWIND;
p->unwind.func = func;
p->unwind.arg = arg;
+ p->unwind.eval_depth = lisp_eval_depth;
}
void
-set_unwind_protect_ptr (ptrdiff_t count, void (*func) (void *), void *arg)
+set_unwind_protect_ptr (specpdl_ref count, void (*func) (void *), void *arg)
{
- union specbinding *p = specpdl + count;
+ union specbinding *p = specpdl_ref_to_ptr (count);
p->unwind_ptr.kind = SPECPDL_UNWIND_PTR;
p->unwind_ptr.func = func;
p->unwind_ptr.arg = arg;
+ p->unwind_ptr.mark = NULL;
}
/* Pop and execute entries from the unwind-protect stack until the
depth COUNT is reached. Return VALUE. */
Lisp_Object
-unbind_to (ptrdiff_t count, Lisp_Object value)
+unbind_to (specpdl_ref count, Lisp_Object value)
{
Lisp_Object quitf = Vquit_flag;
Vquit_flag = Qnil;
- while (specpdl_ptr != specpdl + count)
+ while (specpdl_ptr != specpdl_ref_to_ptr (count))
{
/* Copy the binding, and decrement specpdl_ptr, before we do
the work to unbind it. We decrement first
@@ -3523,22 +3749,6 @@ unbind_to (ptrdiff_t count, Lisp_Object value)
return value;
}
-void
-unbind_for_thread_switch (struct thread_state *thr)
-{
- union specbinding *bind;
-
- for (bind = thr->m_specpdl_ptr; bind > thr->m_specpdl;)
- {
- if ((--bind)->kind >= SPECPDL_LET)
- {
- Lisp_Object sym = specpdl_symbol (bind);
- bind->let.saved_value = find_symbol_value (sym);
- do_one_unbind (bind, false, SET_INTERNAL_THREAD_SWITCH);
- }
- }
-}
-
DEFUN ("special-variable-p", Fspecial_variable_p, Sspecial_variable_p, 1, 1, 0,
doc: /* Return non-nil if SYMBOL's global binding has been declared special.
A special variable is one that will be bound dynamically, even in a
@@ -3546,7 +3756,7 @@ context where binding is lexical by default. */)
(Lisp_Object symbol)
{
CHECK_SYMBOL (symbol);
- return XSYMBOL (symbol)->declared_special ? Qt : Qnil;
+ return XSYMBOL (symbol)->u.s.declared_special ? Qt : Qnil;
}
@@ -3571,11 +3781,11 @@ get_backtrace_frame (Lisp_Object nframes, Lisp_Object base)
{
register EMACS_INT i;
- CHECK_NATNUM (nframes);
+ CHECK_FIXNAT (nframes);
union specbinding *pdl = get_backtrace_starting_at (base);
/* Find the frame requested. */
- for (i = XFASTINT (nframes); i > 0 && backtrace_p (pdl); i--)
+ for (i = XFIXNAT (nframes); i > 0 && backtrace_p (pdl); i--)
pdl = backtrace_next (pdl);
return pdl;
@@ -3589,7 +3799,7 @@ backtrace_frame_apply (Lisp_Object function, union specbinding *pdl)
Lisp_Object flags = Qnil;
if (backtrace_debug_on_exit (pdl))
- flags = Fcons (QCdebug_on_exit, Fcons (Qt, Qnil));
+ flags = list2 (QCdebug_on_exit, Qt);
if (backtrace_nargs (pdl) == UNEVALLED)
return call4 (function, Qnil, backtrace_function (pdl), *backtrace_args (pdl), flags);
@@ -3605,7 +3815,7 @@ DEFUN ("backtrace-debug", Fbacktrace_debug, Sbacktrace_debug, 2, 2, 0,
The debugger is entered when that frame exits, if the flag is non-nil. */)
(Lisp_Object level, Lisp_Object flag)
{
- CHECK_NUMBER (level);
+ CHECK_FIXNUM (level);
union specbinding *pdl = get_backtrace_frame(level, Qnil);
if (backtrace_p (pdl))
@@ -3652,17 +3862,55 @@ Return the result of FUNCTION, or nil if no matching frame could be found. */)
return backtrace_frame_apply (function, get_backtrace_frame (nframes, base));
}
+DEFUN ("backtrace--frames-from-thread", Fbacktrace_frames_from_thread,
+ Sbacktrace_frames_from_thread, 1, 1, NULL,
+ doc: /* Return the list of backtrace frames from current execution point in THREAD.
+If a frame has not evaluated the arguments yet (or is a special form),
+the value of the list element is (nil FUNCTION ARG-FORMS...).
+If a frame has evaluated its arguments and called its function already,
+the value of the list element is (t FUNCTION ARG-VALUES...).
+A &rest arg is represented as the tail of the list ARG-VALUES.
+FUNCTION is whatever was supplied as car of evaluated list,
+or a lambda expression for macro calls. */)
+ (Lisp_Object thread)
+{
+ struct thread_state *tstate;
+ CHECK_THREAD (thread);
+ tstate = XTHREAD (thread);
+
+ union specbinding *pdl = backtrace_thread_top (tstate);
+ Lisp_Object list = Qnil;
+
+ while (backtrace_thread_p (tstate, pdl))
+ {
+ Lisp_Object frame;
+ if (backtrace_nargs (pdl) == UNEVALLED)
+ frame = Fcons (Qnil,
+ Fcons (backtrace_function (pdl), *backtrace_args (pdl)));
+ else
+ {
+ Lisp_Object tem = Flist (backtrace_nargs (pdl), backtrace_args (pdl));
+ frame = Fcons (Qt, Fcons (backtrace_function (pdl), tem));
+ }
+ list = Fcons (frame, list);
+ pdl = backtrace_thread_next (tstate, pdl);
+ }
+ return Fnreverse (list);
+}
+
/* For backtrace-eval, we want to temporarily unwind the last few elements of
the specpdl stack, and then rewind them. We store the pre-unwind values
directly in the pre-existing specpdl elements (i.e. we swap the current
value and the old value stored in the specpdl), kind of like the inplace
pointer-reversal trick. As it turns out, the rewind does the same as the
unwind, except it starts from the other end of the specpdl stack, so we use
- the same function for both unwind and rewind. */
-static void
-backtrace_eval_unrewind (int distance)
+ the same function for both unwind and rewind.
+ This same code is used when switching threads, except in that case
+ we unwind/rewind the whole specpdl of the threads. */
+void
+specpdl_unrewind (union specbinding *pdl, int distance, bool vars_only)
{
- union specbinding *tmp = specpdl_ptr;
+ union specbinding *tmp = pdl;
int step = -1;
if (distance < 0)
{ /* It's a rewind rather than unwind. */
@@ -3680,29 +3928,32 @@ 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 (vars_only)
+ break;
+ 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);
+ set_buffer_if_live (oldarg);
+ }
+ break;
+ case SPECPDL_UNWIND_EXCURSION:
+ if (vars_only)
break;
+ {
+ Lisp_Object marker = tmp->unwind_excursion.marker;
+ Lisp_Object window = tmp->unwind_excursion.window;
+ save_excursion_save (tmp);
+ save_excursion_restore (marker, window);
}
-
- case SPECPDL_UNWIND_PTR:
- case SPECPDL_UNWIND_INT:
- case SPECPDL_UNWIND_VOID:
- case SPECPDL_BACKTRACE:
break;
case SPECPDL_LET:
{ /* If variable has a trivial value (no forwarding), we can
just set it. No need to check for constant symbols here,
since that was already done by specbind. */
Lisp_Object sym = specpdl_symbol (tmp);
- if (SYMBOLP (sym) && XSYMBOL (sym)->redirect == SYMBOL_PLAINVAL)
+ if (SYMBOLP (sym)
+ && XSYMBOL (sym)->u.s.redirect == SYMBOL_PLAINVAL)
{
Lisp_Object old_value = specpdl_old_value (tmp);
set_specpdl_old_value (tmp, SYMBOL_VAL (XSYMBOL (sym)));
@@ -3717,8 +3968,8 @@ backtrace_eval_unrewind (int distance)
{
Lisp_Object sym = specpdl_symbol (tmp);
Lisp_Object old_value = specpdl_old_value (tmp);
- set_specpdl_old_value (tmp, Fdefault_value (sym));
- Fset_default (sym, old_value);
+ set_specpdl_old_value (tmp, default_value (sym));
+ set_default_internal (sym, old_value, SET_INTERNAL_THREAD_SWITCH);
}
break;
case SPECPDL_LET_LOCAL:
@@ -3733,22 +3984,38 @@ backtrace_eval_unrewind (int distance)
if (!NILP (Flocal_variable_p (symbol, where)))
{
set_specpdl_old_value
- (tmp, Fbuffer_local_value (symbol, where));
- set_internal (symbol, old_value, where, SET_INTERNAL_UNBIND);
+ (tmp, buffer_local_value (symbol, where));
+ set_internal (symbol, old_value, where,
+ SET_INTERNAL_THREAD_SWITCH);
}
+ else
+ /* If the var is not local any more, it can't be undone nor
+ redone, so just zap it.
+ This is important in case the buffer re-gains a local value
+ before we unrewind again, in which case we'd risk applying
+ this entry in the wrong direction. */
+ tmp->kind = SPECPDL_NOP;
}
break;
+
+ default: break;
}
}
}
+static void
+backtrace_eval_unrewind (int distance)
+{
+ specpdl_unrewind (specpdl_ptr, distance, false);
+}
+
DEFUN ("backtrace-eval", Fbacktrace_eval, Sbacktrace_eval, 2, 3, NULL,
doc: /* Evaluate EXP in the context of some activation frame.
NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'. */)
(Lisp_Object exp, Lisp_Object nframes, Lisp_Object base)
{
union specbinding *pdl = get_backtrace_frame (nframes, base);
- ptrdiff_t count = SPECPDL_INDEX ();
+ specpdl_ref count = SPECPDL_INDEX ();
ptrdiff_t distance = specpdl_ptr - pdl;
eassert (distance >= 0);
@@ -3771,7 +4038,7 @@ NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'.
{
union specbinding *frame = get_backtrace_frame (nframes, base);
union specbinding *prevframe
- = get_backtrace_frame (make_number (XFASTINT (nframes) - 1), base);
+ = get_backtrace_frame (make_fixnum (XFIXNAT (nframes) - 1), base);
ptrdiff_t distance = specpdl_ptr - frame;
Lisp_Object result = Qnil;
eassert (distance >= 0);
@@ -3822,15 +4089,7 @@ NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'.
}
break;
- case SPECPDL_UNWIND:
- case SPECPDL_UNWIND_PTR:
- case SPECPDL_UNWIND_INT:
- case SPECPDL_UNWIND_VOID:
- case SPECPDL_BACKTRACE:
- break;
-
- default:
- emacs_abort ();
+ default: break;
}
}
}
@@ -3849,22 +4108,38 @@ mark_specpdl (union specbinding *first, union specbinding *ptr)
for (pdl = first; pdl != ptr; pdl++)
{
switch (pdl->kind)
- {
+ {
case SPECPDL_UNWIND:
mark_object (specpdl_arg (pdl));
break;
+ case SPECPDL_UNWIND_ARRAY:
+ mark_objects (pdl->unwind_array.array, pdl->unwind_array.nelts);
+ 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);
mark_object (backtrace_function (pdl));
if (nargs == UNEVALLED)
nargs = 1;
- while (nargs--)
- mark_object (backtrace_args (pdl)[nargs]);
+ mark_objects (backtrace_args (pdl), nargs);
}
break;
+#ifdef HAVE_MODULES
+ case SPECPDL_MODULE_RUNTIME:
+ break;
+ case SPECPDL_MODULE_ENVIRONMENT:
+ mark_module_environment (pdl->unwind_ptr.arg);
+ break;
+#endif
+
case SPECPDL_LET_DEFAULT:
case SPECPDL_LET_LOCAL:
mark_object (specpdl_where (pdl));
@@ -3872,14 +4147,22 @@ mark_specpdl (union specbinding *first, union specbinding *ptr)
case SPECPDL_LET:
mark_object (specpdl_symbol (pdl));
mark_object (specpdl_old_value (pdl));
- mark_object (specpdl_saved_value (pdl));
break;
case SPECPDL_UNWIND_PTR:
+ if (pdl->unwind_ptr.mark)
+ pdl->unwind_ptr.mark (pdl->unwind_ptr.arg);
+ break;
+
case SPECPDL_UNWIND_INT:
- case SPECPDL_UNWIND_VOID:
+ case SPECPDL_UNWIND_INTMAX:
+ case SPECPDL_UNWIND_VOID:
+ case SPECPDL_NOP:
break;
+ /* While other loops that scan the specpdl use "default: break;"
+ for simplicity, here we explicitly list all cases and abort
+ if we find an unexpected value, as a sanity check. */
default:
emacs_abort ();
}
@@ -3914,16 +4197,6 @@ Lisp_Object backtrace_top_function (void)
void
syms_of_eval (void)
{
- DEFVAR_INT ("max-specpdl-size", max_specpdl_size,
- doc: /* Limit on number of Lisp variable bindings and `unwind-protect's.
-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.
-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.
@@ -3967,6 +4240,7 @@ before making `inhibit-quit' nil. */);
DEFSYM (Qclosure, "closure");
DEFSYM (QCdocumentation, ":documentation");
DEFSYM (Qdebug, "debug");
+ DEFSYM (Qdebug_early, "debug-early");
DEFVAR_LISP ("inhibit-debugger", Vinhibit_debugger,
doc: /* Non-nil means never enter the debugger.
@@ -4003,6 +4277,11 @@ Does not apply if quit is handled by a `condition-case'. */);
DEFVAR_BOOL ("debug-on-next-call", debug_on_next_call,
doc: /* Non-nil means enter debugger before next `eval', `apply' or `funcall'. */);
+ DEFVAR_BOOL ("backtrace-on-redisplay-error", backtrace_on_redisplay_error,
+ doc: /* Non-nil means create a backtrace if a lisp error occurs in redisplay.
+The backtrace is written to buffer *Redisplay-trace*. */);
+ backtrace_on_redisplay_error = false;
+
DEFVAR_BOOL ("debugger-may-continue", debugger_may_continue,
doc: /* Non-nil means debugger may continue execution.
This is nil when the debugger is called under circumstances where it
@@ -4013,6 +4292,7 @@ might not be safe to continue. */);
doc: /* Non-nil means display call stack frames as lists. */);
debugger_stack_frame_as_list = 0;
+ DEFSYM (Qdebugger, "debugger");
DEFVAR_LISP ("debugger", Vdebugger,
doc: /* Function to call to invoke debugger.
If due to frame exit, args are `exit' and the value being returned;
@@ -4020,7 +4300,7 @@ If due to frame exit, args are `exit' and the value being returned;
If due to error, args are `error' and a list of the args to `signal'.
If due to `apply' or `funcall' entry, one arg, `lambda'.
If due to `eval' entry, one arg, t. */);
- Vdebugger = Qnil;
+ Vdebugger = Qdebug_early;
DEFVAR_LISP ("signal-hook-function", Vsignal_hook_function,
doc: /* If non-nil, this is a function for `signal' to call.
@@ -4034,6 +4314,26 @@ Note that `debug-on-error', `debug-on-quit' and friends
still determine whether to handle the particular condition. */);
Vdebug_on_signal = Qnil;
+ DEFVAR_BOOL ("backtrace-on-error-noninteractive",
+ backtrace_on_error_noninteractive,
+ doc: /* Non-nil means print backtrace on error in batch mode.
+If this is nil, errors in batch mode will just print the error
+message upon encountering an unhandled error, without showing
+the Lisp backtrace. */);
+ backtrace_on_error_noninteractive = true;
+
+ /* The value of num_nonmacro_input_events as of the last time we
+ started to enter the debugger. If we decide to enter the debugger
+ again when this is still equal to num_nonmacro_input_events, then we
+ know that the debugger itself has an error, and we should just
+ signal the error instead of entering an infinite loop of debugger
+ invocations. */
+ DEFSYM (Qinternal_when_entered_debugger, "internal-when-entered-debugger");
+ DEFVAR_INT ("internal-when-entered-debugger", when_entered_debugger,
+ doc: /* The number of keyboard events as of last time `debugger' was called.
+Used to avoid infinite loops if the debugger itself has an error.
+Don't set this unless you're sure that can't happen. */);
+
/* When lexical binding is being used,
Vinternal_interpreter_environment is non-nil, and contains an alist
of lexically-bound variable, or (t), indicating an empty
@@ -4063,7 +4363,12 @@ alist of active lexical bindings. */);
staticpro (&Vsignaling_function);
Vsignaling_function = Qnil;
- inhibit_lisp_code = Qnil;
+ staticpro (&Qcatch_all_memory_full);
+ /* Make sure Qcatch_all_memory_full is a unique object. We could
+ also use something like Fcons (Qnil, Qnil), but json.c treats any
+ cons cell as error data, so use an uninterned symbol instead. */
+ Qcatch_all_memory_full
+ = Fmake_symbol (build_pure_c_string ("catch-all-memory-full"));
defsubr (&Sor);
defsubr (&Sand);
@@ -4071,25 +4376,29 @@ alist of active lexical bindings. */);
defsubr (&Scond);
defsubr (&Sprogn);
defsubr (&Sprog1);
- defsubr (&Sprog2);
defsubr (&Ssetq);
defsubr (&Squote);
defsubr (&Sfunction);
defsubr (&Sdefault_toplevel_value);
defsubr (&Sset_default_toplevel_value);
defsubr (&Sdefvar);
+ defsubr (&Sdefvar_1);
defsubr (&Sdefvaralias);
DEFSYM (Qdefvaralias, "defvaralias");
defsubr (&Sdefconst);
+ defsubr (&Sdefconst_1);
+ defsubr (&Sinternal__define_uninitialized_variable);
defsubr (&Smake_var_non_special);
defsubr (&Slet);
defsubr (&SletX);
defsubr (&Swhile);
+ defsubr (&Sfuncall_with_delayed_message);
defsubr (&Smacroexpand);
defsubr (&Scatch);
defsubr (&Sthrow);
defsubr (&Sunwind_protect);
defsubr (&Scondition_case);
+ DEFSYM (QCsuccess, ":success");
defsubr (&Ssignal);
defsubr (&Scommandp);
defsubr (&Sautoload);
@@ -4108,8 +4417,10 @@ alist of active lexical bindings. */);
DEFSYM (QCdebug_on_exit, ":debug-on-exit");
defsubr (&Smapbacktrace);
defsubr (&Sbacktrace_frame_internal);
+ defsubr (&Sbacktrace_frames_from_thread);
defsubr (&Sbacktrace_eval);
defsubr (&Sbacktrace__locals);
defsubr (&Sspecial_variable_p);
+ DEFSYM (Qfunctionp, "functionp");
defsubr (&Sfunctionp);
}