PROCLAIM-CLASS in ccmp had the following form in its body:
(ext:with-backend
:c/c++ (register-in-ccmp)
:bytecmp (register-globally))
with a clear intention, that CCMP-compiled code should use the first path, and
BCMP-compiled code should use the second. But that's not what this operator
does. This operator caused, that when CCMP was compiled with CCMP, then it
always took (register-in-ccmp) path (even for bytecodes compiler(!)), while when
CCMP was compiled with BCMP (i.e with a flag --disable-shared and compiler is
not builtin), then modifying global instance was always called, disregrading
whether we were compiling with CCMP or BCMP at the moment.
We've replaced this with a more precise statement that decides at runtime which
compiler to chose:
(if *compiler-in-use*
(register-in-ccmp)
(register-globally))
The other part of the problem was that registering the class definition globally
in the bytecodes compiler (or in ccmp when --disable-shared was true), could
redefine existing class in runtime environment with a forward-referenced-class,
and that lead to the environment corruption. Consider:
(compile-file "foo.lisp" :load t) ;defines globally at load time "#<standard-class foo>"
(compile-file "foo.lisp" :load nil) ;defines globally at compile time "#<forward-class foo>"
So after compiling the second file, we don't have the standard class foo, that
we may depend on in later files.
Fixes#843.
Before the last release we've introduced a new dispatch character macro #" that
reads into base strings in the compiler environment, but si_load_bytecodes used
it only for the first read form, something like:
(let ((forms (with-ecl-syntax () (read-forms strm t))))
(loop for forms = forms then (read-forms strm nil)
while forms do
(process forms)))
So if the file had more than one toplevel #Y, the reader broke on #"".
Fixes#842.
Before the last release we've introduced a new dispatch character macro #" that
reads into base strings in the compiler environment, but si_load_bytecodes used
it only for the first read form, something like:
(let ((forms (with-ecl-syntax () (read-forms strm t))))
(loop for forms = forms then (read-forms strm nil)
while forms do
(process forms)))
So if the file had more than one toplevel #Y, the reader broke on #"".
Fixes#842.
When mprotect is used as a cheap interrupt protection, the environment must be
page-aligned. For static data we'd need to use a kludge (or alignas that is not
part of C99) -- the simplest thing is to use the same mechanism to allocate the
first environment as the rest. That will ensure page alignment when mprotect is
used (that is, when mmap allocates the environment).
This was not possible before (in !341), because back then, when mmap was not
used, we've been using the garbage collector to allocate th environment, but now
we use the manual allocator.
Fixes#828.
clang miscompiles some functions since the version 17; we bump the version from
19 to 22, because it was confirmed that it is still the case. Fixes#838.
When mprotect is used as a cheap interrupt protection, the environment must be
page-aligned. For static data we'd need to use a kludge (or alignas that is not
part of C99) -- the simplest thing is to use the same mechanism to allocate the
first environment as the rest. That will ensure page alignment when mprotect is
used (that is, when mmap allocates the environment).
This was not possible before (in !341), because back then, when mmap was not
used, we've been using the garbage collector to allocate th environment, but now
we use the manual allocator.
Fixes#828.
clang miscompiles some functions since the version 17; we bump the version from
19 to 22, because it was confirmed that it is still the case. Fixes#838.
This compiler is:
- not fully conformant
- hard to obtain (despite free versions existing)
- requires numerous kludges
- requires separate build system so many changes need to be duplicated
Fixes#809.
When we have processed local nicknames, we've copied the list, but local
nicknames are an assoc list ((a . b) (c . d)) etc, in other words, conses were
still shared with the original form; calling RPLACA and RPLACD modified the
original form, so when it was loaded back, the bytecodes compiler had problems,
because the list contained a literal package instead of the string.
Fixes#839.
2026-02-12 Didier Verna <didier@didierverna.net>
* src/clos/boot.lsp (make-empty-standard-class): New argument SIZE.
Default it to the length of standard class slots. Pass it on to
SI:ALLOCATE-RAW-INSTANCE.
* src/clos/hierarchy.lsp (+class-hierarchy+): Set it to the length
of structure class slots when creating the STRUCTURE-OBJECT class.
Closes!362.
We were dropping type information in some cases.
First, let bindings are implemented by first assigning the result of
evaluating the initialization forms to temporary variables and then
setting the real variables once all initialization forms have been
evaluated. If type declarations for the variables in the let form were
present, we were not applying them to the temporary variables. This is
particularly problematic for variables which are later on found to be
constant. The compiler has become slightly smarter now and will
eliminate the variables, leaving only the temporary variables and
forgetting the type information in the process.
Second, if the type was declared to be read-only, then we were not
taking into account type declarations and only relying on the inferred
type of the initalization form.
The optimization allows the compiler to use more precise type
information. This can be used to remove unnecessary boxing of
variables, see e.g. the disassembly of the following code:
(lambda (i)
(declare (fixnum i))
(code-char (mod i 128)))
The optimization was removed in commit
c7da5bc919. The promised FCALL-ARG
destination has not been implemented so far, thus we restore the old
implementation for now.
Xcode 26 distributes a clang version which identifies itself with
__clang_major__=17 and that is also affected by the bug for which the
workaround in commit 2fbdd292af was
added.
Closes#825.
build-module on rebuild reloads only files that have changes, so if we had
updated only sockets.lisp, then the package is not defined when the file is
recompiled and loaded.
This introduces unneeded boxing of constant values, e.g. in
> (disassemble (lambda (x) (< x 4.0)))
/* function definition for GAZONK */
/* optimize speed 3, debug 0, space 0, safety 2 */
static cl_object L1c__gazonk(cl_object v1x)
{
cl_object env0 = ECL_NIL;
const cl_env_ptr cl_env_copy = ecl_process_env();
cl_object value0;
ecl_cs_check(cl_env_copy,value0);
L1:;
value0 = ecl_make_bool(ecl_lower(v1x,ecl_make_single_float((float) 4. )));
cl_env_copy->nvalues = 1;
return value0;
}
The same would apply to complex floats if we were to handle them in
the same manner.