* libguile/vm.c (vm_error_kwargs_invalid_keyword,
vm_error_kwargs_unrecognized_keyword): Add parameter. Pass it
enclosed in a list as the last argument to `scm_error_scm'.
* libguile/vm-i-system.c (bind_kwargs): Adjust accordingly.
* libguile/eval.c (error_invalid_keyword, error_unrecognized_keyword):
Add parameter.
(prepare_boot_closure_env_for_apply): Adjust accordingly.
* module/ice-9/eval.scm (primitive-eval): Likewise.
* libguile/error.c (scm_error_scm): Mention `keyword-argument-error' in
docstring.
* module/ice-9/boot-9.scm (keyword-error-printer): New procedure; use it.
* test-suite/tests/optargs.test (c&e, with-test-prefix/c&e): Remove.
("define*")["unrecognized keyword"]: Test the value passed along the
`keyword-argument-error' exception.
["invalid keyword"]: New test.
* doc/ref/api-control.texi (Error Reporting): Update `scm-error'
description.
* doc/ref/api-procedures.texi (Case-lambda): Expand case-lambda*
documentation.
* module/ice-9/eval.scm (primitive-eval):
* libguile/eval.c (prepare_boot_closure_env_for_apply): Dispatch to the
next case-lambda clause if there are too many positionals.
* doc/ref/vm.texi (Function Prologue Instructions):
* libguile/vm-i-system.c (bind-optionals/shuffle-or-br): New
instruction, like bind-optionals/shuffle but can dispatch to the next
clause if there are too many positionals.
* module/language/assembly/disassemble.scm (code-annotation):
* module/language/assembly/decompile-bytecode.scm (decode-load-program):
* module/language/assembly/compile-bytecode.scm (compile-bytecode): Add
case for bind-optionals/shuffle-or-br.
* module/language/glil/compile-assembly.scm (glil->assembly): If there
is an alternate, use bind-optionals/shuffle-or-br instead of
bind-optionals/shuffle.
* test-suite/tests/optargs.test ("case-lambda*"): Add tests.
* libguile/deprecated.h:
* libguile/deprecated.c (scm_sym2var): Deprecate this function.
* libguile/modules.h:
* libguile/modules.c (scm_module_ensure_local_variable): New public
function, replacing scm_sym2var with a true definep, without going
through eval closures (which are deprecated).
(scm_current_module): Rework to do something sensible before modules
are booted.
(scm_module_lookup, scm_lookup): Refactor to use scm_module_variable.
(scm_module_define, scm_define): Refactor to use
scm_module_ensure_local_variable.
* libguile/vm-i-system.c (define!): Use scm_define.
* libguile/vm.c (resolve_variable): Use scm_module_lookup.
* libguile/macros.c (scm_make_syntax_transformer): Use
scm_module_variable.
* libguile/gdbint.c (gdb_binding): Use scm_define.
* doc/ref/api-modules.texi (Accessing Modules from C): Add docs for
scm_module_ensure_local_variable.
* libguile/frames.c (scm_frame_instruction_pointer):
* module/system/vm/frame.scm (frame-bindings):
(frame-next-source, frame-call-representation): Fix a few locations
that thought that the frame-procedure will always be a VM
procedure. This will not not be the case when traversing the stack of
an application of a non-procedure.
* libguile/vm-i-system.c (call, tail-call, mv-call): Instead of
special-casing structs and smobs at these call sites, just set up the
stack, and jump to a generic apply loop if the proc is not a program.
* libguile/vm-engine.c: The generic apply loop is here. Also, the boot
program is now simply a boot continuation, and can handle any number
of arguments.
* libguile/vm.c (make_boot_program): Update the code that makes the boot
continuation.
* libguile/vm.c:
(vm_error):
(vm_error_bad_instruction):
(vm_error_unbound):
(vm_error_unbound_fluid):
(vm_error_not_a_variable):
(vm_error_not_a_thunk):
(vm_error_apply_to_non_list):
(vm_error_kwargs_length_not_even):
(vm_error_kwargs_invalid_keyword):
(vm_error_kwargs_unrecognized_keyword):
(vm_error_too_many_args):
(vm_error_wrong_num_args):
(vm_error_wrong_type_apply):
(vm_error_stack_overflow):
(vm_error_stack_underflow):
(vm_error_improper_list):
(vm_error_not_a_pair):
(vm_error_not_a_bytevector):
(vm_error_not_a_struct):
(vm_error_no_values):
(vm_error_not_enough_values):
(vm_error_continuation_not_rewindable):
(vm_error_bad_wide_string_length):
(vm_error_invalid_address):
(vm_error_object):
(vm_error_free_variable): New internal helpers, implementing VM error
handling.
* libguile/vm-engine.h (VM_ASSERT): New helper macro.
(ASSERT, CHECK_OBJECT, CHECK_FREE_VARIABLE):
(PRE_CHECK_UNDERFLOW, PUSH_LIST): Use the new helper.
* libguile/vm-i-loader.c:
* libguile/vm-i-scheme.c:
* libguile/vm-i-system.c: Use VM_ASSERT and the out-of-line error
handlers.
* libguile/vm-engine.c (vm_engine): Remove inline error handlers, and
remove a couple of local vars. Use VM_ASSERT. Have halt handle the
return itself.
* libguile/vm.c (prepare_smob_call): New helper. Now, instead of making
a per-smob trampoline, we will shuffle the smob into the args and use
a gsubr. This prevents a memory leak in which the trampolines, which
were values in a weak-key table, were preventing the smobs from being
collected.
* libguile/vm-i-system.c (call, tail-call, mv-call): Adapt to new smob
application mechanism.
(smob-call): Remove this instruction.
* libguile/smob.h (scm_smob_descriptor): Rename apply_trampoline_objcode
to apply_trampoline.
* libguile/smob.c: Remove our own objcode trampolines in favor of using
scm_c_make_gsubr.
(scm_smob_prehistory): No more trampoline weak map.
* libguile/procprop.c (scm_i_procedure_arity): Adapt to applicable smob
representation change.
* libguile/vm-engine.h (DEAD): New macro, nulls out a value.
* libguile/vm-i-system.c:
* libguile/vm-i-loader.c:
* libguile/vm-i-scheme.c: Use DEAD when variables become dead.
Later we can #ifdef this out, but I want to give the buildbots a try
with this patch to make sure it's correct.
Fixes part of <http://bugs.gnu.org/10520>.
Reported by Bruno Haible <bruno@clisp.org>.
* libguile/vm-i-system.c (COMPILER_BARRIER): New macro.
(halt, return, return_values): Insert compiler barrier after each
assignment to `fp'.
* libguile/fluids.c (grow_dynamic_state, new_fluid): Arrange for the
default value in the dynamic-state vector to be SCM_UNDEFINED instead
of SCM_BOOL_F. If the value in the dynamic-state is #f, default to a
value attached to the fluid instead. This allows useful default
values.
(scm_make_fluid_with_default): New function, allows the user to
specify a default value for the fluid. Defaults to #f. Bound to
`make-fluid' on the Scheme side.
(scm_make_unbound_fluid): Use SCM_UNDEFINED as the default in all
threads.
(scm_fluid_unset_x): Also unset the default value. Not sure if this
is the right thing.
(fluid_ref): Update to the new default-value strategy.
* libguile/threads.c (scm_i_reset_fluid): Reset to SCM_UNDEFINED.
* libguile/threads.h: Remove extra arg to scm_i_reset_fluid.
* libguile/vm-i-system.c (fluid-ref): Update to new default-value
strategy.
* module/ice-9/vlist.scm (block-growth-factor): Default to 2 in all
threads. Fixes http://debbugs.gnu.org/10093.
* libguile/__scm.h (SCM_ASYNC_TICK_WITH_CODE): Redefine to take a
scm_i_thread* as well. OK to do because it's within a
BUILDING_LIBGUILE block.
* libguile/vm-engine.c (vm_engine): Cache the scm_i_thread* instead of
the dynstate, so we can use the thread for ticks.
* libguile/vm-engine.h (VM_HANDLE_INTERRUPTS): Tick with the
scm_i_thread* local var, to avoid excessive tls calls.
* libguile/vm-i-system.c: Fix dynstate users to use
current_thread->dynamic_state.
* libguile/vm-engine.c (VM_CHECK_OBJECT, VM_CHECK_FREE_VARIABLES): Set
to 0 for both engines. These are really internal debugging variables,
which don't affect user-visible features, provided that the compiler
is correct of course.
(VM_CHECK_UNDERFLOW): New var, also off by default: whether to check
for stack underflow when popping values.
(vm_engine): Don't declare object_count if we are not checking object
table accesses.
* libguile/vm-engine.h (CACHE_PROGRAM): Don't muck with object_count
if we are not checking object table accesses.
(CHECK_UNDERFLOW, PRE_CHECK_UNDERFLOW): Nop out if we are not checking
underflow.
(POP2, POP3): New macros which check for underflow before popping more
than one value.
* libguile/vm-i-loader.c (load_array):
* libguile/vm-i-scheme.c (set_car, set_cdr, vector_set, slot_set)
(BV_SET_WITH_ENDIANNESS, BV_FIXABLE_INT_SET, BV_INT_SET)
(BV_FLOAT_SET):
* libguile/vm-i-system.c (partial_cont_call, fix_closure, prompt)
(fluid_set): Use POP2 / POP3.
(local_set, long_local_set): Pop to locals instead of using values on
the stack then dropping; allows for underflow to be checked before the
value is accessed.
(BR): Don't NULLSTACK or DROP after the operation.
(br_if, br_if_not, br_if_eq, br_if_not_eq, br_if_null)
(br_if_not_null): Pop to locals before doing the compare and jump.
* libguile/vm-i-system.c (new-frame): Though it was appealing to set the
dynamic link here on the incomplete frame, we no longer do that, for
the reasons mentioned in the code.
(call, mv-call): Adapt to set the frame's dynamic link.
* libguile/vm-engine.c (vm_engine): Don't set dynamic link here, even
for boot program.
* libguile/frames.c (scm_frame_num_locals, scm_frame_local_ref)
(scm_frame_local_set_x): Fix up not-yet-active frame detection.
* libguile/vm-i-system.c (variable-ref, variable-set, variable-bound?):
Check that the argument is actually a variable. Thanks to Kevin
Holmes for the report.
* libguile/vm-engine.c (vm_engine): Error handling down here.
* THANKS: Update.
* libguile/fluids.c (scm_make_undefined_fluid, scm_fluid_unset_x)
(scm_fluid_bound_p): New functions.
(fluid_ref): New function; like scm_fluid_ref, but will not throw an
error for unbound fluids.
(scm_fluid_ref, swap_fluid): Use `fluid_ref'.
* libguile/fluids.h (scm_make_undefined_fluid, scm_fluid_unset_x)
(scm_fluid_bound_p): New prototypes.
* libguile/vm-i-system.c (fluid_ref): If fluid is unbound, jump to
`vm_error_unbound_fluid'.
* libguile/vm-engine.c (VM_NAME)[vm_error_unbound_fluid]: New error
message.
* test-suite/tests/fluids.test ("unbound fluids")["fluid-ref of unbound
fluid", "fluid-bound? of bound fluid", "fluid-bound? of unbound
fluid", "unbound fluids can be set", "bound fluids can be unset"]: New
tests.
* libguile/vm-i-system.c (variable-ref, toplevel-ref)
(long-toplevel-ref): Fixup callers.
* libguile/vm-engine.c (vm_error_unbound): Don't use vm-error for
unbound vars, use misc-error. Don't include VM: in the string. Take
the name directly in finish_args, not as a list.
* libguile/vm-i-system.c (VM_DEFINE_INSTRUCTION): Drop the stack items
corresponding the the with-fluids object. Thanks very much to Stefan
Israelsson Tampe for the fix.
* libguile/vm-i-scheme.c (symbol?, vector?): New
instructions. Renumbered the rest.
* libguile/vm-i-system.c: Renumber instructions.
* libguile/_scm.h (SCM_OBJCODE_MINOR_VERSION): Bump.
* module/ice-9/psyntax.scm (binding-type, binding-value): Define using
macros so that we inline to car and cdr opcodes. Oh, for an inliner :)
* module/language/tree-il/compile-glil.scm (*primcall-ops*)
* module/language/tree-il/primitives.scm
(*interesting-primitive-names*, *effect-free-primitives*)
(*effect+exception-free-primitives*): Add symbol? and vector?
inlines.
* libguile/vm-i-system.c (call_cc, tail_call_cc): Call the new
RESTORE_CONTINUATION_HOOK when a continuation is restored.
(prompt): Call the new ABORT_CONTINUATION_HOOK when entering the abort
handler's continuation.
* libguile/vm-engine.h (ABORT_CONTINUATION_HOOK)
(RESTORE_CONTINUATION_HOOK):
* libguile/vm.h (SCM_VM_ABORT_CONTINUATION_HOOK)
(SCM_VM_RESTORE_CONTINUATION_HOOK):
* libguile/vm.c: (scm_vm_abort_continuation_hook): New hook, called when
entering an abort handler.
(scm_vm_restore_continuation_hook): New hook, called after returning
to a continuation.
* module/system/vm/vm.scm: Add hooks to export list.
* libguile/vm.h (SCM_VM_PUSH_CONTINUATION_HOOK)
(SCM_VM_POP_CONTINUATION_HOOK): New hooks, to replace
enter/exit/return.
(SCM_VM_BOOT_HOOK, SCM_VM_HALT_HOOK, SCM_VM_BREAK_HOOK): Remove these
useless hooks.
* libguile/vm.c (scm_vm_push_continuation_hook)
(scm_vm_pop_continuation_hook): New accessors.
* libguile/vm-i-system.c: Remove boot, halt, break, enter, exit, and
return hooks. Also remove the break instruction. Instead now when we
push a new continuation onto the stack we call PUSH_CONTINUATION_HOOK,
and when we pop via a return we call POP_CONTINUATION_HOOK. APPLY_HOOK
is now decoupled from continuation pushes and pops.
* libguile/vm-engine.h:
* libguile/vm-engine.c: Adapt for hooks.
* module/system/vm/trace.scm (vm-trace): Adapt for hooks. Also revive
the #:instructions? #t mode.
* module/system/vm/vm.scm: Adapt exports for new set of hooks.
* libguile/vm-engine.c (VM_NAME)[vm_error_unbound]: Add comment.
* libguile/vm-i-system.c (variable_ref): Attempt provide the name of X
in FINISH_ARGS.
* libguile/vm-engine.c: Add func_name local, for error reporting.
(vm_error_apply_to_non_list): New error case.
(vm_error_wrong_type_arg): Remove this generic error case.
(vm_error_wrong_type_apply): Remove FUNC_NAME -- no sense in seeing
"vm-debug-engine" in the error report.
(vm_error_not_a_pair, vm_error_not_a_bytevector)
(vm_error_not_a_struct, vm_error_not_a_thunk): Use func_name instead
of FUNC_NAME, so we can indicate what caused the error.
* libguile/vm-i-scheme.c (VM_VALIDATE_CONS, car, cdr, set-car!)
(set-cdr!): Indicate provenance of errors.
(VM_VALIDATE_STRUCT, struct-vtable):
(VM_VALIDATE_BYTEVECTOR, BV_FIXABLE_INT_REF, BV_INT_REF)
(BV_FLOAT_REF, BV_FIXABLE_INT_SET, BV_INT_SET, BV_FLOAT_SET): Same.
* libguile/vm-i-system.c (apply, tail-apply): Use
vm_error_apply_to_non_list.
* libguile/vm-i-system.c (assert-nargs-ee/locals): New instruction, a
combination of assert-nargs-ee and reserve-locals in the case in which
nreq and nlocs can both be represented in 8 bits.
* module/language/glil/compile-assembly.scm (glil->assembly): Add
compiler case.
* doc/ref/vm.texi (Function Prologue Instructions): Update docs.
* libguile/pairs.h (scm_is_null): Nil is also null.
* libguile/vm-i-scheme.c (not, not-not, null?, not-null?):
* libguile/vm-i-system.c (br-if-null, br-if-not-null): Remove some more
nil special cases.
* libguile/boolean.h (scm_is_false): Recognize nil as false, by default.
(scm_is_bool): Recognize nil as a boolean.
* libguile/boolean.c (scm_not, scm_boolean, scm_to_bool, scm_is_bool):
Adapt to treat nil as false.
* libguile/vm-i-system.c (br-if, br-if-not): Just use scm_is_false
instead of specifically mentioning nil.
* libguile/vm-i-system.c (continuation_call): Sync before calling a
continuation. Shouldn't much matter, but it seems like a good idea.
(wind-fluids): More importantly, sync before allocating a with-fluids
object.
* libguile/control.h (SCM_PROMPT_HANDLER): Remove, it was unused.
(SCM_PROMPT_DYNWINDS): Rename from SCM_PROMPT_DYNENV.
* libguile/control.c: (scm_c_make_prompt): Take another arg, the winds
that are to be in place for the prompt. Fix allocation to be 4 words
instead of 5 (the handler was never used).
* libguile/eval.c (eval):
* libguile/throw.c (pre_init_catch): Adapt to scm_c_make_prompt change.
* libguile/vm-i-system.c (partial-cont-call): Grovel the new elements of
the wind list in order to call setjmp() on the new prompts. Pass
cookie to vm_reinstate_partial_continuation.
(prompt): Adapt to scm_c_make_prompt change.
* libguile/vm.c (vm_reinstate_partial_continuation): Take a cookie arg,
used when winding captured prompts onto the stack. Winding a prompt
implies making a new prompt, actually -- with new registers, a new
jump buffer, new winds, etc.
* test-suite/tests/control.test ("rewinding prompts"): Add a test for
rewinding prompts.
* libguile/control.h:
* libguile/control.c (scm_c_make_prompt): Instead of taking a VM arg,
take the registers directly.
(scm_c_abort): Declare as returning void. In fact it will never
return.
* libguile/eval.c (eval):
* libguile/throw.c (pre_init_catch): Adapt to prompt API change.
* libguile/vm-i-system.c (prompt): Pass the abort ip as the ip to
scm_c_make_prompt. This fixes a bug in which we used the "offset"
local var, but it wasn't guaranteed to be around after a longjmp.
* libguile/vm-engine.c (vm_error_continuation_not_rewindable):
* libguile/vm-i-system.c (partial-cont-call):
* libguile/vm.h (SCM_VM_CONT_PARTIAL_P):
(SCM_VM_CONT_REWINDABLE_P): Fix a bug in which we weren't checking if
a partial continuation was actually rewindable.
* libguile/control.c (cont_objcode):
* libguile/vm-i-system.c (partial-cont-call):
* libguile/vm.c (vm_reinstate_partial_continuation): Don't keep the
"external winds" in a partial continuation, as they aren't logically
part of the continuation. Reinstate the "internal winds" when entering
a partial continuation. Things seem to work!
* libguile/vm-i-system.c (partial-cont-call): Sync registers before
splatting a partial continuation, and cache them back afterwards.
* libguile/vm.c (vm_reinstate_partial_continuation): Actually implement,
except dynamic-wind.
* libguile/control.c (cont_objcode): Along with a bunch of boilerplate
that certainly needs to go in some central place, define this
continuation-calling trampoline.
(reify_partial_continuation): New function, returns a procedure that
when called will reinstate a partial continuation.
(scm_c_abort): Take an extra arg, the cookie. Actually reify a
continuation.
(scm_at_abort): Adapt to scm_c_abort change.
* libguile/control.h: Declare scm_c_abort change.
* libguile/vm-i-system.c (partial_cont_call): New instruction.
(call/cc, tail-call/cc): Adapt to scm_i_vm_capture_stack change.
(abort): Pass vm_cookie to abort.
* libguile/vm.h (SCM_F_VM_CONT_PARTIAL, SCM_F_VM_CONT_REWINDABLE): New
flags.
(struct scm_vm_cont): Add flags field.
(SCM_VM_CONT_PARTIAL_P, SCM_VM_CONT_REWINDABLE_P): New predicates.
* libguile/vm.c (scm_i_vm_capture_stack): Rename from
vm_capture_continuation, and make internal instead of static. Take a
flags argument.
(scm_i_vm_capture_continuation): Adapt to scm_i_vm_capture_stack
change.
(vm_abort): Plumb cookie to scm_c_abort.
(vm_reinstate_partial_continuation): New stub.
* libguile/control.h:
* libguile/control.c (scm_c_make_prompt): Take an extra arg, a cookie.
Continuations will be rewindable only if the abort has the same cookie
as the prompt.
(scm_at_abort): Redefine from scm_abort, and instead of taking rest
args, take the abort values as a list directly. Also, don't allow
rewinding, because we won't support rewinding the C stack with
delimited continuations.
* libguile/eval.c (eval): Adapt to scm_c_make_prompt change.
* libguile/vm-engine.c (vm_engine): Use vp->cookie to get a unique value
corresponding to this VM invocation.
* libguile/vm-i-system.c (prompt): Pass the cookie to scm_c_make_prompt.
(abort): Take an additional tail arg.
* libguile/vm.c (vm_abort): Parse out the abort tail arg. This is for
the @abort case, or the (apply abort ...) case.
(make_vm): Initialize the cookie to 0.
* libguile/vm.h (struct scm_vm): Add cookie.
* module/ice-9/boot-9.scm (abort): Define here as a trampoline to
@abort. Needed to make sure that a call to abort dispatches to a VM
opcode, so the cookie will be the same.
* module/language/tree-il.scm (<tree-il>): Add a "tail" field to
<abort>, for the (apply abort ...) case, or (@abort tag args). Should
be #<const ()> in the normal case. Add support throughout.
* module/language/tree-il/analyze.scm (analyze-lexicals): Add abort-tail
support here too.
* module/language/tree-il/compile-glil.scm (flatten): Compile the tail
argument appropriately.
* module/language/tree-il/primitives.scm (*primitive-expand-table*): Fix
@abort and abort cases to pass the tail arg to make-abort.
* libguile/control.h:
* libguile/control.c: Remove scm_atcontrol and scm_atprompt.
(scm_c_make_prompt): Remove handler arg, as the handler is inline.
(scm_abort): New primitive, exported to Scheme as `abort'. The
compiler will also recognize calls to `abort', but this is the base
case.
(scm_init_control): Remove scm_register_control, just have this
function, which adds `abort' to the `(guile)' module.
* libguile/eval.c (eval): Add SCM_M_PROMPT case.
* libguile/init.c (scm_i_init_guile): Change scm_register_control call
into a nice orderly scm_init_control call.
* libguile/memoize.h: (scm_sym_at_prompt, SCM_M_PROMPT):
* libguile/memoize.c (MAKMEMO_PROMPT, scm_m_at_prompt, unmemoize): Add
prompt support to the memoizer.
* libguile/vm-i-system.c (prompt): Fix to not expect a handler on the
stack.
* module/ice-9/boot-9.scm (prompt): Add definition in terms of @prompt.
* module/ice-9/control.scm: Simplify, and don't play with the compiler
here, now that prompt and abort are primitive.
* module/ice-9/eval.scm (primitive-eval): Add a prompt case.
* module/language/tree-il/primitives.scm
(*interesting-primitive-names*): Add @prompt and prompt.
* libguile/control.h:
* libguile/control.c (scm_c_abort): Add an implementation of `abort',
but it doesn't reify the continuation yet.
* libguile/vm-i-system.c (abort):
* libguile/vm.c (vm_abort): Wire up the call to `abort', avoiding
consing the args into a list.
* module/language/tree-il/compile-glil.scm (flatten): Add some compily
bits that can allow the abort to be resumed.
* libguile/vm-engine.c (vm_engine): Cache the dynamic state in a local
var when we enter the VM.
* libguile/vm-i-system.c (wind-fluids, unwind-fluids): Use the cached
dynamic state instead of going through SCM_I_CURRENT_THREAD.
* libguile/control.h:
* libguile/control.c (scm_c_make_prompt, SCM_PROMPT_PRE_UNWIND_HANDLER):
* libguile/vm-i-system.c (prompt)
* module/language/tree-il.scm (<prompt> prompt-pre-unwind-handler):
* module/language/tree-il/analyze.scm:
* module/language/tree-il/compile-glil.scm:
* module/language/tree-il/inline.scm:
* module/language/tree-il/primitives.scm: Remove the "pre-unwind"
handler from prompt; it turns out not to be necessary. Adapt all
references.