* libguile/__scm.h (SCM_ALIGNED): New macro.
* libguile/_scm.h: Include "libguile/strings.h", to make the
string/stringbuf-related constants visible to snarffed code.
* libguile/snarf.h (SCM_SUPPORT_STATIC_ALLOCATION): New macro.
(SCM_SYMBOL, SCM_GLOBAL_SYMBOL)[SCM_SUPPORT_STATIC_ALLOCATION]: New
alternative versions of these macros with support for (almost) static
allocation via the use of `string->symbol'.
(SCM_IMMUTABLE_DOUBLE_CELL, SCM_IMMUTABLE_STRINGBUF,
SCM_IMMUTABLE_STRING): New macros.
* libguile/tags.h (SCM)[SCM_DEBUG_TYPING_STRICTNESS==1]: Use a pointer
type that is compatible with other pointer types, to avoid potential
violation of strict aliasing rules.
* libguile/strings.h (scm_tc7_ro_string, SCM_I_STRINGBUF_F_SHARED,
SCM_I_STRINGBUF_F_INLINE): New macros.
* libguile/strings.c (STRINGBUF_F_SHARED): Alias for
`SCM_I_STRINGBUF_F_SHARED'.
(STRINGBUF_F_INLINE): Alias for `SCM_I_STRINGBUF_F_INLINE'.
(RO_STRING_TAG): Alias for `scm_tc7_ro_string'.
* libguile/vm.h (struct scm_vm_cont):
* libguile/vm.c (capture_vm_cont, reinstate_vm_cont): Change so we just
store the registers as they are, with the reloc.
(vm_cont_mark): Only mark the stack if it has elements on it, otherwise
we get a bogus fp.
* libguile/stacks.c (scm_make_stack): Update for change to vm
continuations.
Because of how Guile saves and restores continuations (by copying the
stack), and how it uses alloca to create space for debug information
on the stack, we must have an alloca() that really does use the stack,
and not one that uses the heap.
To do this, we use the Gnulib "alloca-opt" module instead of "alloca".
This commit also updates the Gnulib sources from the current Gnulib
Git repository.
* benchmark/measure.scm (measure): Fix bitrot.
* libguile/vm.c (VM_ENABLE_STACK_NULLING): Undefine this, as it hasn't
caught any errors in quite a while.
* libguile/vm-engine.h (PUSH_LIST): Add a parameter to check that the
list was proper.
* libguile/vm-i-system.c: Adapt PUSH_LIST callsites to pass SCM_NULLP or
SCM_NULL_OR_NIL_P, as appropriate. Add a check to return/values*.
* libguile/vm.c: Add lang.h header for SCM_NULL_OR_NIL_P.
* test-suite/tests/elisp.test: Fix XFAIL for elisp + apply.
* doc/ref/vm.texi (Stack Layout): Update to remove references to the
"heap link".
* gdbinit: Update for "heap link" removal.
* libguile/frames.c:
* libguile/frames.h: Update macros and diagram for removal of "heap
link". As part of this, we also remove "heap frames", replacing them
with "vm frames", which are much like the interpreter's debug objects,
but for VM stacks. That is to say, they don't actually hold the stack
themselves, just the pointers into stack that's held by a continuation
(either captured or current).
* libguile/stacks.c (stack_depth, read_frames): Since a "stack" object is
really a copy of information that comes from somewhere else, it makes
sense to copy over info from the VM, just as `make-stack' does from the
evaluator. The tricky bit is to figure out how to interleave VM and
interpreter frames. We do that by starting in the interpreter, and
whenever the current frame's procedure is actually a program, we switch
to the VM stack, switching back when we reach a "bootstrap frame". The
last bit is hacky, but it does work...
(is_vm_bootstrap_frame): Hacky predicate to see if a VM frame is a
bootstrap frame.
(scm_make_stack): Accept a VM frame in addition to debug frames.
Probably has some bugs in this case. But in the case that the arg is
#t (a common case), do the right thing, capturing the top VM frame as
well, and interleaving those frames appropriately on the stack.
As an accident, we lost the ability to limit the number of frames in
the backtrace. We could add that back, but personally I always want
*all* frames in the trace... Narrowing still works fine, though there
are some hiccups sometimes -- e.g. an outer cut to a procedure that
does a tail-call in VM code will never find the cut, as it no longer
exists in the continuation.
* libguile/vm.h (struct scm_vm): So! Now that we have switched to save
stacks in the normal make-stack, there's no more need for `this_frame'
or `last_frame'. On the other hand, we can take this opportunity to fix
tracing: when we're in a trace hook, we set `trace_frame' on the VM,
so we know not to fire hooks when we're already in a hook.
(struct scm_vm_cont): Expose this, as make-stack needs it to make VM
frames from VM continuations.
* libguile/vm.c (scm_vm_trace_frame): New function, gets the current
trace frame.
(vm_mark, make_vm): Hook up the trace frame.
(vm_dispatch_hook): New hook dispatcher, with a dynwind so it does the
right thing if the hook exits nonlocally.
* libguile/vm-engine.c (vm_run): No more this_frame in the wind data.
* libguile/vm-engine.h (RUN_HOOK): Run hooks through the dispatcher.
(ALIGN_AS_NON_IMMEDIATE, POP_LIST_ON_STACK): Remove unused code.
(NEW_FRAME): Adapt for no HL in the frame.
* libguile/vm-i-system.c (goto/args, mv-call, return, return/values):
Adapt for no HL in the frame.
* module/system/vm/frame.scm:
* module/system/vm/vm.scm: Beginnings of some reworkings, needs more
thought.
* libguile/backtrace.c (display_backtrace_get_file_line): If the source
is a vector, treat it as a #(line column file) vector, as emitted by
the VM. Needs subsequent patches to make sense.
This reverts commit f3e3f530c2, which is
appropriate because subscription is not now required for someone to
send a message to bug-guile@gnu.org.
Conflicts:
* libguile/Makefile.am (guile_LDFLAGS): Remove `@DLPREOPEN@' since it
has no effect.
* libguile/guile.c (main): Don't invoke `LTDL_SET_PRELOADED_SYMBOLS ()'
since it had no effect given how we invoke `libtool'. It also fixes
compatibility issues when using libltdl 1.5 with a Libtool 2.2
package.
* libguile/strings.c (scm_string_ref): Add proper range checking for the
empty string.
(scm_string_set_x): Likewise.
Reported by Bill Schottstaedt <bil@ccrma.Stanford.EDU>.
* test-suite/tests/strings.test ("string-ref"): New test prefix.
("string-set!")["empty string", "empty string and non-zero index",
"out of range", "negative index", "regular string"]: New tests.
* NEWS: Update.
This fixes bug #24009 reported by Martin Pitt.
* libguile/threads.c (guilify_self_1): Check the return value of
pipe(2).
(scm_std_select): Use `full_read ()' instead of `read ()' when reading
from WAKEUP_FD.
* libguile/async.c (scm_i_queue_async_cell): Use `full_write ()' instead
of write(2) when writing to SLEEP_FD.
* libguile/fports.c (fport_flush): Likewise.
* libguile/posix.c (getgroups): Use the return value of getgroups(2) as
NGROUPS.
(scm_nice): Get the return value of nice(2) to make glibc happy.
* libguile/scmsigs.c (take_signal): Use `full_write ()' instead of
write(2).
We recently modified scm_c_read so that it temporarily swaps the
caller's buffer with the port's normal read buffer, in order to
improve performance in the case where the port is unbuffered (which
actually means having a single-byte buffer) - but we implemented the
swap in the buffered case too. The latter turns out to be a bad idea
- because it means that the C code of a custom port implementation
cannot rely on a port's buffer always being the same as when it was
first set up - and so this commit reverts that. The buffer swapping
trick now applies to unbuffered ports only.
* libguile/ports.c (scm_c_read): Only do swapping of port and caller
buffer for unbuffered ports.
* NEWS: Update.
* libguile/threads.c (scm_i_init_thread_for_guile): When the thread is
already guilified, update `t->base' so that it corresponds to the new
stack base. Bug report and patch by Linas Vepstas <linasvepstas@gmail.com>.
* test-suite/standalone/Makefile.am (test_scm_with_guile_CFLAGS,
test_scm_with_guile_LDADD): New.
(check_PROGRAMS, TESTS): Add `test-scm-with-guile'.
* libguile/eval.c (scm_debug_opts): Whereas, today's machines are larger
than yesterday's; GCC consumes more words per stack frame than it used
to; and you can get quite some recursion in a halfway-compiled system,
be it resolved: let's bump up the C stack limit to 40k words (160 kB /
320 kB, depending on word size).
This reverts par of "Document the failure of `gc.test' wrt. unused modules."
(commit 328efeb9a6.)
* ice-9/boot-9.scm (set-module-eval-closure!): Don't set the `module' property
on CLOSURE.
* libguile/modules.c (scm_lookup_closure_module): Call `abort ()' to make it
clear that code that uses the `module' property no longer works. That code
is unused anyway.
* libguile/vm-i-system.c (return/values): In the
multiple-values-to-a-single-value-continuation (or MV but where N=1),
null out the correct number of values from the stack. Fixes aborts on
(apply values '(1)).
* testsuite/t-values.scm (call-with-values): Add a test.
* libguile/vm-i-system.c (call, goto/args): Handle the case in which a
non-program (i.e. interpreted program or a subr) returns multiple
values.
* testsuite/t-values.scm: Add test case that exhibited this problem.
* libguile/procs.c (scm_make_procedure_with_setter): Patch through the
getter's procedure name to the procedure-with-setter. Fixes part of the
srfi-17 test, as the VM doesn't set procedure-name on define -- but
perhaps that is the bug that should be fixed. In any case this patching
is cheap.
* test-suite/tests/eval.test: Change so that (define name pws) is
initially passed an anonymous procedure-with-setter, as was the case
before the procs.c change.
* libguile/smob.c (scm_smob_prehistory): When initializing
SMOB_GC_KIND, pass 1 as the CLEAR_NEW_OBJECTS argument to
`GC_new_kind ()'. Without this, an assertion failure is
triggered in libgc's `reclaim.c'.
* libguile/goops.c (get_slot_value, set_slot_value): While keeping the
inlined getter/setter dispatch for closures, allow the getters and
setters to be any kind of procedure.
* oop/goops.scm (compute-getters-n-setters): Relax the checks on
getter/setter procedures, so that if a getter is a procedure but not a
closure, we don't try to poke its arity.
* oop/goops/Makefile.am (SOURCES): Compile all the goops submodules!
* oop/goops/old-define-method.scm: Removed, in an act of housekeeping.
* oop/goops/compile.scm:
* oop/goops/dispatch.scm: Break a circular module dependency by making
sure that (oop goops) is loaded when we go to compile submodules.
* oop/goops/compile.scm (compile-method/memoizer)
(compile-method/memoizer+next): Allow a procedure without source
through. This can happen with getter and setter lambdas that were
compiled, and in that case there is no next-method call anyway. Ideally
we should be able to specify compile-method for accessor methods...
* libguile/goops.c (scm_sys_initialize_object): Don't assume that an init
thunk is a closure; just go through scm_call_0 instead.
* oop/goops/compile.scm (make-make-next-method/memoizer): Allow for the
case that the next method is compiled.
The `on_thread_exit ()' function allocates memory via libgc. When
called from the context of a pthread key detructor, the thread is
essentially "dead" already and `GC_lookup_thread ()' returns NULL,
which triggers an assertion in libgc's `thread_local_alloc.c'. This
patch arranges so that `on_thread_exit ()' is called from a suitable
context.
* libguile/threads.c (on_thread_exit): Remove now invalid comment
about access to libgc's TLS.
(init_thread_key): Don't pass `on_thread_exit ()' to
`scm_i_pthread_key_create ()'.
(scm_leave_guile_cleanup): Invoke `do_thread_exit ()'.
(really_launch): Invoke `pthread_exit ()'.
* libguile/eval.i.c (type_dispatch, apply_vm_cmethod)
(apply_memoized_cmethod): Tweak the nastiness a bit more so as to deal
with the '(no-method) empty entries. I would like to stop the search if
the cdr isn't a pair, but currently with the inlined memoized bits, the
cdr is a pair. The fix would be to make the memoizer return a procedure
and not the already-inlined bits -- slightly slower but the vm will be
faster anyway.
* libguile/objects.c (scm_mcache_lookup_cmethod): Same fixes here.
* oop/goops/dispatch.scm (cache-hashval, cache-try-hash!): Allow non-list
cmethod tails.
* ice-9/boot-9.scm (make-modules-in): Change to make sure that we are
making modules in modules; that is, that a global binding of `compile'
doesn't prevent a module from importing a submodule named `compile'.
(resolve-module): Clean up a bit, and serialize the logic.
* libguile/objects.c (scm_mcache_lookup_cmethod, scm_apply_generic):
* libguile/eval.i.c (CEVAL): Now that cmethod entries can have a program
as their tail instead of a memoized proc, we have to change the halting
condition on the method cache search, in both places: the one that's
inlined into eval.i.c and the one in objects.c. If the cmethod isn't a
pair, apply it.
* libguile/goops.c (make): In the `make' procedure that's used before
GOOPS is booted, bind #:formals, #:body, and #:compile-env on methods.
* oop/goops/compile.scm (compute-entry-with-cmethod): There was a
terrible trick here that involved putting a dummy pair in the cache,
then modifying it in place with the result of memoization. The note
claimed that this was to cut recursion short, or something. I can't see
how it could recurse, given that `methods' is changing each time. Also,
the pair trick doesn't work with byte-compiled methods. So, remove it.
(compile-method): Dispatch to the appropriate method compiler, based on
whether the method was defined with the interpreter or with the
compiler.
(make-next-method): New function, generically computes a `next-method'
procedure, though the caller has to supply the arguments.
(compile-method/vm): Exciting method byte compiler!
(make-make-next-method/memoizer, compile-method/memoizer): Add the
/memoizer suffix, and move all this code to the bottom of the file.
* ice-9/boot-9.scm (compile-time-environment): Remove definition from
boot-9 -- instead, autoload it and `compile' from (system base
compile).
* libguile/objcodes.h:
* libguile/objcodes.c (scm_objcode_to_program): Add an optional argument,
`external', the external list to set on the returned program.
* libguile/vm-i-system.c (externals): New instruction, returns the
external list. Only used by (compile-time-environment).
* libguile/vm.c (scm_load_compiled_with_vm): Adapt to
scm_objcode_to_program change.
* module/language/scheme/translate.scm (translate): Actually pay
attention to the environment passed as an argument.
(custom-transformer-table): Expand out (compile-time-environment) to
something that can be passed to `compile'.
* module/system/base/compile.scm (*current-language*): Instead of
hard-coding `scheme' in various places, use a current language fluid,
initialized to `scheme'.
(compile-file, load-source-file): Adapt to *current-language*.
(load-source-file): Ada
(scheme-eval): Removed, no one used this.
(compiled-file-name): Don't hard-code "scm" and "go"; instead use the
%load-extensions and %load-compiled-extensions.
(cenv-module, cenv-ghil-env, cenv-externals): Some accessors for
compile-time environments.
(compile-time-environment): Here we define (compile-time-environment)
to something that will return #f; the compiler however produces
different code as noted above.
(compile): New function, compiles an expression into a thunk, then runs
the thunk to get the value. Useful for procedures. The optional second
argument can be either a module or a compile-time-environment; in the
latter case, we can recompile even with lexical bindings.
(compile-in): If the env specifies a module, set that module for the
duration of the compilation.
* module/system/base/syntax.scm (%compute-initargs): Fix a bug where the
default value for a field would always replace a user-supplied value.
Whoops.
* module/system/il/ghil.scm (ghil-env-dereify): New function, takes the
result of ghil-env-reify and turns it back into a GHIL environment.
* scripts/compile (compile): Remove some of the tricky error handling, as
the library procedures handle this for us.
* test-suite/tests/compiler.test: Add a test for the dynamic compilation
bits.
* libguile/Makefile.am (stack-limit-calibration.scm): Use $(srcdir), to
support building in a different directory.
(MOSTLYCLEANFILES): Add stack-limit-calibration.scm.
* ice-9/boot-9.scm (compile-time-environment): Return #f instead of
erroring under the interpreter, a bit more sane.
* libguile/goops.c (create_standard_classes):
* libguile/goops.h (scm_si_formals, scm_si_body, scm_si_compile_env):
* oop/goops.scm (method, initialize): Add `formals', `body', and
`compile-env' slots to <method>.
* libguile/threads.h (held_mutex): New field.
* libguile/threads.c (enqueue, remqueue, dequeue): Use critical
section to protect access to the queue.
(guilify_self_1): Initialize held_mutex field.
(on_thread_exit): If held_mutex non-null, unlock it.
(fat_mutex_unlock, fat_cond_free, scm_make_condition_variable,
fat_cond_signal, fat_cond_broadcast): Delete now unnecessary uses
of c->lock.
(fat_mutex_unlock): Pass m->lock to block_self() instead of
c->lock; move scm_i_pthread_mutex_unlock(m->lock) call from before
block_self() to after.
(scm_pthread_cond_wait, scm_pthread_cond_timedwait,
scm_i_thread_sleep_for_gc): Set held_mutex before pthread call;
reset it afterwards.
I was seeing a hang in srfi-18.test, when running make check in master,
in the "exception handler installation is thread-safe" test. It wasn't
100% reproducible, so looked like a race.
The problem is that wait-condition-variable is not actually
atomic in the way that it is supposed to be. It unlocks the mutex,
then starts waiting on the cond var. So it is possible for another
thread to lock the same mutex, and signal the cond var, before the
wait-condition-variable thread starts waiting.
In order for wait-condition-variable to be atomic - e.g. in a race
where thread A holds (Scheme-level) mutex M, and calls
(wait-condition-variable C M), and thread B calls (begin (lock-mutex
M) (signal-condition-variable C)) - it needs to call pthread_cond_wait
with the same underlying mutex as is involved in the `lock-mutex'
call. In terms of the threads.c code, this means that it has to use
M->lock, not C->lock.
block_self() used its mutex arg for two purposes: for protecting
access and changes to the wait queue, and for the pthread_cond_wait
call. But it wouldn't work reliably to use M->lock to protect C's
wait queue, because in theory two threads can call
(wait-condition-variable C M1) and (wait-condition-variable C M2)
concurrently, with M1 and M2 different. So we either have to pass
both C->lock and M->lock into block_self(), or use some other mutex to
protect the wait queue. For this patch, I switched to using the
critical section mutex, because that is a global and so easily
available. (If that turns out to be a problem for performance, we
could make each queue structure have its own mutex, but there's no
reason to believe yet that it is a problem, because the critical
section mutex isn't used much overall.)
So then we call block_self() with M->lock, and move where M->lock is
unlocked to after the block_self() call, instead of before.
That solves the first hang, but introduces a new one, when a SRFI-18
thread is terminated (`thread-terminate!') between being launched
(`make-thread') and started (`thread-start!'). The problem now is
that pthread_cond_wait is a cancellation point (see man
pthread_cancel), so the pthread_cond_wait call is one of the few
places where a thread-terminate! call can take effect. If the thread
is cancelled at that point, M->lock ends up still being locked, and
then when do_thread_exit() tries to lock M->lock again, it hangs.
The fix for that is a new `held_mutex' field in scm_i_thread, which is
set to point to the mutex just before a pthread_cond_(timed)wait call,
and set to NULL again afterwards. If on_thread_exit() finds that
held_mutex is non-NULL, it unlocks that mutex.
A detail is that checking and unlocking held_mutex must be done before
on_thread_exit() calls scm_i_ensure_signal_delivery_thread(), because
the innards of scm_i_ensure_signal_delivery_thread() can do another
pthread_cond_wait() call and so overwrite held_mutex. But that's OK,
because it's fine for the mutex check and unlock to happen outside
Guile mode.
Lastly, C->lock is then not needed, so I've removed it.
* libguile/threads.h (held_mutex): New field.
* libguile/threads.c (enqueue, remqueue, dequeue): Use critical
section to protect access to the queue.
(guilify_self_1): Initialize held_mutex field.
(on_thread_exit): If held_mutex non-null, unlock it.
(fat_mutex_unlock, fat_cond_free, scm_make_condition_variable,
fat_cond_signal, fat_cond_broadcast): Delete now unnecessary uses
of c->lock.
(fat_mutex_unlock): Pass m->lock to block_self() instead of
c->lock; move scm_i_pthread_mutex_unlock(m->lock) call from before
block_self() to after.
(scm_pthread_cond_wait, scm_pthread_cond_timedwait,
scm_i_thread_sleep_for_gc): Set held_mutex before pthread call;
reset it afterwards.
I was seeing a hang in srfi-18.test, when running make check in master,
in the "exception handler installation is thread-safe" test. It wasn't
100% reproducible, so looked like a race.
The problem is that wait-condition-variable is not actually
atomic in the way that it is supposed to be. It unlocks the mutex,
then starts waiting on the cond var. So it is possible for another
thread to lock the same mutex, and signal the cond var, before the
wait-condition-variable thread starts waiting.
In order for wait-condition-variable to be atomic - e.g. in a race
where thread A holds (Scheme-level) mutex M, and calls
(wait-condition-variable C M), and thread B calls (begin (lock-mutex
M) (signal-condition-variable C)) - it needs to call pthread_cond_wait
with the same underlying mutex as is involved in the `lock-mutex'
call. In terms of the threads.c code, this means that it has to use
M->lock, not C->lock.
block_self() used its mutex arg for two purposes: for protecting
access and changes to the wait queue, and for the pthread_cond_wait
call. But it wouldn't work reliably to use M->lock to protect C's
wait queue, because in theory two threads can call
(wait-condition-variable C M1) and (wait-condition-variable C M2)
concurrently, with M1 and M2 different. So we either have to pass
both C->lock and M->lock into block_self(), or use some other mutex to
protect the wait queue. For this patch, I switched to using the
critical section mutex, because that is a global and so easily
available. (If that turns out to be a problem for performance, we
could make each queue structure have its own mutex, but there's no
reason to believe yet that it is a problem, because the critical
section mutex isn't used much overall.)
So then we call block_self() with M->lock, and move where M->lock is
unlocked to after the block_self() call, instead of before.
That solves the first hang, but introduces a new one, when a SRFI-18
thread is terminated (`thread-terminate!') between being launched
(`make-thread') and started (`thread-start!'). The problem now is
that pthread_cond_wait is a cancellation point (see man
pthread_cancel), so the pthread_cond_wait call is one of the few
places where a thread-terminate! call can take effect. If the thread
is cancelled at that point, M->lock ends up still being locked, and
then when do_thread_exit() tries to lock M->lock again, it hangs.
The fix for that is a new `held_mutex' field in scm_i_thread, which is
set to point to the mutex just before a pthread_cond_(timed)wait call,
and set to NULL again afterwards. If on_thread_exit() finds that
held_mutex is non-NULL, it unlocks that mutex.
A detail is that checking and unlocking held_mutex must be done before
on_thread_exit() calls scm_i_ensure_signal_delivery_thread(), because
the innards of scm_i_ensure_signal_delivery_thread() can do another
pthread_cond_wait() call and so overwrite held_mutex. But that's OK,
because it's fine for the mutex check and unlock to happen outside
Guile mode.
Lastly, C->lock is then not needed, so I've removed it.