Don't use a simple-vector for storage, as it essentially wasted 12 bytea
per vector (counting all the 0s in the header and length words).
Rather than invent a new primitive object, this change uses a variable-length
INSTANCE, similarly to how CONDITION primitive objects are represented,
yielding somewhere between 5% to 10% space reduction for those data,
which is significant if have >16MiB of 'em eating up heap space.
There is no savings for #-compact-instance-header, but there are easy ways
to remedy that: (1) invent a new headered primitive object that is vector-like
but with the length in the header, (2) put a bit in an instance header saying
that next word which would ordinarily be a LAYOUT is not, (3) just use the
LAYOUT slot for whatever we like, and make GC robust against failure.
Option (3) isn't actually too unsafe - the 0th info element is a fixnum.
Of course there's always option (4) - implement #+compact-instance-header.
And there's no real benefit for 32-bit, since there wasn't as much waste.
A few more points to note:
- SYMBOL-INFO-VECTOR got renamed to SYMBOL-DBINFO, and SYMBOL-INFO to
SYMBOL-%INFO for the primitive slot to try to keep things clearer
as to which accesses the globaldb.
- It wasn't worth redoing all the specialized vops for SYMBOL-PLIST
that would have been needed, so they're all gone.
- these days we don't need so much of the "!" convention for removing
unnecessary symbols rom the core, since the tree-shaker does that.
It is a completely unnecessary complication because:
- The cross-compiler, a program defined by a subset of 'build-order.lisp-expr',
either gets compiled right, or doesn't. If it does, then it must not have any
forward references within itself to global symbols.
- That SAME program is compiled again, as the compiler, so if it worked to
compile it in make-host-1, it should work to compile it in make-host-2.
- This leaves open to question whether any of the runtime files not common
to both make-host passes contain forward references (the "remedy" for which
was to use DEF!CONSTANT). There are (at least) three better fixes:
(1) Fix the build order. Correct code should not forward-reference constants.
(2) If the use of the constant is injected by a source-transform or macro
whose expander was defined in make-host-1 and whose constant value
was also defined in make-host-1, the expanded code can contain
the VALUE of the constant, not the name of the constant.
(3) In a pinch, "#." might do the trick. While potentially the least desirable
fix, it is more explainable then yet another means (such as is DEF!foo)
of injecting definitions into the cross-compiler despite that it has not
digested a defining forms. (See ADDRESS-BASED-COUNTER-VAL, which is
cross-compiled before 'objdef'. It needs the host's value of a thread
slot offset, but in an inline function, not a macro.)
The main idea is that info values are stored in a vector attached to
each symbol when possible. When not possible, the storage reverts
to the volatile [sic] environment, but still using a vector as the
payload instead of the chained hashing/alist approach.
This strives to be very fast at lookup at the expense of some added
complexity during updates. Performance testing suggests that it is
at least 2x to 3x faster at (INFO :class :type name), and FBOUNDP
is almost 4x faster. In a repeatable test, a file that took 1.8 seconds
to compile now takes 1.7 seconds but with more consing (as expected).
sbcl.core itself increases in size by <1% for 64-bit architecture,
and less for 32-bit architecture because there is proportionaly less
wasted space. A compact environment's table is effectively the
concatenation of all info vectors into one, so the added overhead is
in vector headers. However the fallback hash is now smaller,
so there used to be more wasted cells in the compact env.
Eventually the compact and volatile environments will both go away,
but not until the quasi-lockfree hashtable bootstraps properly.
The problem is an inability to use raw slots in early cold init.
It's actually not a problem of using them - the compiled code is ok -
but cold-init drops into 'ldb' due to how defstruct expands.
Among the bugs fixed by this (not straightforwardly testable) is that
the compact environment would hold into symbols that became otherwise
inaccessible. It no longer does, but still holds onto other names.
This patch builds with CCL as host, and for 32-on-64 and vice-versa,
so nothing seems terribly broken in terms of assumptions made.
* Coalesce non-circular lists, bit-vectors, and non-base-strings in the
file-compiler. (We could do more, but these are the "easy" ones.) Takes
care of OPTIMIZATIONS #34 in practice: outside the file compiler one can
still trick the system into similar behaviour, but that seems a fairly
academic concern.
* Never go through SYMBOL-VALUE at runtime to fetch the value of a constant
variable in compiled code.
* Use (SYMBOL-VALUE <NAME>) as the load-form to dump references to named
constants into fasls.
* Signal a continuable error if an attempt to change the SYMBOL-VALUE of a
constant variable is made.
* Assignments to undefined variables go through SET, so that one
cannot accidentally modify a constant by doing something like:
(defun set-foo (x) (setq foo x))
(defconstant foo 42)
(set-foo 13)
* Gets rid of INFO :VARIABLE :CONSTANT-VALUE, and just uses SYMBOL-VALUE to
store constant values.
* Move definition of SB!XC:LAMBDA-LIST-KEYWORDS to be beginning of the build,
and use it instead of the host LAMBDA-LIST-KEYWORDS where appropriate.
* Tests.
Test that the cross-compiler knows about constants on startup
... or at least at the end of being built
SunOS versions less than 5.8 now fully supported (thanks to Eric
Marsden for diagnosis and testing)