Fixes <https://bugs.gnu.org/32786>.
'scm_atomic_compare_and_swap_scm' is a thin wrapper around
'atomic_compare_exchange_weak' (where available), and therefore it may
spuriously fail on some platforms, leaving the atomic object unchanged
even when the observed value is equal to the expected value. Since
'scm_atomic_compare_and_swap_scm' returns both a boolean result and the
observed value, the caller is able to detect spurious failures when
using that API.
'atomic-box-compare-and-swap!' presents a simpler API, returning only
the observed value. The documentation advises callers to assume that
the exchange succeeded if the observed value is 'eq?' to the expected
value. It's therefore not possible to report spurious failures with
this API.
'atomic-box-compare-and-swap!' uses 'scm_atomic_compare_and_swap_scm',
and prior to this commit would simply ignore the boolean result and
return the observed value. In case of spurious failures, the caller
would legitimately conclude that the exchange had succeeded.
With this commit, 'atomic-box-compare-and-swap!' now retries in case of
spurious failures.
* libguile/atomic.c (scm_atomic_box_compare_and_swap_x): If
'scm_atomic_compare_and_swap_scm' returns false and the observed value
is equal to 'expected', then try again.
* libguile/vm-engine.c (atomic-box-compare-and-swap!): Ditto.
* doc/ref/compiler.texi (Bytecode): Update macro-assembler instructions,
and move most of them to the instruction set reference.
* doc/ref/vm.texi (A Virtual Machine for Guile, VM Programs): Minor
fixes.
(Instruction Set): Update for Guile 3 instruction set.
* libguile/vm-engine.c (vm_engine): Update a few instruction
docstrings.
* libguile/jit.c (compile_s64_numerically_equal): Remove as this
instruction was removed in previous refactoring.
(compile_atomic_scm_set_immediate), compile_atomic_scm_ref_immediate):
Adapt to change in C name of these instructions.
* libguile/vm-engine.c: Add comments for all instructions.
* libguile/vm-engine.c (abort): If the abort doesn't need to longjmp and
the abort hook was enabled, cache registers first to avoid restoring
a bad IP to the VM.
* libguile/loader.h (SCM_OBJCODE_MINIMUM_MINOR_VERSION):
(SCM_OBJCODE_MINOR_VERSION): Bump version.
* module/system/vm/assembler.scm (*bytecode-minor-version*): Bump.
* libguile/vm-engine.c: Rearrange opcodes to be contiguous and in a
somewhat sensible order.
* libguile/jit.c: Wrap the whole thing in ENABLE_JIT.
* libguile/threads.c (on_thread_exit):
* libguile/vm.c (scm_call_n):
* libguile/init.c (scm_i_init_guile):
* libguile/vm-engine.c (VM_NAME): Wrap calls into jit.c with ENABLE_JIT.
* configure.ac: Move up AC_CANONICAL_TARGET, as autoconf was complaining
about it coming after AC_ARG_PROGRAM.
* acinclude.m4 (GUILE_ENABLE_JIT): Fix to honor --enable-jit arg.
* libguile/vm.c (scm_i_vm_emergency_abort): New helper: an abort that
doesn't allocate, not even stack.
* libguile/throw.c (abort_to_prompt): Use scm_i_vm_emergency_abort.
* libguile/vm.h: Declare helper.
* libguile/vm.c (vm_clear_mcode_return_addresses): New helper.
(vm_recompute_disable_mcode): Force a thread to deoptimize if hooks
become enabled.
(scm_call_n): Don't enter mcode if it's disabled. Also check the right
flag for when to run the abort hook (the abort_hook_enabled flag).
* libguile/vm-engine.c (instrument-entry, instrument-loop)
(return-values, abort, compose-continuation): Don't enter mcode if mcode
is disabled for this thread.
* libguile/vm.h (SCM_VM_NUM_HOOKS): Remove hook enumeration.
(struct scm_vm): Re-arrange members to be more dense and to use common
cache lines for commonly-used members. Declare hooks and their enabled
flags by name.
* libguile/vm-engine.c (RUN_HOOK): Refer to hooks by name.
* libguile/vm.c (FOR_EACH_HOOK): New helper.
(vm_hook_compute_enabled, vm_recompute_disable_mcode): New routines to
recompute when hooks are enabled, and whether to disable mcode because
hooks are active.
(set_vm_trace_level): New helper.
(invoke_hook): Take hook to invoke by value.
(DEFINE_INVOKE_HOOK): Refactor to use named hooks.
(scm_i_vm_prepare_stack): Init named hooks.
(VM_ADD_HOOK, VM_REMOVE_HOOK): Refactor to use named hooks, and also
recompute global disable_mcode flag.
(scm_set_vm_trace_level_x, scm_c_set_vm_engine_x): Use internal helper.
* libguile/threads.h (struct scm_thread): Move the embedded "struct
scm_vm" earlier in the scm_thread. Since the VM (and the JIT) access
VM data (SP, FP, etc) through the thread pointer, this allows more
accesses to be encoded in shorter instruction sequences.
* libguile/intrinsics.h (SCM_FOR_ALL_VM_INTRINSICS): Remove VM hook
intrinsics, now that we're going to rely on the interpreter for
stepping and breakpoints.
* libguile/jit.c (struct scm_jit_state): Remove "hooks_enabled" member,
now that we won't JIT. Remove all code related to calling hooks.
* libguile/vm-engine.c (RUN_HOOK): Call hooks directly instead of
through intrinsics. Use precise per-hook enable flags.
* libguile/vm.c (DEFINE_INVOKE_HOOK): New helper. Use to define the
hook invokers.
* libguile/vm.h (SCM_VM_ABORT_HOOK): Rename from
SCM_VM_ABORT_CONTINUATION_HOOK.
* libguile/vm-engine.c (ABORT_HOOK):
* libguile/vm.c (invoke_abort_hook): Adapt to SCM_VM_ABORT_HOOK name
change.
(reset_vm_hook_enabled): New helper.
(VM_ADD_HOOK, VM_REMOVE_HOOK): New helper macros, replacing
VM_DEFINE_HOOK.
(scm_vm_add_abort_hook_x, scm_vm_remove_abort_hook_x)
(scm_vm_add_apply_hook_x, scm_vm_remove_apply_hook_x)
(scm_vm_add_return_hook_x, scm_vm_remove_return_hook_x)
(scm_vm_add_next_hook_x, scm_vm_remove_next_hook_x): New functions,
replacing direct access to the hooks. Allows us to know in a more
fine-grained way when to enable hooks.
(scm_set_vm_trace_level_x): Use reset_vm_hook_enabled to update the
individual hook_enabled flags.
* module/statprof.scm:
* module/system/vm/coverage.scm:
* module/system/vm/traps.scm:
* module/system/vm/vm.scm: Adapt VM hook users to the new API.
* libguile/jit.c (struct code_arena): New data type.
(struct scm_jit_state): Add code arena member.
(allocate_code_arena): New helper.
(emit_code): New helper. Emits code into a thread-local code arena.
(compute_mcode): Allow for failure to JIT.
(scm_jit_compute_mcode): Stop automatic JIT compilation on resource
exhaustion.
* libguile/jit.c (compile_call_scm_from_scm_scm): Add fast paths for
inum add and sub.
(compile_call_scm_from_scm_uimm): Add fast paths for inum
add/immediate and sub/immediate.
(compile_less): Add fast path for inum compare.
* libguile/jit.c (compile_check_arguments)
(compile_check_positional_arguments): Fix these functions. The
compiler uses "jge" as a "compare result not NONE", but the VM
instructions set NONE on greater-than, not greater-than-or-equal.
Sad!
* libguile/vm-engine.c (instrument-entry, instrument-loop): Make the
counter check >=, so that we can set the threshold to 0 and still get
compilation.
* libguile/jit.h (enum scm_jit_counter_value): Make the increments
event.
* libguile/jit.c (jit_log_level): New local.
(_LOG, INFO, DEBUG, LOG): New macros.
(compile1):
(compute_mcode):
(scm_jit_enter_mcode): Use new logging macros.
* libguile/jit.c (jit_stop_after, jit_pause_when_stopping): New locals.
(scm_jit_compute_mcode): Add ability to stop after N compilations.
(scm_jit_enter_mcode): Comment out printfs for the time being.
(scm_init_jit): Init locals from environment variables.
* libguile/jit.c (compile1): Add debug for when instructions are first
compiled. Will be removed when all is working.
(compute_mcode): Add debugging about what code is compiled.
(scm_sys_jit_compile): Remove per-instruction output.
(scm_jit_compute_mcode): Actually compile JIT code. Use
GUILE_JIT_COUNTER_THRESHOLD to control when JIT happens.
* libguile/jit.c (scm_jit_counter_threshold): Make a static variable
instead of a compile-time constant.
(scm_init_jit): Init scm_jit_counter_threshold from
GUILE_JIT_COUNTER_THRESHOLD environment variable. Default is -1
indicating "never JIT".
* libguile/vm-engine.c (instrument-entry, instrument-loop): Adapt to new
variable.
* libguile/control.c (compose_continuation_code): Fix offset of code
end.
* libguile/jit.c (compile_compose_continuation): Fix test for mcode not
null.
* libguile/jit.c (compile_prompt): Actually push the MRA arg.
(analyze): Mark call continuations as entries, as both FP and SP are
set then, and also mark prompt handlers as entries (and blocks).
* libguile/intrinsics.c (add_immediate, sub_immediate, less_p)
(numerically_equal_p): Add fast paths. Makes one test locally go from
.77s interpreted to .60s.
(scm_to_uint64_truncate): Add a likelihood annotation.