Because GC scavenging is more finicky now that it does not necessarily
proceed strictly object-by-object, non-zeroing could have caused
inadvertent floating garbage at best, or a crash at worst.
In general any cons with most-positive-word in the car.
I do like the idea of using -1 because it is unambiguously a filler
where (0 . 0) is possibly a real cons.
This test had a tendency to prevent the non-GC worker threads from running,
and/or cause heap exhaustion. Sometimes it would report thousands of GCs instead
of the expected couple of dozen or so. And ironically, tests that hammer on
GC rather than let it auto-trigger can cause garbage to promote from gen0
to gen1 on each cycle filling up gen1 by accident. The auto-trigger isn't
able to compensate for this unusual use-case by triggering in time.
This was a very misleading change. This does not actually allow one to
block compile multiple files, and this approach can't work to actually
do so. The only thing it does is essentially the equivalent of
concatenating fasl files, which third party tools like ASDF can
already do. None of the state variables for compilation like ir1
namespacing get shared, which is crucial for block compilation.
We probably want to do multi-file block compilation through
WITH-COMPILATION-UNIT, or if we are going to do the "different
signature" route, we should go back to having source infos handle
multiple files, like CMU CL, as that is more efficient and more
general, because it actually treats multiple files as one thing to
read forms out of.
The parent commit added functionality to allow the normal compiler to
produce smaller fasls than the fopcompiler in many cases, without a
real compile-time or load-time tradeoff. Therefore, remove the
fopcompiler, as it adds a lot of complexity and needs to be turned off
on high debug or instrumentation. As a bonus, the fopcode space is
freed up a bit.
It also suffers from multiple macroexpansion. Some things this allows
us to simplify:
* No need to have LOAD-FORM-IS-DEFAULT-MLFSS-P be used in the
compiler. The way we used it was sketchy anyway.
* The compiler and loader no longer need to keep track of skipping on
the FOP stack, or whether LOAD-TIME-VALUE needs it to be done or not.
For top level forms we now smash top level lambdas into one component,
as if we were block compiling. We do it automatically 20 tlls at a
time, which significantly reduces the number of components that need
to get loaded and called at load time, reducing fasl size. Unlike CMU
CL, we've solved the problems of package environment interaction, so
that the optimization is semantically sound.
I also found a solution for recursive IR1 namespacing with respect to
forcing top level lambda smashing before emitting load time value and
constant junk, as it was causing problems with constant infos not
getting cleaned up properly. CMU CL also ran into this issue, but took
one step forward and one step back by removing a force call and adding
another one. Fix this by doing both force calls.
As a representative of compiling a large file, compiling
"src/compiler/node.lisp"
- with no tlf smashing: produces a fasl of 940039 bytes.
- with fop compilation: produces a fasl of 830003 bytes.
- with tlf smashing 20 forms at a time: produces a fasl of 752591 bytes.
Compiling ironclad shows no difference in speed. Loading the resulting
fasls also shows no measurable difference in speed when TIMEd.
Since we use the normal compiler, we don't sacrifice any debuggability
or coverage instrumentation, as well as avoiding issues with multiple
macroexpansion. This also opens up the possibility of using a real
byte-compiler in conjunction with tlf smashing to squeeze out even
more bytes out of fasls for loading top level code. The ir1-based cmu
cl byte compiler, for example, gets 6x space savings over (risc)
machine code on average (cf. cmu documentation). Note from the above
that fop-based byte compilation does not even produce more compact
code than machine code once top level lambdas are merged.
The fopcompiler will get removed in a subsequent change.
When delaying toplevel form execution until after component loading in
the loader, shadowing would not effect the package environment
correctly during fasloading. Fix this by recording whether inheritance
for the symbol is allowed at the point of dumping. We are allowed to
do this because the specification says that in conforming code, the
package environment during compilation should be congruent to the
package environment during fasload.
This is the most expedient fix, but this could probably be done better
in a way that unifies the accessibility logic in cold load.
We share the logic for deprecation warnings between compile file and
fasload, so that the same exact conditions are signalled when
fasloading as during compilation. This also significantly simplifies
the loader, as well as making it less flaky with respect to trying to
literally grovel the fop stack for a hardcoded pattern which doesn't
manifest at all on higher debug or coverage
instrumentation (specifically relying on fopcompilation to happen).
Check consistency doesn't work here on high debug. In addition, the
original test case didn't call for it anyway. The reason it doesn't
work is that signalling a compiler error while compiling breaks the
consistency of the IR. That's just how it is.
This essentially restores the state of things prior to rev d2ca90b6
but with the advantage of ahead-of-time compiling the anonymous
(and oxymoronic) writer functions for readonly slots.
When implementing variable-length trailing bitmaps, I half forgot that
there were variable-length data for the layout IDs of :INCLUDEd types.
C code was right but some Lisp code wasn't. BITMAP-NWORDS was right
if the depthoid did not require appending to the reserved ID words.
There is space for 6 included IDs by default (STRUCTURE-OBJECT being
implicit), so for typical structure definitions, no bug was evident.
Integer< checks for all INTEGERs, which includes fixnums. Separate
VOPs could work on bignums, but (and bignump (< x 0)) are probably
rare.
Fixes lp#1970154
Never JIT-compile a writer for a readonly slot. Instead when macroexpanding
DEFSTRUCT, always create anonymized incarnations of each slot accessor
and hand those to the CLOS class installer. Thusly all rigmarole about whether
there is a pair of globally BOUNDP function names per slot is irrelevant.
Our representation selection has been improved enough for a while
now (maybe since e6c2b1771c, or
earlier), such that we don't indiscriminately just store all
double-floats in an unboxed format. Update some tests to reflect that.
Instead of trying to materialize immediate values greater than 32
bits, which is hard to do GC-safely on riscv64, don't treat >32 bit
immediate values as immediates at all. Rather, always treat them as
boxed constants. If we ever fix up how immediates are materialized on
riscv64, such that no untagged intermediates could possibly be loaded
into descriptor-regs, then we can go back to loading in immediates for
all fixnum values.
This also corrects a misunderstanding on what immediate-constant-sc is
supposed to do, as tested for in vm.before-xc.lisp. It's actually
entirely backend/implementation dependent for what we treat as an
immediate. It just happened that on 32-bit MIPS, encoded fixnums
coincided with the conveniently materializable immediate, so the idea
of fixnum = immediate got adopted to the other platforms, even when
this wasn't the original design intention.
And also give SAPs the same treatment.
This change allows compiling
(lambda (stream unsigned-p)
(let ((number (readnum-helper stream unsigned-p)))
(cond ((null number) nil)
((sb-ext:float-nan-p number) :nan)
((= number sb-ext:double-float-positive-infinity) number)
((= number sb-ext:double-float-negative-infinity) :-inf)
(t :number))))
at all as well as inferring the return type
(or (single-float +inf +inf) (double-float +inf +inf)
(member nil :nan :inf :number))
The reason for the single float positive infinity in the return type
is that
(= sb-ext:single-float-positive-infinity
sb-ext:double-float-positive-infinity) => t
while
(eql sb-ext:single-float-positive-infinity
sb-ext:double-float-positive-infinity) => nil
This simplifies rebinding of the warning and note muffler, and allows
tracing or otherwise intercepting system-generated compilation.
Also: gensym is considered harmful. I'm noticing tons of compilations
to the identical lambda, and it's a lot easier to figure out why
without having to think about symbols that differ for no good reason.
(I suspect that if N threads all need to invoke a GF for the first time
at about the same time, they'll all cache miss, and then all compile
the identical dfun. This is horrible and is need of good solution)
This idiom is used for a loop on a list where inspection or other
action needs to be taken on the list during the rest of each
iteration. It is straightforwardly reordered by using CAR rather than
POP in the variable clause, and performing POP in the body.
Strictly speaking the variable clauses introduced by `for` must
precede the main clause introduced by `repeat`. By placing the repeat
after the for, the semantics of the loop are changed observably in the
presence of a `finally` clause, which will see the effect of one extra
step of the iteration variable (and, if the step has side-effects,
those side-effects happen one more time).
Split the type (simd-pack[-256] integer) into (simd-pack[-256] (A B)),
where A is one of {signed-byte,unsigned-byte} and where B is one of
{8,16,32,64}. The benefits of doing so are more precise static type
checking, and a more helpful printed representation of integer SIMD packs.
Additionally, introduce a simd-pack[-256]-any primitive type that can be
used to implement VOPs whose implementation is independent of the actual
SIMD pack type, such as %simd-pack-low or %simd-pack-256-0. This way, we
can get rid of the clumsy sb-vm:simd-pack[-256]-dispatch macros that lead
to unnecessary code bloat.