-/* Copyright (C) 2001, 2009, 2010, 2011 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
/* Internal variables */
int nvalues = 0;
- const char *func_name = NULL; /* used for error reporting */
- SCM finish_args; /* used both for returns: both in error
- and normal situations */
+
#ifdef HAVE_LABELS_AS_VALUES
static const void **jump_table_pointer = NULL;
#endif
PUSH (SCM_PACK (0)); /* mvra */
PUSH (SCM_PACK (0)); /* ra */
PUSH (prog);
- if (SCM_UNLIKELY (sp + nargs >= stack_limit))
- goto vm_error_too_many_args;
+ VM_ASSERT (sp + nargs < stack_limit, vm_error_too_many_args (nargs));
while (nargs--)
PUSH (*argv++);
}
}
#endif
-
- vm_done:
- SYNC_ALL ();
- return finish_args;
-
- /* Errors */
- {
- SCM err_msg;
-
- /* FIXME: need to sync regs before allocating anything, in each case. */
-
- vm_error_bad_instruction:
- err_msg = scm_from_latin1_string ("VM: Bad instruction: ~s");
- finish_args = scm_list_1 (scm_from_uchar (ip[-1]));
- goto vm_error;
-
- vm_error_unbound:
- /* FINISH_ARGS should be the name of the unbound variable. */
- SYNC_ALL ();
- err_msg = scm_from_latin1_string ("Unbound variable: ~s");
- scm_error_scm (scm_misc_error_key, program, err_msg,
- scm_list_1 (finish_args), SCM_BOOL_F);
- goto vm_error;
-
- vm_error_unbound_fluid:
- SYNC_ALL ();
- err_msg = scm_from_latin1_string ("Unbound fluid: ~s");
- scm_error_scm (scm_misc_error_key, program, err_msg,
- scm_list_1 (finish_args), SCM_BOOL_F);
- goto vm_error;
-
- vm_error_not_a_variable:
- SYNC_ALL ();
- scm_error (scm_arg_type_key, func_name, "Not a variable: ~S",
- scm_list_1 (finish_args), scm_list_1 (finish_args));
- goto vm_error;
-
- vm_error_apply_to_non_list:
- SYNC_ALL ();
- scm_error (scm_arg_type_key, "apply", "Apply to non-list: ~S",
- scm_list_1 (finish_args), scm_list_1 (finish_args));
- goto vm_error;
-
- vm_error_kwargs_length_not_even:
- SYNC_ALL ();
- err_msg = scm_from_latin1_string ("Odd length of keyword argument list");
- scm_error_scm (sym_keyword_argument_error, program, err_msg,
- SCM_EOL, SCM_BOOL_F);
-
- vm_error_kwargs_invalid_keyword:
- /* FIXME say which one it was */
- SYNC_ALL ();
- err_msg = scm_from_latin1_string ("Invalid keyword");
- scm_error_scm (sym_keyword_argument_error, program, err_msg,
- SCM_EOL, SCM_BOOL_F);
-
- vm_error_kwargs_unrecognized_keyword:
- /* FIXME say which one it was */
- SYNC_ALL ();
- err_msg = scm_from_latin1_string ("Unrecognized keyword");
- scm_error_scm (sym_keyword_argument_error, program, err_msg,
- SCM_EOL, SCM_BOOL_F);
-
- vm_error_too_many_args:
- err_msg = scm_from_latin1_string ("VM: Too many arguments");
- finish_args = scm_list_1 (scm_from_int (nargs));
- goto vm_error;
-
- vm_error_wrong_num_args:
- /* nargs and program are valid */
- SYNC_ALL ();
- scm_wrong_num_args (program);
- /* shouldn't get here */
- goto vm_error;
-
- vm_error_wrong_type_apply:
- SYNC_ALL ();
- scm_error (scm_arg_type_key, NULL, "Wrong type to apply: ~S",
- scm_list_1 (program), scm_list_1 (program));
- goto vm_error;
-
- vm_error_stack_overflow:
- err_msg = scm_from_latin1_string ("VM: Stack overflow");
- finish_args = SCM_EOL;
- if (stack_limit < vp->stack_base + vp->stack_size)
- /* There are VM_STACK_RESERVE_SIZE bytes left. Make them available so
- that `throw' below can run on this VM. */
- vp->stack_limit = vp->stack_base + vp->stack_size;
- goto vm_error;
-
- vm_error_stack_underflow:
- err_msg = scm_from_latin1_string ("VM: Stack underflow");
- finish_args = SCM_EOL;
- goto vm_error;
-
- vm_error_improper_list:
- err_msg = scm_from_latin1_string ("Expected a proper list, but got object with tail ~s");
- goto vm_error;
-
- vm_error_not_a_pair:
- SYNC_ALL ();
- scm_wrong_type_arg_msg (func_name, 1, finish_args, "pair");
- /* shouldn't get here */
- goto vm_error;
-
- vm_error_not_a_bytevector:
- SYNC_ALL ();
- scm_wrong_type_arg_msg (func_name, 1, finish_args, "bytevector");
- /* shouldn't get here */
- goto vm_error;
-
- vm_error_not_a_struct:
- SYNC_ALL ();
- scm_wrong_type_arg_msg (func_name, 1, finish_args, "struct");
- /* shouldn't get here */
- goto vm_error;
-
- vm_error_not_a_thunk:
- SYNC_ALL ();
- scm_wrong_type_arg_msg ("dynamic-wind", 1, finish_args, "thunk");
- /* shouldn't get here */
- goto vm_error;
-
- vm_error_no_values:
- err_msg = scm_from_latin1_string ("Zero values returned to single-valued continuation");
- finish_args = SCM_EOL;
- goto vm_error;
-
- vm_error_not_enough_values:
- err_msg = scm_from_latin1_string ("Too few values returned to continuation");
- finish_args = SCM_EOL;
- goto vm_error;
-
- vm_error_continuation_not_rewindable:
- err_msg = scm_from_latin1_string ("Unrewindable partial continuation");
- finish_args = scm_cons (finish_args, SCM_EOL);
- goto vm_error;
-
- vm_error_bad_wide_string_length:
- err_msg = scm_from_latin1_string ("VM: Bad wide string length: ~S");
- goto vm_error;
-
-#ifdef VM_CHECK_IP
- vm_error_invalid_address:
- err_msg = scm_from_latin1_string ("VM: Invalid program address");
- finish_args = SCM_EOL;
- goto vm_error;
-#endif
-
-#if VM_CHECK_OBJECT
- vm_error_object:
- err_msg = scm_from_latin1_string ("VM: Invalid object table access");
- finish_args = SCM_EOL;
- goto vm_error;
-#endif
-
-#if VM_CHECK_FREE_VARIABLES
- vm_error_free_variable:
- err_msg = scm_from_latin1_string ("VM: Invalid free variable access");
- finish_args = SCM_EOL;
- goto vm_error;
-#endif
-
- vm_error:
- SYNC_ALL ();
+ abort (); /* never reached */
- scm_ithrow (sym_vm_error, scm_list_3 (sym_vm_run, err_msg, finish_args),
- 1);
- }
+ vm_error_bad_instruction:
+ vm_error_bad_instruction (ip[-1]);
+ abort (); /* never reached */
+ handle_overflow:
+ SYNC_ALL ();
+ vm_error_stack_overflow (vp);
abort (); /* never reached */
}
-/* Copyright (C) 2001, 2009, 2010, 2011 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* Cache/Sync
*/
+#define VM_ASSERT(condition, handler) \
+ do { if (SCM_UNLIKELY (!(condition))) { SYNC_ALL(); handler; } } while (0)
+
#ifdef VM_ENABLE_ASSERTIONS
-# define ASSERT(condition) if (SCM_UNLIKELY (!(condition))) abort()
+# define ASSERT(condition) VM_ASSERT (condition, abort())
#else
# define ASSERT(condition)
#endif
/* Accesses to a program's object table. */
#if VM_CHECK_OBJECT
-#define CHECK_OBJECT(_num) \
- do { if (SCM_UNLIKELY ((_num) >= object_count)) goto vm_error_object; } while (0)
+#define CHECK_OBJECT(_num) \
+ VM_ASSERT ((_num) < object_count, vm_error_object ())
#else
#define CHECK_OBJECT(_num)
#endif
#if VM_CHECK_FREE_VARIABLES
-#define CHECK_FREE_VARIABLE(_num) \
- do { \
- if (SCM_UNLIKELY ((_num) >= SCM_PROGRAM_NUM_FREE_VARIABLES (program))) \
- goto vm_error_free_variable; \
- } while (0)
+#define CHECK_FREE_VARIABLE(_num) \
+ VM_ASSERT ((_num) < SCM_PROGRAM_NUM_FREE_VARIABLES (program), \
+ vm_error_free_variable ())
#else
#define CHECK_FREE_VARIABLE(_num)
#endif
# define NULLSTACK_FOR_NONLOCAL_EXIT()
#endif
-#define CHECK_OVERFLOW() \
- if (SCM_UNLIKELY (sp >= stack_limit)) \
- goto vm_error_stack_overflow
+/* For this check, we don't use VM_ASSERT, because that leads to a
+ per-site SYNC_ALL, which is too much code growth. The real problem
+ of course is having to check for overflow all the time... */
+#define CHECK_OVERFLOW() \
+ do { if (SCM_UNLIKELY (sp >= stack_limit)) goto handle_overflow; } while (0)
#ifdef VM_CHECK_UNDERFLOW
-#define CHECK_UNDERFLOW() \
- if (SCM_UNLIKELY (sp <= SCM_FRAME_UPPER_ADDRESS (fp))) \
- goto vm_error_stack_underflow
#define PRE_CHECK_UNDERFLOW(N) \
- if (SCM_UNLIKELY (sp - N <= SCM_FRAME_UPPER_ADDRESS (fp))) \
- goto vm_error_stack_underflow
+ VM_ASSERT (sp - (N) > SCM_FRAME_UPPER_ADDRESS (fp), vm_error_stack_underflow ())
+#define CHECK_UNDERFLOW() PRE_CHECK_UNDERFLOW (0)
#else
-#define CHECK_UNDERFLOW() /* nop */
#define PRE_CHECK_UNDERFLOW(N) /* nop */
+#define CHECK_UNDERFLOW() /* nop */
#endif
{ \
for (; scm_is_pair (l); l = SCM_CDR (l)) \
PUSH (SCM_CAR (l)); \
- if (SCM_UNLIKELY (!NILP (l))) { \
- finish_args = scm_list_1 (l); \
- goto vm_error_improper_list; \
- } \
+ VM_ASSERT (NILP (l), vm_error_improper_list (l)); \
} while (0)
\f
-/* Copyright (C) 2001,2008,2009,2010,2011 Free Software Foundation, Inc.
+/* Copyright (C) 2001,2008,2009,2010,2011,2012 Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
scm_t_wchar *wbuf;
FETCH_LENGTH (len);
- if (SCM_UNLIKELY (len % 4))
- {
- finish_args = scm_list_1 (scm_from_size_t (len));
- goto vm_error_bad_wide_string_length;
- }
+ VM_ASSERT ((len % 4) == 0,
+ vm_error_bad_wide_string_length (len));
SYNC_REGISTER ();
PUSH (scm_i_make_wide_string (len / 4, &wbuf, 1));
-/* Copyright (C) 2001, 2009, 2010, 2011 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
}
#define VM_VALIDATE_CONS(x, proc) \
- if (SCM_UNLIKELY (!scm_is_pair (x))) \
- { func_name = proc; \
- finish_args = x; \
- goto vm_error_not_a_pair; \
- }
+ VM_ASSERT (scm_is_pair (x), vm_error_not_a_pair (proc, x))
VM_DEFINE_FUNCTION (141, car, "car", 1)
{
* Structs
*/
#define VM_VALIDATE_STRUCT(obj, proc) \
- if (SCM_UNLIKELY (!SCM_STRUCTP (obj))) \
- { \
- func_name = proc; \
- finish_args = (obj); \
- goto vm_error_not_a_struct; \
- }
+ VM_ASSERT (SCM_STRUCTP (obj), vm_error_not_a_pair (proc, obj))
VM_DEFINE_FUNCTION (166, struct_p, "struct?", 1)
{
* Bytevectors
*/
#define VM_VALIDATE_BYTEVECTOR(x, proc) \
- do \
- { \
- if (SCM_UNLIKELY (!SCM_BYTEVECTOR_P (x))) \
- { \
- func_name = proc; \
- finish_args = x; \
- goto vm_error_not_a_bytevector; \
- } \
- } \
- while (0)
+ VM_ASSERT (SCM_BYTEVECTOR_P (x), vm_error_not_a_bytevector (proc, x))
#define BV_REF_WITH_ENDIANNESS(stem, fn_stem) \
{ \
VM_DEFINE_INSTRUCTION (1, halt, "halt", 0, 0, 0)
{
+ SCM ret;
+
nvalues = SCM_I_INUM (*sp--);
NULLSTACK (1);
+
if (nvalues == 1)
- POP (finish_args);
+ POP (ret);
else
{
- POP_LIST (nvalues);
- POP (finish_args);
SYNC_REGISTER ();
- finish_args = scm_values (finish_args);
+ sp -= nvalues;
+ CHECK_UNDERFLOW ();
+ ret = scm_c_values (sp + 1, nvalues);
+ NULLSTACK (nvalues);
}
{
NULLSTACK (old_sp - sp);
}
- goto vm_done;
+ SYNC_ALL ();
+ return ret;
}
VM_DEFINE_INSTRUCTION (2, drop, "drop", 0, 1, 0)
unlike in top-variable-ref, it really isn't an internal assertion
that can be optimized out -- the variable could be coming directly
from the user. */
- if (SCM_UNLIKELY (!SCM_VARIABLEP (x)))
- {
- func_name = "variable-ref";
- finish_args = x;
- goto vm_error_not_a_variable;
- }
- else if (SCM_UNLIKELY (!VARIABLE_BOUNDP (x)))
+ VM_ASSERT (SCM_VARIABLEP (x),
+ vm_error_not_a_variable ("variable-ref", x));
+
+ if (SCM_UNLIKELY (!VARIABLE_BOUNDP (x)))
{
SCM var_name;
/* Attempt to provide the variable name in the error message. */
var_name = scm_module_reverse_lookup (scm_current_module (), x);
- finish_args = scm_is_true (var_name) ? var_name : x;
- goto vm_error_unbound;
+ vm_error_unbound (program, scm_is_true (var_name) ? var_name : x);
}
else
{
{
SCM x = *sp;
- if (SCM_UNLIKELY (!SCM_VARIABLEP (x)))
- {
- func_name = "variable-bound?";
- finish_args = x;
- goto vm_error_not_a_variable;
- }
- else
- *sp = scm_from_bool (VARIABLE_BOUNDP (x));
+ VM_ASSERT (SCM_VARIABLEP (x),
+ vm_error_not_a_variable ("variable-bound?", x));
+
+ *sp = scm_from_bool (VARIABLE_BOUNDP (x));
NEXT;
}
{
SYNC_REGISTER ();
resolved = resolve_variable (what, scm_program_module (program));
- if (!VARIABLE_BOUNDP (resolved))
- {
- finish_args = what;
- goto vm_error_unbound;
- }
+ VM_ASSERT (VARIABLE_BOUNDP (resolved), vm_error_unbound (program, what));
what = resolved;
OBJECT_SET (objnum, what);
}
{
SYNC_REGISTER ();
resolved = resolve_variable (what, scm_program_module (program));
- if (!VARIABLE_BOUNDP (resolved))
- {
- finish_args = what;
- goto vm_error_unbound;
- }
+ VM_ASSERT (VARIABLE_BOUNDP (resolved),
+ vm_error_unbound (program, what));
what = resolved;
OBJECT_SET (objnum, what);
}
VM_DEFINE_INSTRUCTION (31, variable_set, "variable-set", 0, 2, 0)
{
- if (SCM_UNLIKELY (!SCM_VARIABLEP (sp[0])))
- {
- func_name = "variable-set!";
- finish_args = sp[0];
- goto vm_error_not_a_variable;
- }
+ VM_ASSERT (SCM_VARIABLEP (sp[0]),
+ vm_error_not_a_variable ("variable-set!", sp[0]));
VARIABLE_SET (sp[0], sp[-1]);
DROPN (2);
NEXT;
scm_t_ptrdiff n;
n = FETCH () << 8;
n += FETCH ();
- if (sp - (fp - 1) != n)
- goto vm_error_wrong_num_args;
+ VM_ASSERT (sp - (fp - 1) == n,
+ vm_error_wrong_num_args (program));
NEXT;
}
scm_t_ptrdiff n;
n = FETCH () << 8;
n += FETCH ();
- if (sp - (fp - 1) < n)
- goto vm_error_wrong_num_args;
+ VM_ASSERT (sp - (fp - 1) >= n,
+ vm_error_wrong_num_args (program));
NEXT;
}
nkw += FETCH ();
kw_and_rest_flags = FETCH ();
- if (!(kw_and_rest_flags & F_REST)
- && ((sp - (fp - 1) - nkw) % 2))
- goto vm_error_kwargs_length_not_even;
+ VM_ASSERT ((kw_and_rest_flags & F_REST)
+ || ((sp - (fp - 1) - nkw) % 2) == 0,
+ vm_error_kwargs_length_not_even (program))
CHECK_OBJECT (idx);
kw = OBJECT_REF (idx);
break;
}
}
- if (!(kw_and_rest_flags & F_ALLOW_OTHER_KEYS) && !scm_is_pair (walk))
- goto vm_error_kwargs_unrecognized_keyword;
-
+ VM_ASSERT (scm_is_pair (walk)
+ || (kw_and_rest_flags & F_ALLOW_OTHER_KEYS),
+ vm_error_kwargs_unrecognized_keyword (program));
nkw++;
}
- else if (!(kw_and_rest_flags & F_REST))
- goto vm_error_kwargs_invalid_keyword;
+ else
+ VM_ASSERT (kw_and_rest_flags & F_REST,
+ vm_error_kwargs_invalid_keyword (program));
}
NEXT;
goto vm_call;
}
else
- goto vm_error_wrong_type_apply;
+ {
+ SYNC_ALL();
+ vm_error_wrong_type_apply (program);
+ }
}
CACHE_PROGRAM ();
goto vm_tail_call;
}
else
- goto vm_error_wrong_type_apply;
+ {
+ SYNC_ALL();
+ vm_error_wrong_type_apply (program);
+ }
}
else
{
SCM vmcont, intwinds, prevwinds;
POP2 (intwinds, vmcont);
SYNC_REGISTER ();
- if (SCM_UNLIKELY (!SCM_VM_CONT_REWINDABLE_P (vmcont)))
- { finish_args = vmcont;
- goto vm_error_continuation_not_rewindable;
- }
+ VM_ASSERT (SCM_VM_CONT_REWINDABLE_P (vmcont),
+ vm_error_continuation_not_rewindable (vmcont));
prevwinds = scm_i_dynwinds ();
vm_reinstate_partial_continuation (vm, vmcont, intwinds, sp + 1 - fp, fp,
vm_cookie);
goto vm_mv_call;
}
else
- goto vm_error_wrong_type_apply;
+ {
+ SYNC_ALL();
+ vm_error_wrong_type_apply (program);
+ }
}
CACHE_PROGRAM ();
ASSERT (nargs >= 2);
len = scm_ilength (ls);
- if (SCM_UNLIKELY (len < 0))
- {
- finish_args = ls;
- goto vm_error_apply_to_non_list;
- }
-
+ VM_ASSERT (len >= 0,
+ vm_error_apply_to_non_list (ls));
PUSH_LIST (ls, SCM_NULL_OR_NIL_P);
nargs += len - 2;
ASSERT (nargs >= 2);
len = scm_ilength (ls);
- if (SCM_UNLIKELY (len < 0))
- {
- finish_args = ls;
- goto vm_error_apply_to_non_list;
- }
-
+ VM_ASSERT (len >= 0,
+ vm_error_apply_to_non_list (ls));
PUSH_LIST (ls, SCM_NULL_OR_NIL_P);
nargs += len - 2;
NULLSTACK (vals + nvalues - sp);
}
else
- goto vm_error_no_values;
+ {
+ SYNC_ALL ();
+ vm_error_no_values ();
+ }
/* Restore the last program */
program = SCM_FRAME_PROGRAM (fp);
l = SCM_CDR (l);
nvalues++;
}
- if (SCM_UNLIKELY (!SCM_NULL_OR_NIL_P (l))) {
- finish_args = scm_list_1 (l);
- goto vm_error_improper_list;
- }
+ VM_ASSERT (SCM_NULL_OR_NIL_P (l), vm_error_improper_list (l));
goto vm_return_values;
}
if (rest)
nbinds--;
- if (nvalues < nbinds)
- goto vm_error_not_enough_values;
+ VM_ASSERT (nvalues >= nbinds, vm_error_not_enough_values ());
if (rest)
POP_LIST (nvalues - nbinds);
/* Push wind and unwind procedures onto the dynamic stack. Note that neither
are actually called; the compiler should emit calls to wind and unwind for
the normal dynamic-wind control flow. */
- if (SCM_UNLIKELY (scm_is_false (scm_thunk_p (wind))))
- {
- finish_args = wind;
- goto vm_error_not_a_thunk;
- }
- if (SCM_UNLIKELY (scm_is_false (scm_thunk_p (unwind))))
- {
- finish_args = unwind;
- goto vm_error_not_a_thunk;
- }
+ VM_ASSERT (scm_thunk_p (wind), vm_error_not_a_thunk ("dynamic-wind", wind));
+ VM_ASSERT (scm_thunk_p (unwind), vm_error_not_a_thunk ("dynamic-wind", unwind));
scm_i_set_dynwinds (scm_cons (scm_cons (wind, unwind), scm_i_dynwinds ()));
NEXT;
}
{
unsigned n = FETCH ();
SYNC_REGISTER ();
- if (sp - n - 2 <= SCM_FRAME_UPPER_ADDRESS (fp))
- goto vm_error_stack_underflow;
+ PRE_CHECK_UNDERFLOW (n + 2);
vm_abort (vm, n, vm_cookie);
/* vm_abort should not return */
abort ();
SCM val = SCM_SIMPLE_VECTOR_REF (fluids, num);
if (scm_is_eq (val, SCM_UNDEFINED))
val = SCM_I_FLUID_DEFAULT (*sp);
- if (SCM_UNLIKELY (scm_is_eq (val, SCM_UNDEFINED)))
- {
- finish_args = *sp;
- goto vm_error_unbound_fluid;
- }
+ VM_ASSERT (!scm_is_eq (val, SCM_UNDEFINED),
+ vm_error_unbound_fluid (program, *sp));
*sp = val;
}
/* nargs = n & 0x7, nlocs = nargs + (n >> 3) */
n = FETCH ();
- if (SCM_UNLIKELY (sp - (fp - 1) != (n & 0x7)))
- goto vm_error_wrong_num_args;
+ VM_ASSERT (sp - (fp - 1) == (n & 0x7),
+ vm_error_wrong_num_args (program));
old_sp = sp;
sp += (n >> 3);
scm_puts (">", port);
}
+\f
+/*
+ * VM Error Handling
+ */
+
+static void vm_error (const char *msg, SCM arg) SCM_NORETURN;
+static void vm_error_bad_instruction (scm_t_uint32 inst) SCM_NORETURN;
+static void vm_error_unbound (SCM proc, SCM sym) SCM_NORETURN;
+static void vm_error_unbound_fluid (SCM proc, SCM fluid) SCM_NORETURN;
+static void vm_error_not_a_variable (const char *func_name, SCM x) SCM_NORETURN;
+static void vm_error_not_a_thunk (const char *func_name, SCM x) SCM_NORETURN;
+static void vm_error_apply_to_non_list (SCM x) SCM_NORETURN;
+static void vm_error_kwargs_length_not_even (SCM proc) SCM_NORETURN;
+static void vm_error_kwargs_invalid_keyword (SCM proc) SCM_NORETURN;
+static void vm_error_kwargs_unrecognized_keyword (SCM proc) SCM_NORETURN;
+static void vm_error_too_many_args (int nargs) SCM_NORETURN;
+static void vm_error_wrong_num_args (SCM proc) SCM_NORETURN;
+static void vm_error_wrong_type_apply (SCM proc) SCM_NORETURN;
+static void vm_error_stack_overflow (struct scm_vm *vp) SCM_NORETURN;
+static void vm_error_stack_underflow (void) SCM_NORETURN;
+static void vm_error_improper_list (SCM x) SCM_NORETURN;
+static void vm_error_not_a_pair (const char *subr, SCM x) SCM_NORETURN;
+static void vm_error_not_a_bytevector (const char *subr, SCM x) SCM_NORETURN;
+static void vm_error_not_a_struct (const char *subr, SCM x) SCM_NORETURN;
+static void vm_error_no_values (void) SCM_NORETURN;
+static void vm_error_not_enough_values (void) SCM_NORETURN;
+static void vm_error_continuation_not_rewindable (SCM cont) SCM_NORETURN;
+static void vm_error_bad_wide_string_length (size_t len) SCM_NORETURN;
+#if VM_CHECK_IP
+static void vm_error_invalid_address (void) SCM_NORETURN;
+#endif
+#if VM_CHECK_OBJECT
+static void vm_error_object (void) SCM_NORETURN;
+#endif
+#if VM_CHECK_FREE_VARIABLES
+static void vm_error_free_variable (void) SCM_NORETURN;
+#endif
+
+static void
+vm_error (const char *msg, SCM arg)
+{
+ scm_throw (sym_vm_error,
+ scm_list_3 (sym_vm_run, scm_from_latin1_string (msg),
+ SCM_UNBNDP (arg) ? SCM_EOL : scm_list_1 (arg)));
+ abort(); /* not reached */
+}
+
+static void
+vm_error_bad_instruction (scm_t_uint32 inst)
+{
+ vm_error ("VM: Bad instruction: ~s", scm_from_uint32 (inst));
+}
+
+static void
+vm_error_unbound (SCM proc, SCM sym)
+{
+ scm_error_scm (scm_misc_error_key, proc,
+ scm_from_latin1_string ("Unbound variable: ~s"),
+ scm_list_1 (sym), SCM_BOOL_F);
+}
+
+static void
+vm_error_unbound_fluid (SCM proc, SCM fluid)
+{
+ scm_error_scm (scm_misc_error_key, proc,
+ scm_from_latin1_string ("Unbound fluid: ~s"),
+ scm_list_1 (fluid), SCM_BOOL_F);
+}
+
+static void
+vm_error_not_a_variable (const char *func_name, SCM x)
+{
+ scm_error (scm_arg_type_key, func_name, "Not a variable: ~S",
+ scm_list_1 (x), scm_list_1 (x));
+}
+
+static void
+vm_error_not_a_thunk (const char *func_name, SCM x)
+{
+ scm_error (scm_arg_type_key, func_name, "Not a thunk: ~S",
+ scm_list_1 (x), scm_list_1 (x));
+}
+
+static void
+vm_error_apply_to_non_list (SCM x)
+{
+ scm_error (scm_arg_type_key, "apply", "Apply to non-list: ~S",
+ scm_list_1 (x), scm_list_1 (x));
+}
+
+static void
+vm_error_kwargs_length_not_even (SCM proc)
+{
+ scm_error_scm (sym_keyword_argument_error, proc,
+ scm_from_latin1_string ("Odd length of keyword argument list"),
+ SCM_EOL, SCM_BOOL_F);
+}
+
+static void
+vm_error_kwargs_invalid_keyword (SCM proc)
+{
+ scm_error_scm (sym_keyword_argument_error, proc,
+ scm_from_latin1_string ("Invalid keyword"),
+ SCM_EOL, SCM_BOOL_F);
+}
+
+static void
+vm_error_kwargs_unrecognized_keyword (SCM proc)
+{
+ scm_error_scm (sym_keyword_argument_error, proc,
+ scm_from_latin1_string ("Unrecognized keyword"),
+ SCM_EOL, SCM_BOOL_F);
+}
+
+static void
+vm_error_too_many_args (int nargs)
+{
+ vm_error ("VM: Too many arguments", scm_from_int (nargs));
+}
+
+static void
+vm_error_wrong_num_args (SCM proc)
+{
+ scm_wrong_num_args (proc);
+}
+
+static void
+vm_error_wrong_type_apply (SCM proc)
+{
+ scm_error (scm_arg_type_key, NULL, "Wrong type to apply: ~S",
+ scm_list_1 (proc), scm_list_1 (proc));
+}
+
+static void
+vm_error_stack_overflow (struct scm_vm *vp)
+{
+ if (vp->stack_limit < vp->stack_base + vp->stack_size)
+ /* There are VM_STACK_RESERVE_SIZE bytes left. Make them available so
+ that `throw' below can run on this VM. */
+ vp->stack_limit = vp->stack_base + vp->stack_size;
+ else
+ /* There is no space left on the stack. FIXME: Do something more
+ sensible here! */
+ abort ();
+ vm_error ("VM: Stack overflow", SCM_UNDEFINED);
+}
+
+static void
+vm_error_stack_underflow (void)
+{
+ vm_error ("VM: Stack underflow", SCM_UNDEFINED);
+}
+
+static void
+vm_error_improper_list (SCM x)
+{
+ vm_error ("Expected a proper list, but got object with tail ~s", x);
+}
+
+static void
+vm_error_not_a_pair (const char *subr, SCM x)
+{
+ scm_wrong_type_arg_msg (subr, 1, x, "pair");
+}
+
+static void
+vm_error_not_a_bytevector (const char *subr, SCM x)
+{
+ scm_wrong_type_arg_msg (subr, 1, x, "bytevector");
+}
+
+static void
+vm_error_not_a_struct (const char *subr, SCM x)
+{
+ scm_wrong_type_arg_msg (subr, 1, x, "struct");
+}
+
+static void
+vm_error_no_values (void)
+{
+ vm_error ("Zero values returned to single-valued continuation",
+ SCM_UNDEFINED);
+}
+
+static void
+vm_error_not_enough_values (void)
+{
+ vm_error ("Too few values returned to continuation", SCM_UNDEFINED);
+}
+
+static void
+vm_error_continuation_not_rewindable (SCM cont)
+{
+ vm_error ("Unrewindable partial continuation", cont);
+}
+
+static void
+vm_error_bad_wide_string_length (size_t len)
+{
+ vm_error ("VM: Bad wide string length: ~S", scm_from_size_t (len));
+}
+
+#ifdef VM_CHECK_IP
+static void
+vm_error_invalid_address (void)
+{
+ vm_error ("VM: Invalid program address", SCM_UNDEFINED);
+}
+#endif
+
+#if VM_CHECK_OBJECT
+static void
+vm_error_object ()
+{
+ vm_error ("VM: Invalid object table access", SCM_UNDEFINED);
+}
+#endif
+
+#if VM_CHECK_FREE_VARIABLES
+static void
+vm_error_free_variable ()
+{
+ vm_error ("VM: Invalid free variable access", SCM_UNDEFINED);
+}
+#endif
+
+\f
static SCM
really_make_boot_program (long nargs)
{