Compare commits

..

1084 commits

Author SHA1 Message Date
Stas Boukarev bf95715fa5 arm64, return ldp/stp optimization: fix constants reuse
Some checks are pending
CL-host / sbcl (push) Waiting to run
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-09-10 09:29:28 +03:00
Aaron Estrada d1afdc52ec x86-64: fix EVEX disassembly for vpmovzx/vpmovsx and ymm-ymm-imm register extension
- Allow EVEX printer generation for vpmovsx* (#x20-#x25) and vpmovzx*
  (#x30-#x35) in map 0F38 in avx2-inst-printer-list.
- Use xmmreg/mem for 4x/8x widening conversions and half-ymmreg/mem for 2x
  widening conversions so source operands disassemble with their correct
  architectural register width (XMM or YMM).
- Define evex-ymmreg-b to incorporate EVEX.X / B' (bit 4) for register-direct
  operands in EVEX-ymm-ymm-imm format, correctly decoding registers 16-31 for
  vpslldq, vpsrldq, and shift/rotate instructions.
- Widen register bounds checks in print-ymmreg-rm, print-ymmreg-vvvv,
  print-ymmreg, and print-xmmreg from (unsigned-byte 4) to (mod 32).
- Add regression tests in tests/simd-pack-512.pure.lisp.
2026-09-09 21:30:10 -06:00
Stas Boukarev 0077dde930 Better bignum multiplication
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Do not cons positive bignums at the start of the loop, the result can
be adjusted in place by subtraction at the end.
On arm64 and x86-64, write the whole loop in assembly, not just the
first iteration.
2026-09-10 03:29:54 +03:00
Douglas Katzman 3d4fe67e29 build-all-cores 2026-09-09 16:14:36 -04:00
Stas Boukarev e6455a7841 Remove an ignore
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-09-09 11:01:39 +03:00
Stas Boukarev 4669caad14 make-host-1: better diagnostics on style-warning stoppage
Give with-compilation-unit to finish and print its thing.
2026-09-09 11:00:17 +03:00
Stas Boukarev 0dc9bd7f2f Stop early on make-host-1 warnings 2026-09-09 09:18:38 +03:00
Stas Boukarev fe329fb1f4 Remove unused functions 2026-09-09 09:18:19 +03:00
Stas Boukarev f4a731c355 Warn about improper lists created by list* 2026-09-09 07:46:37 +03:00
Stas Boukarev d6c5a50395 Catch bad array dimensions in (make-array (list -1 x)) 2026-09-09 07:39:07 +03:00
Stas Boukarev 248bbb1fff (concatenate (string (code-char i))) splice the character directly
As is already done with (concatenate 'string (list (code-char i)))
2026-09-09 06:34:22 +03:00
Stas Boukarev f64c78d96e arm64: simplify decode-logical-immediate 2026-09-09 05:43:40 +03:00
Stas Boukarev 9aadfb046e sb-pcl::whitespacep don't defeat optimizations 2026-09-09 05:42:59 +03:00
Stas Boukarev 1e992bfe97 riscv: add support for Zba
Some checks are pending
CL-host / clisp (push) Waiting to run
CL-host / ecl (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Predicated by *backend-subfeatures*

Patch by Faried Nawaz.
2026-09-09 04:45:54 +03:00
Stas Boukarev f47b711b3e Account for commutativity when finding iteration steps
(incf x y) actually expands into (setq x (+ y x)), and
iteration-step-values only checks the first argument. Using
combination-match brings commutative matching automatically.
Then the set isn't reoptimized when y changes, again looking for the
first argument.
2026-09-09 04:26:39 +03:00
Aaron Estrada ed317dc00c fix(sb-simd): define missing-instruction fallbacks for sap-ref on unsupported CPUs
- In define-vrefs.lisp, emit define-missing-instruction forms for ,sap
  and (setf ,sap) when the target instruction set is not available.
  Prevents unattached definition errors during package validation
  (e.g. F64.8-SAP-REF on hosts without AVX-512 support).
- In missing-instruction.lisp, use record-instruction-set and
  record-name rather than instruction-record-* aliases so that
  missing-instruction error reporting works for sap-ref and other
  function records inheriting from base record.
- Verified under Intel SDE Haswell (-hsw) and Skylake (-skl) emulation
  with 0 errors (737 tests, 9,992,078 checks passed).
- Verified natively on Zen 4 host with 0 regressions (737 tests,
  13,860,908 checks passed).
2026-09-09 02:17:04 +03:00
Aaron Estrada 336b6ae146 feat(sb-simd): guard constant folding and missing instructions on unsupported CPU targets
- define-instruction-vops.lisp: only declare foldable on defknown when
  the underlying instruction set is available on the host CPU.
- define-scalar-casts.lisp: gate sb-c:foldable on instruction-set-available-p.
- define-associatives.lisp, define-reducers.lisp, define-comparisons.lisp,
  define-unequals.lisp, define-ifs.lisp: fallback to define-missing-instruction
  when the instruction set is unavailable on the host. This prevents compile-time
  constant folding from attempting to evaluate vector constructors or instructions
  on host CPUs lacking the requisite instruction set extensions.
2026-09-09 02:17:04 +03:00
Aaron Estrada 0dc8bb88d2 feat(sb-simd): add modular AVX-512_FP16 vector support (f16.32, f16.16, f16.8)
- cpu-identification.lisp: add avx512fp16-supported-p detection via CPUID
  leaf 7 subleaf 0 EDX bit 23.
- packages.lisp: export avx512fp16-supported-p and define sb-simd-avx512fp16
  package extending sb-simd-avx512dq.
- instruction-sets/avx512fp16.lisp: define :avx512fp16 instruction set
  introducing half-precision float vectors:
  * f16.32 (512-bit ZMM, 32 lanes)
  * f16.16 (256-bit YMM, 16 lanes)
  * f16.8 (128-bit XMM, 8 lanes)
  * Vector arithmetic (vaddph, vsubph, vmulph, vdivph, vsqrtph, vminph,
    vmaxph, vrcpph, vrsqrtph, vscalefph)
  * FMA with :encoding :fma (vfmadd213ph, vfmsub213ph, vfnmadd213ph, vfnmsub213ph)
  * Conversions (f32.16 <-> f16.16, s32.16 <-> f16.16)
  * Bitwise logic and casts
- define-custom-vops.lisp: add f16.32-not to def-not macrolet.
- x86-64-fake-vops.lisp: add f16.8-broadcast, f16.16-broadcast, and
  f16.32-broadcast fake VOPs.
- record.lisp & test-suite/utilities.lisp: replace deprecated
  :sb-simd-pack-256 and :sb-simd-pack-512 feature guards with :x86-64.
- test-packages.lisp: validate sb-simd-avx512fp16 symbol bindings.
2026-09-09 02:17:04 +03:00
Aaron Estrada 16a029c1e0 feat(sb-simd): add modular AVX-512F, AVX-512BW, and AVX-512DQ vector support 2026-09-09 02:17:04 +03:00
Aaron Estrada 9c92f31492 x86-64: fix vbroadcastss and vbroadcastsd EVEX over-promotion
In avx2-insts.lisp, vbroadcastss and vbroadcastsd mistakenly checked
(or (xmm-register-p src) (zmm-register-p dst)) to decide whether to
emit EVEX. Because f32.4-broadcast passes src in single-reg (XMM),
this caused 128-bit and 256-bit AVX broadcast instructions to be encoded
with EVEX prefixes (62 f2 ...), raising SIGILL on hosts lacking AVX-512
support.

Fix the condition to check (zmm-register-p dst). Standard emit-avx2-inst
already auto-promotes operands using registers 16-31 to EVEX.
2026-09-09 02:17:04 +03:00
Aaron Estrada 2428c1efd0 x86-64: implement AVX-512_FP16 instruction set and CPUID detection
- avx2-insts.lisp: expand EVEX prefix encoder to support 3-bit mmm
  opcode map selection, enabling Map 5 (#b101) and Map 6 (#b110).
- x86-64-arch.c: add runtime CPUID detection for AVX-512_FP16
  (leaf 7, subleaf 0, EDX bit 23) guarded by OS ZMM state enablement.
- avx512-insts.lisp: implement complete AVX-512_FP16 instruction suite:
  * vector and scalar arithmetic (vaddph/sh, vsubph/sh, vmulph/sh,
    vdivph/sh, vminph/sh, vmaxph/sh, vsqrtph/sh, vrcpph/sh, vrsqrtph/sh,
    vscalefph/sh)
  * fused multiply-add (vfmadd*ph/sh, vfmsub*ph/sh, vfnmadd*ph/sh,
    vfnmsub*ph/sh, vfmaddsub*ph, vfmsubadd*ph, vfcmaddcph, vfmaddcph)
  * comparisons and classification (vcmpph/sh, vcomish, vucomish,
    vfpclassph/sh, vrndscaleph/sh)
  * conversions (vcvtph2psx, vcvtps2phx, vcvtdq2ph, vcvtph2dq,
    vcvttph2dq, vcvtuw2ph, vcvtw2ph, vcvtph2w, vcvtph2uw, vcvttph2w,
    vcvttph2uw, vcvtsd2sh, vcvtss2sh, vcvtsi2sh, vcvtsh2si, vcvttsh2si)
  * scalar and GPR moves (vmovsh, vmovw)
  * masked instruction variants with {k} and {z} zeroing
- tests/assembler.pure.lisp: verify bit-exact binary emission and
  round-trip disassembly across all FP16 instruction categories.
2026-09-09 02:17:02 +03:00
Aaron Estrada ce548a2163 x86-64: fix EVEX vmovsd/vmovss emitters, GPR vector move length, and 64-byte inline constant alignment
- avx512-insts.lisp: pass explicit W=1 for vmovsd (64-bit float) and
  W=0 for vmovss to prevent #UD on EVEX scalar moves. Fix 3-operand
  emitter ordering (ModRM r/m in thing, first source in vvvv).
- avx2-insts.lisp: force :ll 0 for GPR-to-vector moves (vmovd/vmovq)
  promoted to EVEX to prevent invalid 512-bit vector length prefixes.
- insts.lisp: cap emit-inline-constant alignment to sb-assem::max-alignment
  so 64-byte :zword constants respect code object alignment bounds.
2026-09-09 02:16:32 +03:00
Aaron Estrada 0546c92588 x86-64: add AVX-512CD, AVX-512VNNI, and AVX-512BF16 instruction definitions 2026-09-09 02:16:32 +03:00
Aaron Estrada 94f65cecd8 x86-64: update avx512-insts.lisp header to reflect implemented instruction subsets 2026-09-09 02:16:32 +03:00
Aaron Estrada db9c8af135 x86-64: add AVX-512 instruction definitions (vcmpps, vbroadcast, arithmetic)
- Add EVEX compare-to-mask instructions (vcmpps, vcmppd, vcmpss, vcmpsd)
  with opmask destination and optional input opmask.
- Extend vbroadcastss to accept XMM register sources with auto-promotion.
- Extend vpbroadcastd/vpbroadcastq with GPR32/64 sources (opcode #x7C)
  and XMM vector sources.
- Fix kmovd/kmovq GPR transfer prefix and W bits (#xF2 prefix).
- Add 14 masked arithmetic and logic instructions with opmask and
  zero-masking ({z}) support.
- Add AVX-512 EVEX test cases to tests/assembler.pure.lisp.
2026-09-09 02:16:32 +03:00
Stas Boukarev 4c24ec8547 case: warn about duplicate keys in the same clause 2026-09-09 02:16:11 +03:00
Stas Boukarev e019d6a878 arm64: reuse the last comparison in default-unknown-values 2026-09-09 01:47:29 +03:00
Stas Boukarev 2fc0da234d x86-64: off by one when binding multiple values 2026-09-09 01:47:29 +03:00
Stas Boukarev a156c041d9 Inline FIXNUMIZE 2026-09-09 01:47:29 +03:00
Stas Boukarev 9bdb6b51ba arm64: improve load-immediate-word 2026-09-09 01:47:29 +03:00
Stas Boukarev a95d3f5c50 Fix block-compilation of the build
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-09-08 20:12:52 +03:00
Charles Zhang d57ec16e2a ir1opt: Allow %analyze-set-uses to look through let bindings as well
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Which helps loops where the index wrapped around or transformed by
intermediate immutable variable bindings.

This particularly helps type inference for SSA form programs where
multiple sets correspond to fresh variable bindings that are related
through the bindings.
2026-09-08 11:19:28 +02:00
Stas Boukarev fe75c79a88 Uncommenet accidentally commented out code 2026-09-08 08:57:12 +03:00
Stas Boukarev 6531116f2b transform-union-typep: don't put double-floats into a member call
Checking for double-float-p first is better.
2026-09-08 08:19:54 +03:00
Stas Boukarev 8faeac79a9 Better type transform for rational/integer types with different bounds
Check integers first instead of splitting things into ranges.
2026-09-08 07:40:55 +03:00
Stas Boukarev 4df6bfd828 Fix a typep transform when mixing integers and rationals 2026-09-08 07:10:40 +03:00
Stas Boukarev a42c09f297 Fix cut-to-width
The logand mask has to be checked to be unsigned

Fixes lp#2166725
2026-09-08 06:07:34 +03:00
Douglas Katzman d79b179ccb Clean up fixedobj_points_to_younger 2026-09-07 22:25:59 -04:00
Stas Boukarev 81b27ad777 Remove debugging code
[skip ci]
2026-09-08 04:33:17 +03:00
Stas Boukarev b7fb00e028 Disable a flaky test 2026-09-08 04:14:50 +03:00
Stas Boukarev 9c365edb59 x86-64: set the right cost for a VOP 2026-09-08 04:02:15 +03:00
Stas Boukarev d638084646 Be more diligent about deleted nodes in do-nodes :restart-p t
Fixes lp#2166714
2026-09-08 03:51:58 +03:00
Stas Boukarev 39aa19ebee combination-match: transition some logand and logtest transforms 2026-09-08 03:41:33 +03:00
Stas Boukarev 3ce92c6341 Better &rest and cast handling in combination-match
Some checks are pending
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-09-07 20:21:36 +03:00
Charles Zhang 731c203ff2 Add a WITH-TEST.
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-09-07 11:48:56 +02:00
Charles Zhang bc2c8e1fa9 constraint: Handle equality constraints for local calls generally.
Which allows us to do bounds elimination for the attached test cases.

The constraint propagation code to handle general local calls now
resembles something like a cross between the code that handles LET and
SET, corresponding to the fact that local call binds variables as LET
does but also must clear existing information while propagating some
of the old information as SET does.
2026-09-07 11:48:56 +02:00
Charles Zhang 4a1cbf4f1a constraint: Improve assignment lambda handling.
Assignment lambdas have first order control flow like let lambdas
do. So we can just do global constraint propagation around their
blocks like normal instead of having to reason about higher-order
control flow through local calls.

This speeds things up by not having to do conset bookkeeping in local
calls and stopping the leading blocks optimization. Possibly as a
consequence, it also seems to derive more constraints this way as
shown in the attached test case.

In any case, this is clearly how assignment lambdas should be
handled (by that I mean the same type propagation logic as with other
local call function kinds, but without needing higher order control
flow reasoning), so mark the old TODO item around assignment lambdas
as finished.
2026-09-07 11:48:56 +02:00
Charles Zhang 1ac5b145ea constraint: Handle LET and MV-LET in the local call logic.
It doesn't matter too much, but putting the logic for let and mv-let
where the other local call logic is makes it clearer that these
propagate constraints from local call arguments to
variables. Otherwise we were bending backwards a bit to find the call
node just to do that. Whereas the bind node is not something we care
about at all, and could not generalize to e.g. ASSIGNMENT or the other
functional kinds.

It also makes it obvious that we don't handle mv-combinations.
2026-09-07 11:48:56 +02:00
Charles Zhang 9412c7ab71 Remove some unnecessary checks.
And declare a type.
2026-09-07 11:48:56 +02:00
Stas Boukarev 3e6f374427 More options for combination-match 2026-09-07 10:58:55 +03:00
Stas Boukarev bb2895f75a Transfer a couple more uses from combination-match to combination-match2 2026-09-07 10:03:49 +03:00
Stas Boukarev 3ca74b1072 Fix a logcount transform
Fixes lp#2166634
2026-09-07 08:13:43 +03:00
Stas Boukarev 2880c35e95 Add aliases to combination-match 2026-09-07 05:17:39 +03:00
Douglas Katzman 0d46c3c373 Delete obsolete comment
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Linked lists of objects are not the right way to implement layout remsets
2026-09-06 21:22:09 -04:00
Douglas Katzman 9bc9b7ceaf Add with-pinned-objects where needed for "documentation"
This is kind of a no-op for x86-64 and doesn't actually improve the situation
for arm64. When fixedobj space was changed to use software card marking instead
of mprotect, I wanted to avoid creating more hand-written asm code, and I also
thought at the time that the remembered set of modified layouts would be more
than just setting a card mark. But it ended up as just that.
2026-09-06 21:21:19 -04:00
Douglas Katzman c23e7716ae Fix sb-vm::with-pseudo-atomic-foreign-calls
The intent is to say that here is logic which it not machine-specific and so
we're not going to put it inside of pseudo-atomic inside of a vop, but it needs
to act as if it was pseudo-atomic.
For sb-safepoint, even though as the comment said it "could" be controlled
by an optimize decl, it was not getting done. For nonstop-foreign-call not only
should we skip emitting instructions to save the stack pointer and possibly
take a stop-for-gc trap, we must insert the pseudo-atomic barrier instructions,
otherwise the foreign code would receive a stop-for-gc signal as if in lisp.

And the implementation really should get finished for the architecturs other
than x86-64, though it does not seem to be as critical and I'm not sure why.
The uses guarded by #+immobile-space are clearly unimportant unless immobile
space exists, but uses involving dlopen and dladdr seem important.
2026-09-06 20:36:25 -04:00
Stas Boukarev 53d0b3c4ff Invent a new combination matching macro to do it all 2026-09-07 03:28:02 +03:00
Stas Boukarev 313fd89575 Fix the combination-match macro around :sole-dest
Fixes lp#2166618 lp#2166617
2026-09-06 21:18:08 +03:00
Stas Boukarev e8407e53ce Don't change the number of values types in transforms
Some checks are pending
CL-host / clisp (push) Waiting to run
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Fixes lp#2166598
2026-09-06 17:11:59 +03:00
Stas Boukarev 935551f30a Don't ash large integers in an integer-length transform
Fixes lp#2166599
2026-09-06 17:11:59 +03:00
Stas Boukarev 7ec2408a9d ltn-analyze-mv-bind: discard more unused variables
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
So that default-unknown-values doesn't need to.
2026-09-06 10:01:56 +03:00
Stas Boukarev db0339a5c4 Resolve a loop in an ash transform 2026-09-06 08:08:07 +03:00
Stas Boukarev fce3a00f0e x86-64, default-unknown-values: remove the last CMP 2026-09-06 08:08:07 +03:00
Stas Boukarev fc5e832ae5 x86-64, default-unknown-values: use cmov for one value 2026-09-06 08:08:07 +03:00
Stas Boukarev d6fb6072e5 x86-64: default-unknown-values ignore upper unused values completely
Since the stack doesn't need to be adjusted just pretend they don't
exist.
2026-09-06 08:08:07 +03:00
Douglas Katzman 7aadac2648 Revise some outdated comments 2026-09-06 04:48:43 +00:00
Stas Boukarev 790814f16e Transform (< (abs rational) c) before abs is transformed
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-09-05 23:40:09 +03:00
Stas Boukarev 783a2ab0e9 Transform (</> (integer-length x) constants) 2026-09-05 22:21:56 +03:00
Stas Boukarev d3ff35b362 (logcount (* x power-of-two)) => (logcount x)
It's not always transformed to ash.
2026-09-05 20:45:28 +03:00
Stas Boukarev 6925ac5a0c (integer-length (lognot x)) => (integer-length x) 2026-09-05 20:07:22 +03:00
Stas Boukarev 67570e5c28 Add some logcount identities
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
(logcount (logcount x)) => (logcount x)
(logcount (ash x positive)) => (logcount x)
2026-09-05 19:52:25 +03:00
Stas Boukarev 961c8c87dd Transform (= (logcount x) (integer-length x)) 2026-09-05 19:52:19 +03:00
Stas Boukarev 120d5eab81 Add transforms for (= (logcount word-sized) 1) 2026-09-05 18:45:30 +03:00
Stas Boukarev f8160932da integer-type-length: work on union types 2026-09-05 18:45:30 +03:00
Stas Boukarev 2865cf89d7 (logxor n (ash n -63)) is (unsigned-byte 63) for (signed-byte 64) n 2026-09-05 18:45:30 +03:00
Douglas Katzman 42549b22cc De-flake a test of sxhash hash quality
I asked Gemini to do the math on this, and it said that it's no surprise
a flake was seen with only 20 objects.  Changing to 60 objects reduces the
chance of spurious failure to 1 in 5e-16
2026-09-05 11:14:43 -04:00
Qiantan Hong 65f214fd09 add sb-simd-ssse3:u8.16-shuffle 2026-09-05 14:56:08 +03:00
Stas Boukarev 1fd7b4721e Catch destination-less casts in leaf-refs-not-escape-elsewhere-p
Fixes lp#2166183
2026-09-05 14:50:59 +03:00
Stas Boukarev 6e8c214ff1 Use word-sized-lvar-p more
Addresses an issue reported by Qiantan Hong.

Tests by Qiantan Hong.
2026-09-05 14:38:26 +03:00
Stas Boukarev 15c2369194 Resolve some stack pointer issues on nonstop-foreign-call on x86-64
Some checks are pending
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
scrub_thread_control_stack can't be called on the altstack.
sigtrap_handler might be updating th->control_stack_pointer which
might become stale.
2026-09-05 07:41:42 +03:00
Stas Boukarev c100979210 #+ an optional function 2026-09-05 04:11:32 +03:00
Stas Boukarev 37ddc92c87 Stop stack-analyze interfering with direct mv-calls
They don't push any values.
2026-09-05 04:05:56 +03:00
Stas Boukarev b193d1f288 Fix calls
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-09-05 03:11:17 +03:00
Stas Boukarev 9107d0306d Add --interpret to parallel-exec
[skip ci]
2026-09-04 22:09:31 +03:00
Stas Boukarev ea4332cd1f Disable pass-through-path-p for NLX
nlx-entry-pass-through currently makes the whole function return,
bypassing any other cleanups.
2026-09-04 20:07:50 +03:00
Douglas Katzman 07bb993d53 Disregard .lispwords when marking used labels
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Seems to have caused a problem for 32-bit x86
2026-09-04 16:27:45 +00:00
Stas Boukarev a1918d4e0a Include variant-vars when removing inherited ignores from define-vop 2026-09-04 18:41:52 +03:00
Stas Boukarev 82fdbae144 arm64: start implementing pass-through-call
Add only the VOPs in call.lisp
Unbreak the build where pass-through-call is disabled/unimplemented.
2026-09-04 17:46:30 +03:00
Douglas Katzman f2e1794438 x86-64: Pass-through multiple values across harmless cleanups
Some checks are pending
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Optimize non-tail full calls followed by "easy" cleanups that do not execute
arbitrary forms. "Easy" includes DX allocations, special var unbinding, popping
the CATCH block stack. Then the unknown values can be directly returned as if
by tail call, bypassing the RETURN-MULTIPLE helper routine.

We annotate return LVAR as :pass-through, suppress register restoration
after the call (:save-p :compute-only), and emit return as LEAVE+RET.
Cleanup VOPs (unbind-n, %catch-breakup) must preserve the carry flag, and use
only clobberable temporary registers.

For CATCH, decouple the normal return path from the NLX path. The normal path
eliminates use of the stack for buffering the mv-save area and then restoring
it from the stack.
2026-09-04 04:44:09 +00:00
Stas Boukarev f9db67bdfc Actually invoke mv-call-direct-named 2026-09-04 07:37:14 +03:00
Stas Boukarev 136b501c85 assem: avoid emitting instructions with a lot of arguments
Like lookup tables.
2026-09-04 07:23:40 +03:00
Douglas Katzman 6c4e7b5b72 Fix misplaced paren 2026-09-04 04:20:37 +00:00
Stas Boukarev a05ed363f0 Allow direct calls for (mv-call x (values 1 2) (funcall y)) 2026-09-04 06:58:24 +03:00
Stas Boukarev d0a6ee5bba Disable useless optimize notes from (truncate signed-word signed-word) 2026-09-04 06:29:32 +03:00
Douglas Katzman a894522bb2 Add a slot to SB-ASSEM::STMT
Separating the slot makes treatment of the prefix much more uniform, and the
compiler trace file for x86-64 becomes easier to understand. Previously the
trace didn't decode prefix bits in the IR2 dump of assembly instructions in
each vop, while the symbolic asm listing showing vops as comments did.

The peephole optimizer's instruction matcher is also a little simpler.
arm64 could use a similar idea for its vector length prefixes.
2026-09-04 01:45:00 +00:00
Stas Boukarev 213c270561 Better (m-v-call f (g)) on tls-based-mv-return
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Copy the values directly from the return stack. If there are no other
non-multiple arguments preceding the call then the registers stay in
the same place.
2026-09-04 00:55:16 +03:00
Gabor Melis 289db46c16 sb-manual: do not document unbuilt contribs
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Also, test texinfo generation on github.
2026-09-03 14:09:06 +02:00
Gabor Melis ccbf25c80d Improve DEFPACKAGE docstring
Add pointers to the documentation of non-standard options.
2026-09-03 11:16:52 +02:00
Stas Boukarev a7922782cf Fix make-target-contrib on Windows
Some checks are pending
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-09-03 02:14:22 +03:00
Stas Boukarev 61c92ca20a arm64/return: try to do STP/LDP 2026-09-03 02:14:21 +03:00
Douglas Katzman 9c4d4347c2 Avoid SETF of stmt-op and stmt-operands
Assembler backends typically treat these as immutable entities because
mutation tends to be a more bug-prone approach.
The current design still allows mutation, but we can mostly hide it.
2026-09-02 23:01:52 +00:00
Douglas Katzman 252a0b200c Rename STMT-MNEMONIC to STMT-OP
Easier to type, and matches standard assembler terminology
2026-09-02 19:24:28 +00:00
Douglas Katzman 386706b438 Update crossbuild makefile 2026-09-02 19:09:44 +00:00
Douglas Katzman 3dfe0b3e65 Fix sb-manual build when SBCL_CONTRIB_BLOCKLIST is nonempty 2026-09-02 16:07:22 +00:00
Stas Boukarev 087cb81385 arm64/return: avoid overwriting tmp-tn by load-store-offset
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Load store offsets are good for 4096 values, but it's better to ensure
an error is signaled.
2026-09-02 13:52:20 +03:00
Stas Boukarev 974e29da3b arm64/return: don't put descriptors into tmp-tn 2026-09-02 12:44:56 +03:00
Stas Boukarev 0b7c732828 arm64/return: store to (thread-mv-count) first 2026-09-02 10:48:00 +03:00
Stas Boukarev c8d0ca77a9 Use CMP instead of SUBS when possible 2026-09-02 10:41:59 +03:00
Douglas Katzman 4ab4654f68 arm64: implement tls-based-mv-return
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Authored by Antigravity
2026-09-01 22:06:41 +00:00
Douglas Katzman 78e706bf96 Generalize the number of MV return regs in gc-common
And treat the values as movable roots, not pinned roots
2026-09-01 21:37:55 +00:00
Stas Boukarev 1c95a90c3f arm64: fix passing empty alien structs 2026-09-02 00:30:03 +03:00
Stas Boukarev ce99730828 x86-64: fix passing packed structs by value
Reported by Andrew Wolven.
2026-09-02 00:24:05 +03:00
Stas Boukarev b746310040 Skip tests on #+interpreter 2026-09-01 18:01:23 +03:00
Douglas Katzman 9daea02bac win32: disable agressive stack scrub
Some checks are pending
Linux arm / build (push) Waiting to run
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
2026-09-01 09:59:48 -04:00
Stas Boukarev 303db288a5 Correctly not check ftypes of unused optionals
Fixes lp#2165974
2026-09-01 16:53:10 +03:00
Charles Zhang 9685c98e78 Auto-stack-allocate self and mutually-referential functions as well.
Teach environment analysis how to detect when functions which have
references in other functions (potentially itself) are automatically
stack allocatable. This is done by marrying the closure environment
analysis with some of the existing escape analysis utilities, and by
combining those analysis with a step to annotate the correct derived
dynamic extent lifetime, which further required some IR1 flow-graph
hacking utilities to revoke tail call semantics when
necessary. Additionally, the escape analysis performed for functions
is also now somewhat unified with how values are handled, so such
functions are now also stack allocated when all their references
deliver values to e.g. dx-safe functions. In fact, dx-safe as an
ir1-info annotation should probably just be removed in favor of
user-defined dx declarations.

We have thus deleted the arbitrary restriction on auto-dxification of
functions that made us just give up the moment a reference to a
potentially dxable function was in a different environment.

This fixes the existing expected test failures we had regarding being
able to auto stack allocate self-referential functions. We also add a
bunch of new tests to exercise stack-allocatability and correctness of
mutually referential functions which close over each other as well.

We can now remove some explicit dynamic extent declarations in the
system that are now automatically inferred by the compiler, since it
is safer that way in case the functions are changed. It may work to
remove more declarations but these are clearly the instances that the
compiler now handles.

Some test cases provided by Gemini. Everything else written by me.
2026-09-01 13:09:51 +02:00
Charles Zhang ee1e63f0fb Be even more conservative around cons and non-simple array types.
While it could be argued that

(lambda (x)
  (declare (optimize speed))
  (declare (type (array * (4 4)) x))
  (adjust-array x '(3 5))
  (array-dimension (the (array t) x) 0))

should be able to return 4 (I think this is rather dubious though),
clearly it is not correct for the attached test case to be able to do
so. Because declared types do not know anything about variable
subsitution, do not try and squeeze more type information from a
declared type if there is more than one reference to the variable.

While it is unfortunate that a test had to be disabled as a worse type
is derived, I don't see how to safely derive a better type without
making other cases incorrect. This could be fixed as a follow-up.

Notably

(lambda (x)
  (declare (type (or null (cons fixnum)) x))
  (setf (car x) 'foo)
  (if x
      (+ (car x) 4)
      0))

simply crashes without this fix and is not safe, which is not good
even if it's undefined behavior. The corresponding test case with a
variable substitution is not only unsafe but incorrect despite being
defined behavior.

Fixes lp#2165835.
2026-09-01 13:09:51 +02:00
Charles Zhang 2ca5d27079 Delete random macrolet. 2026-09-01 13:09:51 +02:00
Charles Zhang b69b11cc26 stack: Fix preservation of intervening stack lifetimes, again^n.
We were sometimes merging dynamic extent lifetimes in such a way that
the stack lvar of a dynamic extent later in the flowgraph was used
instead of the earliest one. Fix this by checking the state of the
stack and making sure that dynamic extents always end up taking on the
stack lvars of dynamic extents that happen before them in the
flowgraph when merging their lifetimes.

Fix found with assistance from Gemini Pro after much heavy hinting
from me. Extended commentary and test case reduction by me.

Fixes lp#2156347.
2026-09-01 13:01:00 +02:00
Charles Zhang 2f5e20b7af Endow DX semantics to SET values at IR1tran time.
Instead of waiting for environment analysis to scan set nodes for
dxable values, we can just create a dynamic extent per lambda and
associate it with the value of a SET during IR1
translation. Environment analysis can then run as normal and only
needs to worry about checking whether the environments of the value
and the dynamic extent are the same.

Doing so provides the following benefits (notably fixing a bug):

* We make handling of DX and sets more uniform, so that we no longer
need to handle a case where let conversion has happened or not. This
has the following benefits:
** Assignment lambdas don't confuse DX anymore. This fixes
lp#2163043.
** Flushed initial values don't cause pessimization anymore, fixing a
FIXME.

* It is now straightforward/more clear how to make the compiler
handle free dynamic-extent declarations.

* We can optimize or transform away SET nodes (think copy propagation
or SSA type optimizations) during IR1 optimization without worrying about additional DX
bookkeeping.

Also, revise some commentary about dynamic extent handling across
locall and envanal.
2026-09-01 13:00:58 +02:00
Stas Boukarev 8e964fd583 Add shortcuts for bignum * and /
Some checks are pending
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-09-01 07:08:06 +03:00
Stas Boukarev 695553ac46 Improve intexp around ratios and bignums
Avoiding unnecessary negations.
2026-09-01 07:08:06 +03:00
Douglas Katzman 310019ac0e Add a hack to make GC weak-hash-table tests reliable
The optimization of not scrubbing the part of the control stack that you
think you don't have to scrub is contrary to the requirement of some tests.
Real use would not often care. As mentioned in the prior commit, the
scrubbing logic was actually deficient going back nearly 15 years,
so the new logic is merely differently deficient but geared toward avoiding
touching all memory of all stacks of all threads on every GC.
2026-09-01 00:04:57 -04:00
Douglas Katzman c0ab42f560 Add a fallback path for arch_scrub_control_stack 2026-08-31 22:59:19 -04:00
Douglas Katzman ba8cedba53 Simplify and speed up arch_scrub_control_stack
It now uses a heuristic to decide where to stop clearing memory, which is
less technically accurate than before, but the key observation is that this
code was wrong for 15 years and therefore it's hard to say it takes less time
to do more work. i.e. because it never cleared enough, it stands to reason
that it might take more CPU time, though algorithmically it's better.
Hopefully this is also in practice better at reducing floating garbage.

Reviewed by Gemini
2026-08-31 21:53:35 -04:00
Stas Boukarev 774ad4de28 Speed up gmp-intexp
Faster dispatch to orig-intexp.
Faster (expt ratio -power)
2026-09-01 03:03:25 +03:00
Ilia Gradina c998d48297 sb-gmp: hand a non-rational base back to the original INTEXP
EXPT dispatches to INTEXP for a (COMPLEX RATIONAL) base as well as for
fixnums, bignums and ratios:

  (((foreach fixnum (or bignum ratio) (complex rational)) integer)
   (intexp base power))

GMP-INTEXP handles integers, ratios and 0/+-1, then sends everything else to
MPZ-POW, which only takes an integer. So merely loading the contrib - LOAD-GMP
calls INSTALL-GMP-FUNS itself, and again from an init hook - turns a working
EXPT into a type error:

  * (expt #c(1/5 1) 1)
  ; Evaluation aborted on #<TYPE-ERROR expected-type: INTEGER
  ;                                    datum: #C(1/5 1)>

Constant folding hides it from a toplevel REPL form, so it only shows up in
compiled code with a computed base. Maxima hits it through bernstein_poly,
where it fails one of the regression tests on any build linked against sb-gmp.

Send non-rational bases to ORIG-INTEXP, which handles them by repeated
squaring; GMP keeps the integer and ratio paths it was installed for.
2026-09-01 03:03:25 +03:00
Stas Boukarev 39303703db with-interrupt-bindings: mv-count is a fixnum
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
2026-09-01 00:53:12 +03:00
Stas Boukarev de01b60ddb Try more values in mv-return.impure
Some backends use 4 or 6 registers
2026-09-01 00:36:13 +03:00
Stas Boukarev 1dc3d56d15 Redo a test without using threads 2026-09-01 00:23:12 +03:00
Douglas Katzman 17d379157f Forgot a DX 2026-08-31 16:45:30 -04:00
Douglas Katzman 3a3d112d7e Fix interrupt-thread for #+tls-based-mv-return 2026-08-31 16:35:26 -04:00
Gabor Melis 9c2cbbd7d1 sb-manual: don't use version controlled symlinks
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
They are a hassle on Windows.
2026-08-31 10:20:39 +02:00
Stas Boukarev ce95b400c9 Resolve a GC issue with #+tls-based-mv-return
Write the high water mark before storing things on the return stack.
2026-08-31 10:34:45 +03:00
Stas Boukarev 66e972ebc0 #+tls-based-mv-return return: don't write RCX before it's needed
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-08-31 03:13:58 +03:00
Stas Boukarev 2a3976842d Better return value tn movement with #+tls-based-mv-return
E.g.
(values 1 2 3 4 5 7 8 9 10 11 12 13) doesn't move into stack locations
before moving into its passing place.
2026-08-31 03:02:22 +03:00
Stas Boukarev 565e932d70 Reduce DISPATCH-RATIO expansion size
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Don't check for fixnum ratio components if the integer it'll be added
to is a bignum.
2026-08-31 01:00:58 +03:00
Stas Boukarev 8b499bda00 More ratio arithmetic shortcuts
Like dividing by -1 adding 0, etc.
2026-08-31 00:45:27 +03:00
Douglas Katzman c5d1a5ce8e Enable a crossbuild test of :tls-based-mv-return 2026-08-30 16:57:03 -04:00
Douglas Katzman 4abf6ef5f7 x86-64: Implement "possible win" cited in calling-convention.texinfo
Create a dedicated area of 'struct thread' to return multiple-values in excess
of the arg-passing registers. Gating feature is :TLS-BASED-MV-RETURN and not
enabled by default. The limit of 64 (inclusive) values is the minimum to get
most existing tests to pass unchanged.  After the optimizations outlined below
are done, the feature will be more compelling, and we can see about making it
opt-out rather than opt-in, or making MULTIPLE-VALUES-LIMIT configurable.
(I'm sure that some user will claim to need 1000 values.)

The benefit will be fully realized in some subsequent changes, namely:
freeing a DX alloc, unbinding a special var, and breaking up a catch block
will all return from their frame without invoking RETURN-MULTIPLE. Similarly,
some "simple" unwind-protect forms such as release-mutex could too- anything
that does not clobber the thread-local area during a cleanup.
Also this alleviates a big impediment to creating an LLVM-based backend
which could explore performance differences among the call conventions
offered, since micro-management of the stack becomes less critical.

Co-authored with Antigravity
2026-08-30 15:51:25 -04:00
Stas Boukarev b36bdc5855 More compact fop-simd-pack 2026-08-30 21:19:41 +03:00
Douglas Katzman e5daa56dc3 build-all-cores 2026-08-30 12:28:02 -04:00
Stas Boukarev 71c43e5aa0 Don't define very large simd-pack functions for printing
Some checks are pending
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Just use sap-refs from memory.
Saves 1.1MB of core space.
2026-08-30 16:41:43 +03:00
Stas Boukarev e60afcbe4e arm64: use a flagged :conditional %digit-0-or-plusp VOP 2026-08-30 12:44:12 +03:00
Stas Boukarev ba19daa024 Don't define a no-op splat as a VOP
It creates non-transparent moves.
2026-08-30 12:38:11 +03:00
Stas Boukarev 01bd7882b1 More partial result modification false positives 2026-08-30 12:06:55 +03:00
Stas Boukarev 2e9abed30d arm64: more optimizable integer-length
arm64 has leading sign/zeros instructions, to get integer-length they
need to be subtracted from 63/64.
Doing it in VOPs is opaque, move to a lisp transform and two cls/clz VOPs.
That way (- 63 (integer-length x)) is just one instruction.
2026-08-30 09:57:09 +03:00
Stas Boukarev 94b6820242 expt: use (= (ftruncate n) n) to check for integers
It's no slower, and can be faster if #+round-float is available.
It's certainly simpler and more compact.
2026-08-30 08:59:42 +03:00
Stas Boukarev c33aaa910b arm64: better complex-float-=
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-08-30 08:06:30 +03:00
Stas Boukarev 5b897710fc arm64: use zip1 for creating complex floats 2026-08-30 08:06:30 +03:00
Douglas Katzman 69ad1e7908 De-obfuscate a loop
It avoided emitting a load of NIL more than once, but not relevant now.
2026-08-30 00:47:13 -04:00
Stas Boukarev 5a5ce63459 Disable a test
[skip ci]
2026-08-30 05:21:37 +03:00
Stas Boukarev 1899deda6a Distinguish between full and partial constant pass-through 2026-08-30 04:47:33 +03:00
Stas Boukarev 5bfa2103ec More thorough tracking of macro argument modifications 2026-08-30 04:17:15 +03:00
Stas Boukarev c338940576 More constant tracking for destructive modification detection 2026-08-30 04:00:50 +03:00
Stas Boukarev 8a66d3575b Resolve an improper use of functional-kind 2026-08-30 03:30:59 +03:00
Stas Boukarev e938a68479 (aref (vector a) 0) => a 2026-08-30 03:12:59 +03:00
Stas Boukarev d1b2b076bc Don't dx the list in (dx-let ((a (list a b))) (reverse a)) 2026-08-30 01:58:54 +03:00
Stas Boukarev 913710ac98 Don't specify :result-arg for REVERSE
It's a copy.
2026-08-30 01:49:37 +03:00
Stas Boukarev c1a075a94c Don't issue bt instead of cmp x, imm
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
It is more compact but has lower throughput.
2026-08-29 23:29:48 +03:00
Stas Boukarev 100afd03eb x86-64, arm64: use tst instead of cmp if it can use immediates
If it's for all high bits set.
2026-08-29 23:07:14 +03:00
Stas Boukarev 58abf34057 x86-64: use test x, x instead of bt more often 2026-08-29 19:58:17 +03:00
Douglas Katzman cd160079fc Remove comment rendered obsolete by rev 0f08e80e
which removed the byte field in favor of using %set-symbol-value-in-thread
2026-08-29 12:50:12 -04:00
Douglas Katzman 24a5114631 Remove a symbol-macrolet
A macro simply avoided some editing in the change to use null-tn.
2026-08-29 12:47:19 -04:00
Stas Boukarev 12202855b6 arm64: store to the untagged pointer after allocation
Not much of a difference, maybe fewer dependencies.
2026-08-29 19:19:51 +03:00
Stas Boukarev a6ebdf5177 arm64/simd-pack: use stp during allocation 2026-08-29 19:17:46 +03:00
Stas Boukarev f5b9025430 sub-access-debug-var-slot: use mask-signed-field 2026-08-29 19:17:46 +03:00
Douglas Katzman a4faf7a921 Facilitate making array of lispobj fields in struct thread
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Rather than having to maintain a C typedef that matches the :LENGTH
specified in objdef, automatically propagate that length.
2026-08-29 13:27:04 +00:00
Douglas Katzman 210ad59740 build-all-cores 2026-08-29 13:25:17 +00:00
Stas Boukarev 8d53b4ca6e - debugging code 2026-08-29 10:10:37 +03:00
Stas Boukarev c8639b1234 dump-1-packed-dfun: match what compute-args returns 2026-08-29 09:56:51 +03:00
Stas Boukarev 4eb17c020e debug-dump: store package-ids
Saves 288KB on a 35MB core.
2026-08-29 09:56:51 +03:00
Stas Boukarev a8d783b39a debug-dump: don't store var symbol packages twice 2026-08-29 09:56:33 +03:00
Stas Boukarev 99c5b76053 Remove fast-read-var-u-integer
Unused.
2026-08-29 06:14:44 +03:00
Stas Boukarev 4891fda939 Slightly more compact debug register encoding
Assign any-reg and descriptor-reg the same id.
Both any-reg and descriptor-reg are tagged and are accessed in the
same way.
Saves 95K on a 35MB core.
2026-08-29 06:14:44 +03:00
Douglas Katzman 9e3da6bd41 Output lisp-readable list of cold function addresses
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-08-29 01:45:13 +00:00
Douglas Katzman cc13ffc583 x86-64: Disallow :full-call as an asm routine return style
Asm routines are not functions, and this more closely matches the supporting
code for arm, arm64, riscv, loongarch.
2026-08-28 19:10:21 -04:00
Douglas Katzman ca8de03628 Remove clc instructions that do nothing
Assembly routines for generic +,-,* are not tail-callable so they
do not need to adhere to the Lisp function return convention.
2026-08-28 18:51:29 -04:00
Douglas Katzman 8b6a050b46 Remove R/M/W memory operation from alloc-alien-stack-space
Do one more instruction but one fewer memory load, because SUB with a
memory operand counts as both a load and store.
2026-08-28 18:43:35 -04:00
Douglas Katzman 33c68e006d Replace mem-reg XADD with load+add+store
llvm-mca confirms that 3 instructions is better than 2 in this case.
XADD is mainly used with :LOCK so if you don't need :LOCK, you don't need XADD
2026-08-28 18:30:31 -04:00
Stas Boukarev db35d45612 (reverse (list a b c)) => (list c b a)
Some checks are pending
CL-host / sbcl (push) Waiting to run
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-08-28 22:38:50 +03:00
Stas Boukarev a60b90261b Allow (setf (slot-value x 'read-only-struct-slot)) at compile-time
Don't transform it to (setf struct-read-only-struct-slot).
It works when x or read-only-struct-slot are not known at compile
time, no reason to stop it.
2026-08-28 22:38:50 +03:00
Sylvia Harrington e4e628ab84 sb-simd: Fix a bunch of bugs
64-bit integer min/max don't have actual instructions, fake instead
Fix signed lane extraction not sign-extending
Add float abs/neg
Fix fsqrt encoding
Fix u32.4-from-u64.2/s32.4-from-s64.2 family, wrong size
Remove 64-bit integer vector mul, instruction doesn't exist
Add missing exports for integer min/max
Align spilled neon registers properly
Validate more vector instruction forms properly
Fix movi immediates
2026-08-28 22:38:41 +03:00
Christophe Rhodes 62f4bd1032 2.6.8: will be tagged as "sbcl-2.6.8" 2026-08-28 17:31:36 +01:00
Douglas Katzman 5a569e62ec Fix a C style warning
simd_pack_512_mask_slots is unused
2026-08-27 18:32:32 +00:00
Charles Zhang eb3d6740f5 Adjust NEWS
To be slightly more accurate.
2026-08-27 13:18:55 +02:00
Stas Boukarev ecf9f81f92 Adjust NEWS
That was done in the previous release.
2026-08-27 00:31:19 +03:00
Christophe Rhodes fa26f84013 Draft NEWS for sbcl-2.6.8 2026-08-26 22:22:46 +01:00
Douglas Katzman add94c4538 build-all-cores 2026-08-26 16:03:02 -04:00
Stas Boukarev 6b0c5fe453 Remove dstate-disp-n 2026-08-26 17:00:31 +03:00
Stas Boukarev 3d97f782f8 Protect a test with #+ 2026-08-26 08:48:52 +03:00
Stas Boukarev f19ea95f66 Add a test for foldable functions without a runtime function 2026-08-26 08:33:59 +03:00
Stas Boukarev d1fabf915b Fix emit-avx512-inst-imm
With correct evex detection
2026-08-26 05:06:52 +03:00
Stas Boukarev ad1b771806 Disassemble more avx512 instructions 2026-08-26 04:48:06 +03:00
Stas Boukarev fa59dfa2e7 Reset dstate-disp-n to 0 2026-08-26 04:17:38 +03:00
Stas Boukarev 885a2ddd61 Fix disassembler 2026-08-26 03:13:03 +03:00
Stas Boukarev 5119064945 Fix avx512 instruction encoding for ymm16-31
Emit EVEX prefixes for AVX2 instructions.
2026-08-26 02:45:02 +03:00
Stas Boukarev 9788b061b3 Remove debug output 2026-08-26 02:09:26 +03:00
Stas Boukarev 5c3fe7ae65 Don't save avx512 registers in alloc tramps
Declare the allocation routines with :save-p :avx512, to save only the
live registers around the call (which shouldn't happen in optimized
code).
2026-08-26 02:04:12 +03:00
Stas Boukarev 50e4701839 Save avx-512 registers around foreign calls
Without wiring any temporaries
2026-08-26 02:03:43 +03:00
Stas Boukarev 188ae65ab5 Fix avx-512 register allocation
Don't assign zmm0-15 first and run out of registers for xmm/ymm.
Assign zmm31-0 instead.
2026-08-26 01:55:19 +03:00
Stas Boukarev 19040616e7 Fix %make-simd-pack-512-single
Don't overwrite the inputs before they are used.
2026-08-26 01:15:57 +03:00
Stas Boukarev d876820656 arm64: fix %make-simd-pack-double/single
Don't overwrite the inputs before they are used.
2026-08-26 00:51:13 +03:00
Stas Boukarev 856ed453f3 Stop touching avx512 registers in c-call
Which forces avx512 instructions to be used.
This breaks avx512 spilling around foreign calls.

Fixes lp#2164994
2026-08-25 17:23:53 +03:00
Stas Boukarev d21baee184 Add an assertion 2026-08-25 04:09:03 +03:00
Stas Boukarev 6fcc8d928b Correctly signal encoding errors from string-to-octets
Fixes lp#2164924
2026-08-24 20:42:27 +03:00
Stas Boukarev ff86fee2c0 avx2/utf8-strlen: fix the 1/2 byte fast path
Which omits overlongs coming from the full path.
2026-08-24 03:52:04 +03:00
Stas Boukarev c104c75a3c Remove defknowns for removed functions 2026-08-24 03:52:04 +03:00
Stas Boukarev 6a371bf547 Add a folder stub for reverse-values-list
Reported by Andrew Wolven
2026-08-24 02:07:29 +03:00
Stas Boukarev 0d87331ec9 Improve utf-8 tests 2026-08-24 01:31:50 +03:00
Douglas Katzman 0f6128e4a6 Augment genesis/number-types.h, don't make more headers 2026-08-22 13:53:16 -04:00
Douglas Katzman 0383982d88 x86-64: Permute Lisp arg-passing registers
Lisp and C are new identical for #+unix though not #+win32

Co-authored by Gemini
2026-08-22 13:02:13 -04:00
Stas Boukarev bd76fc4481 arm64/character-string-to-utf8: jump to ascii-loop from a better place 2026-08-22 17:31:35 +03:00
Douglas Katzman 0eb8b556ac Apply various micro-optimizations to VECTOR-FILL/T
* use a loopless final pass after the unrolled pass
* use one fewer temp register
* remove a couple of instructions here and there

Also some stylistic changes:
* give better names to registers depending on their usage
* avoid an #ifdef for SB_SAFEPOINT in x86-64-arch

Co-authored with Gemini
2026-08-22 02:00:51 +00:00
Stas Boukarev e4a5665070 arm64/character-string-to-utf8: escape back to ascii-loop 2026-08-22 04:35:51 +03:00
Stas Boukarev bded621c00 arm64/character-string-to-utf8: add a fast-path for 1-2 bytes 2026-08-22 03:21:22 +03:00
Stas Boukarev ca69a527f0 Move an instruction. 2026-08-22 01:37:57 +03:00
Douglas Katzman b5c1bfad94 Make EMIT-EA more complicated
because it wasn't bad^H^H^Hflexible enough
2026-08-21 22:35:29 +00:00
Douglas Katzman 18f8a0c8ea build-all-cores 2026-08-21 22:19:29 +00:00
Stas Boukarev 023755eb0c Incomplete previous diff 2026-08-21 22:22:11 +03:00
Stas Boukarev 2cce59959a x86-64-simd: use helper functions throughout 2026-08-21 21:38:10 +03:00
Stas Boukarev 29b5b1674d Remove non-ascii characters from sources
[skip ci]
2026-08-21 19:18:41 +03:00
arthur f7fe8b09df add infrastructure for EVEX compressed displacement
* Add dstate-disp-n to disassem-state
* Add reg/mem arg types for tuple sizes 1,2,4,8,16,32,64.
* Extend avx512-inst-printer-list to accept :disp-n.
* Scale EVEX disp8 by the instruction-specific tuple size in decode-mod-r/m
* Annotate full-vector EVEX moves and emit compressed displacement for them.
* Add disassembler tests for the functionality in this patch

This covers the full-vector move subset. For other EVEX memory
instructions more work is needed.
2026-08-21 18:48:06 +03:00
arthur e2ff58b302 EVEX: add V' and improve 5-bit register decoding
* Add +evex+ indicator to distinguish EVEX from VEX/legacy
  even for EVEX L'L=00 forms
* Decode ModRM.reg registers 16–31 using R'
* Stop incorrectly applying R' to ModRM.r/m operands
* Decode EVEX ModRM.r/m register-direct 16–31 using X as B'
* Decode EVEX vvvv registers 16–31 using V'
2026-08-21 18:17:34 +03:00
Stas Boukarev 82ffc78960 avx2/utf8-to-character-string: add a 1/2-byte fast path 2026-08-21 02:15:56 +03:00
arthur fde3ddff06 x86-64: rename xmm-tn-p to float-tn-p 2026-08-20 20:42:26 +03:00
Stas Boukarev 6d159d1fd9 (- a (- a b)) => b
And friends.
2026-08-20 15:51:10 +03:00
Stas Boukarev 2e8fa20cbd decode-universal-time: don't do mod and truncate separately
And some other arithmetic rearrangements.
2026-08-20 14:02:17 +03:00
Stas Boukarev 23dedf9150 Copying error 2026-08-20 12:07:57 +03:00
Stas Boukarev fc1d28224a Remove mappings from float-regs to offsets
They are just sequential integers.
2026-08-20 12:01:55 +03:00
arthur c3bb5b8700 Basic support for AVX512 mask registers
* add simd-pack-512-mask as intrinsic type (widetag)
* add associated book-keeping in VM, compiler and interpreter for simd-pack-512-mask
* add VM support for mask registers (mask-reg SC, SB, defregs, ...)
* add VOPs to compiler backend for construction, extraction
* add VOPs for movement: kregs<->kregs, kregs<->gpr and kregs<->mem
* add support for assembler in insts, avx2-insts and avx512-insts
* rewrite most of evex emitter regarding mask registers
* add print support in evex for mask related instructions
* fix some smaller bugs in previous simd-pack-512 support patch
* add tests for creation, extraction, movements, assembly printing and some internal functions
* refactor zmm-registers-used-p into avx512-state-used-p and update call sites
* add support for mask regs to avx512-state-used-p
2026-08-20 10:55:19 +03:00
Stas Boukarev 49beef5fe4 clos.impure passes on sb-eval too 2026-08-20 10:55:19 +03:00
Douglas Katzman f797952a84 Preemptively adjust a test
If RDX ceases to be the first arg-passing register, then this test will fail
because there is no byte-sized register corresponding to byte index 1 of RDI.
2026-08-20 03:52:53 +00:00
Douglas Katzman 5ca456d7fe x86[-64]: Invent syntactic convenience in define-assembly-routine
I want to permute the 3 lisp arg-passing registers to match the machine ABI
and this change makes it less ugly to do so. (Some DEFINE-ALIEN-ROUTINEs
in user code and SBCL itself could potentially emit fewer moves by matching
the ABI but we also will want to tackle a problem of needless spill/restore
of register args by eliminating dead stores)

Other backends don't strictly benefit from this syntax because register
names such as A0,A1 already express exactly what they mean to, whereas x86
register names are alphabet soup in comparison.
2026-08-19 17:01:32 -04:00
Douglas Katzman f5e063c351 Remove #+#. from x86-64 files
We can safely assume n-fixnum-tag-bits = 1. Revision a369686d which gave 1 more
bit of precision theorized that a build-time choice could be made within a
particular backend. While that was true for a while after the commit, x86-64
is now so ingrained with the belief that fixnums are 63 bits that it can't
reasonably be changed. While we should prefer the symbolic constant in lieu
of a literal 1, that style does not imply that littering up the source with
illegible "#+#.(cl:if)" around vops that can't be enabled is sound practice.
2026-08-19 14:15:56 -04:00
Douglas Katzman a3dbf9924e Prefer not to use #+#. in tests 2026-08-19 13:25:20 -04:00
Douglas Katzman f4dc30318b Enable most of clos.impure for --evaluator-mode interpret
Was disabled by rev 278038f2bb but seems to pass nearly all tests
under sb-fasteval. No idea what the situation is with sb-eval.
2026-08-19 13:20:31 -04:00
Stas Boukarev 945dba8de3 read-line: faster return if #\Newline is in the buffer 2026-08-19 08:01:34 +03:00
Stas Boukarev 0b019f26d4 arm64/utf8-to-string: return to the fast path from the full loop
The check is performed for free by utilizing the integer pipeline
using SWAR.
2026-08-19 05:02:42 +03:00
Stas Boukarev b3a61535ef Rearrange branches 2026-08-19 02:04:40 +03:00
Stas Boukarev adb9b23144 arm64/utf8-sap-to-character-string: add a 1/2-byte fast path 2026-08-19 01:54:38 +03:00
Stas Boukarev 4b2be60c8b Don't stop compilation on bad type declarations 2026-08-18 07:41:05 +03:00
Stas Boukarev 09e5b5d14e Never transform ELT to NTH
The initial problem is that elt derives types on constant lists
without adding a NIL, which can be returned by NTH.
Always check bounds instead.
There's no performance advantage in not signaling an error.
2026-08-18 06:44:02 +03:00
Douglas Katzman 8a26a86d76 Assign layout-ids just-in-time as originally intended
This wasn't working right, and the assertion in LAYOUT-ID about assigning
only structures an ID was written incorrectly.

* Layout IDs are assigned only when applying a :layout-id fixup or when storing
  into a descendant type's ID array, whichever occurs first.
* IDs of non-structure instances like STREAM that have nonzero IDs are
  stored at the correct place for their depthoid, and not always at index 0
  so that LAYOUT-ID doesn't have to test +structure-layout-flag+.
* LAYOUT-ID returns NIL instead of 0 if no ID is assigned.
  machine-dependent files will never see the 0.
* The remark that IDs could do type-based dispatch is no longer hypothetical
2026-08-17 19:15:29 -04:00
Stas Boukarev 06151ad1c1 Fix ldb transforms
erase-node-type has to be called with value-types.

Reported by Eric Marsden.
2026-08-17 18:23:13 +03:00
Stas Boukarev 0a1f43ff5d Replace two instructions with one 2026-08-17 07:19:16 +03:00
Stas Boukarev 7f3f7b8ef3 Use a smaller instruction 2026-08-17 06:21:00 +03:00
Douglas Katzman 4f0efb07bc Fix typo 2026-08-17 02:55:35 +00:00
Douglas Katzman b3b9f0efa2 Factor out boilerplate from structure-is-a 2026-08-16 22:19:14 -04:00
Stas Boukarev 65b968f2ac avx2/character-string-to-utf8: optimize newline tracking
And ASCII detection.
Let it work on the bytes packed with saturation.
Use branches.
2026-08-17 04:02:49 +03:00
Douglas Katzman 37d8c020ee Remove some nops for ancient MIPS I support
Due to getting load delays wrong, we have never correctly run on MIPS I afaict
so don't even try. MIPS II has branch delays and also there are some
coprocessor hazards that still need delays, therefore keep those intact.
2026-08-16 20:46:07 -04:00
Douglas Katzman c652d1fb01 Delete 6-year-old TODO
It's better to handle relocation of all spaces like x86-64 does
2026-08-16 15:46:05 -04:00
Stas Boukarev 5f08e87681 Prevent var substitution with lvar-type-annotations
Which might cause type conflicts in new refs.
This might make some things opaque, but type-annotations are used only
in very specific cases, and preserving control flow with casts or
combinations will be just as opaque.
2026-08-16 17:29:38 +03:00
Stas Boukarev e1e0e2df5c avx2/character-string-to-utf8: simplify calculations
Reuse the lower bits of imul to sum utf8 lengths.
2026-08-16 02:36:12 +03:00
Stas Boukarev 4f0383a528 avx2/character-string-to-utf8: don't use a lookup table for sizes
Use a sequence of gpr instructions.
2026-08-15 22:34:25 +03:00
Gabor Melis a797aedf9d fix ffi documentation at the source
The generated texinfo files (e.g. ffi.texinfo) are under version
control only to be able to conveniently track the Markdown-to-Texinfo
output until it's deemed stable enough.
2026-08-15 17:50:15 +02:00
Stas Boukarev f832c8e48e ffi.texinfo: struct by value is supported on Windows
[skip ci]
2026-08-15 17:47:32 +03:00
Stas Boukarev c65240ba13 arm64/character-string-to-utf8: reduce GPR calculations 2026-08-15 08:40:13 +03:00
Stas Boukarev 6efe9cda26 avx2/character-string-to-utf8: reduce a LUT by 4KB
A tag mask can be computed in one instruction from character lengths.
2026-08-15 07:35:52 +03:00
Stas Boukarev 977441e827 arm64/character-string-to-utf8: reduce a LUT by 4KB
A mask that clears the high bits can be generated from the tag bits
with a single right shift.
2026-08-15 06:28:17 +03:00
Stas Boukarev 4c9ebabb78 arm64/character-string-to-utf8: don't use a lookup table for sizes
Use a sequence of gpr instructions. Sits somewhere in the middle
between a lookup table and vector instructions, but doesn't depend on
the L1 cache.
2026-08-15 06:28:15 +03:00
Stas Boukarev 3c314be353 Stop reusing potentially optimized inlined functions
Fixes lp#2163502
2026-08-15 02:02:23 +03:00
Stas Boukarev facbb275e3 arm64: fix fast-logand-c/unsigned=>unsigned
Inherit from the right VOP
2026-08-15 02:02:23 +03:00
Douglas Katzman 524d98588a Use zeroize 2026-08-14 14:46:52 -04:00
Stas Boukarev 27f73d43b2 arm64/character-string-to-utf8: use a lookup table for sizes 2026-08-14 16:57:16 +03:00
Stas Boukarev 55d3b2696e character-string-to-utf8-avx2: shrink the lookup table
The bit clearing masks can be computed cheaply at runtime.
2026-08-14 06:03:53 +03:00
Charles Zhang 6c0c0fdc2c constraint: Inherit EQL var constraints from local calls as well.
(defun f ()
  (declare (optimize speed))
  (labels ((phi (index)
             (declare (type (integer 0) index))
             (if (> index 9)
                 nil
                 (rec 0 index)))
           (rec (zoot gindex)
             (declare (fixnum zoot))
             (if (< zoot 5)
                 (rec (1+ zoot) gindex)
                 (phi (1+ gindex)))))
    (phi 0)))

now no longer produces any notes.

However, we don't have optimistic type propagation in CP itself, so
neither the lower bound nor the integerness of GINDEX or INDEX can be
derived.
2026-08-14 03:19:09 +02:00
Charles Zhang 87608fcd95 Delete unused function. 2026-08-14 03:18:21 +02:00
Douglas Katzman 1faf50d3dc Improve codegen for chain of structure-TYPEP tests
When performing successive tests, if all types have the same depthoid, then
rather than emit an instruction to load instance-layout, and then a series
of instructions to compare the layout-id against various numbers (each
entailing a memory load), instead load the layout-id once up front and
compare that against the various IDs under consideration for equality.

If the depthoids are not all the same, fall back to the slightly suboptimal
code that loads a layout-id every time. (Better would be to try to group
comparisons into sequences of tests that can all use the same loaded ID.)

Test cases by Gemini
2026-08-13 20:13:27 -04:00
Stas Boukarev 0ed5ec0d57 Add some (safety 0)
And some other micro-optimizations.
2026-08-14 02:59:36 +03:00
Douglas Katzman 9c6a402b32 Decrease some repetition 2026-08-13 15:07:45 -04:00
Stas Boukarev 4d580f8f27 utf8-simd: reduce tagging/untagging for arguments/results 2026-08-13 19:39:52 +03:00
Stas Boukarev fee731c7dd character-string-to-utf8-avx2: reduce memory loads 2026-08-13 19:39:46 +03:00
Douglas Katzman 9b59c02a58 Recognize the pattern (if (member x `(,this ,that)) ...)
which is a useful notation for CASE clauses where the symbols to match
are not literals. So you can use a COND without writing an OR over EQL.
2026-08-13 16:19:06 +00:00
arthur 5d1babc0ec Fix bug in selecting kregister in avx512-insts.lisp 2026-08-13 14:38:15 +03:00
Stas Boukarev cefd608dd9 Remove an extra vzeroupper 2026-08-13 06:18:11 +03:00
Stas Boukarev 72da092e11 Appease cmucl 2026-08-13 06:17:27 +03:00
Douglas Katzman ed0f3c56c1 Remove some special vars from DEFCLASS parser 2026-08-12 22:46:06 -04:00
Douglas Katzman d1d85bbaa1 build-all-cores 2026-08-12 22:45:49 -04:00
Stas Boukarev cc40e148a2 x86-64-simd: improve crlf detection 2026-08-13 04:47:32 +03:00
Stas Boukarev 0290cfc968 x86-64: encode lddqu 2026-08-13 02:43:03 +03:00
Stas Boukarev 63e9079dcf character-string-to-utf8-avx2: free up a register 2026-08-13 02:43:03 +03:00
Douglas Katzman f9075a0c2a Ensure that hash-table-index-vector stays with the table
This accidental omission of ALLOCATING-FOR-HASH-TABLE had catastrophic
consequences if any system table was involved. I discovered the problem
in particular on SB-DI::*COMPILED-DEBUG-FUNS* which meant that you were
crashing while crashing, because you couldn't extract cached debug funs.

Test case by Gemini
2026-08-12 18:40:01 -04:00
Douglas Katzman f7d9205bfd Remove effectless case
This looks like a typo from rev 671e23e5 but surprisingly was syntactically ok,
hence no compiler complaint. EQ was parsed as the head of a clause.
2026-08-12 19:31:37 +00:00
Stas Boukarev bc1ea6852e More optimizations in utf8-to-character-string-avx2 2026-08-12 20:27:29 +03:00
Stas Boukarev 839c07f462 utf8-to-character-string-avx2: free up a register using vpmaddubsw 2026-08-12 18:16:24 +03:00
Stas Boukarev 83f7a3d006 utf8-to-character-string-avx2: smaller 8-to-32 widening 2026-08-12 18:01:55 +03:00
Stas Boukarev 82385e1c56 #+sb-unicode 2026-08-12 06:38:46 +03:00
Stas Boukarev f519f0f1e3 arm64-simd: streamline start/end calculations 2026-08-12 06:26:17 +03:00
Stas Boukarev 410e879997 x86-64: full unicode decoding in utf8-to-character-string-avx2 2026-08-12 06:24:47 +03:00
Stas Boukarev a2b2354920 x86-64: full unicode encoding in simd character-string-to-utf8 2026-08-12 02:29:16 +03:00
arthur f59a852d8b Remove duplicate primtype definition for simd-pack-512 2026-08-12 00:09:27 +03:00
arthur ad0ea010b2 fix movdqu64 in move for avx512 + test warning 2026-08-12 00:07:48 +03:00
Stas Boukarev 3cc8aa4c51 Copy the changes from utf8-strlen to utf8-to-character-string 2026-08-11 23:40:44 +03:00
Stas Boukarev ade839f1e4 arm64/utf8-strlen: remove redundant instructions 2026-08-11 21:45:04 +03:00
Stas Boukarev 28d0737865 ppc-vm: context-float-register is implemented on freebsd 2026-08-11 21:05:19 +03:00
Stas Boukarev 17e1f2a4cc arm64/character-string-to-utf8: do not exit early on surrogates
Proceed encoding and return later as if nothing was encoded if
surrogates were encountered.
2026-08-11 20:36:02 +03:00
Stas Boukarev 30e1a2af34 Add a way to jump to lisp code tags from inline-vop 2026-08-11 20:27:37 +03:00
Stas Boukarev 06df2ad72b Fix specialized XEPs with ignored parameters, again
Reported by Sylvia Harrington.
2026-08-11 17:53:31 +03:00
Stas Boukarev e96684a5e7 arm64/character-string-to-utf8: slightly faster surrogate check
By moving one instruction from simd to scalar.
2026-08-11 09:55:16 +03:00
Stas Boukarev 22288ec186 character-string-utf8-length: speed up surrogates tests
Delay the range check to the end by collecting unsigned minimal values
of char-#xd800
2026-08-11 08:56:11 +03:00
Stas Boukarev 915df979d5 arm64: encode simd scalar add, sub, and vector/scalar neg 2026-08-11 07:36:06 +03:00
Charles Zhang 51e87c2de7 Make some prose less bad.
For some reason gen. ai is still awful at writing comprehensible
prose, so re-do the comments manually. (I actually published the last
set of commits prematurely before getting a chance to fix the writing
and other details, though the code was checked already).
2026-08-11 01:38:53 +02:00
Charles Zhang 6125836b9d Restore test case.
Which got fat-fingered and swallowed up in the last diff.
2026-08-11 01:15:06 +02:00
Charles Zhang b72c50c389 Constrain local call parameters from their arguments.
A loop written as a local call inferred worse types at its references
than the same loop written with an assignment, and everything that
produced the difference was on the local call side.

Constraint propagation knew nothing about a local function's
parameters. For a LET it adds a TYPEP constraint from the argument the
variable is bound to, but for any other local function it had only
LEAF-DEFINED-TYPE to go on, so the parameters reached the body with
nothing said about them. An imperative loop's variable, meanwhile, is
refined a step per round by exactly this machinery: COMPUTE-BLOCK-IN
joins what each predecessor knows, which around a loop peels one value
of the sequence per iteration until
*DERIVED-NUMERIC-UNION-COMPLEXITY-LIMIT* collapses the rest.

So constrain the parameters at the call. Binding one is an assignment
to it and carries the same two obligations a CSET does: the callee
learns the argument's type, and what was known of the parameter stops
holding -- which matters when the call is recursive, since the
parameter is then one the calling block has constraints about.
COMPUTE-BLOCK-IN already joins these across the call sites.

That alone changes nothing, because PROPAGATE-LOCAL-CALL-ARGS was
narrowing the same variables from a union recomputed out of arguments
derived from the variables themselves. Around a loop that sharpens on
every visit and never settles, and being the narrower of the two it
won. Leave a parameter that is being solved for optimistically to
PUBLISH-OPTIMISTIC-TYPES, the way a variable with sets is left to
PROPAGATE-FROM-SETS. The optimistic side reaches the same answer
convergently and constraint propagation sharpens the references from
there.

With the optimistic side now the only thing narrowing these
parameters, the rate at which it publishes is the rate at which they
sharpen, and IR1-OPTIMIZE-UNTIL-DONE was charging each publication to
*MAX-OPTIMIZE-ITERATIONS*. A pass that found nothing itself and only
published no longer counts against that budget: types only narrow, so
there are finitely many such passes, and the budget still bounds the
passes that do work. Without this, DELETED-CALL-TYPE and
LOCAL-CALLS-TO-&REST run out of rounds with types still stale.

All nine step shapes in (:LOCAL-CALL-ARG-TYPE :SPELLING-PARITY) now
derive identically to their imperative spelling. (ASH X 1), which had
no fixpoint before and drifted with *MAX-OPTIMIZE-ITERATIONS*, settles
on the answer DO reaches and stays there at 3, 6 and 12 iterations.

Implementation and test cases written by Claude Opus 5.
2026-08-11 01:12:38 +02:00
Charles Zhang 235a657397 Infer local call argument types from how the arguments step.
A loop variable carried through a local call still got a worse type
than the same loop written imperatively, in two ways.

An argument that steps the parameter through a known function of
itself contributed whatever IR1 derived for it, and IR1 derived that
from the function's ftype applied to a parameter that was still T:

  (do ((x (list 1 2 3) (nreverse x))) (...))              => CONS

  (labels ((rec (i x) (... (rec (1- i) (nreverse x)))))
    (rec n (list 1 2 3)))                                 => SEQUENCE

And a numeric parameter stepped by an increment got no bounds at all,
where an assigned one gets them from the direction of the step:

  (do ((n 0 (1+ n))) (...))                               => UNSIGNED-BYTE

  (labels ((rec (i n) (... (rec (1- i) (1+ n)))))
    (rec k 0))                                            => NUMBER

PROPAGATE-FROM-SETS has both answers already, in
SET-TYPE-OF-COMBINATION and MAYBE-INFER-ITERATION-VAR-TYPE, and
neither was reachable from the local call side.

So recognize an argument that carries a parameter forward from its own
previous value -- a step -- and keep it apart from the arguments that
deliver an unrelated value. What the steps say about the parameter is
then decided by the same means and in the same order as for a variable
with assignments: a loop counter's bounds if the steps are increments,
otherwise a fixpoint derived through the stepping function if there is
a single one, otherwise the plain union as before. A SETQ and an
argument in the parameter's own position are the same thing written two
ways, so the machinery is shared rather than mirrored:
%ANALYZE-SET-USES, SETS-NUMERIC-CONTAGION and
MAYBE-INFER-ITERATION-VAR-TYPE now take the lvars the stepped values
arrive on instead of a list of CSETs, the ({+,-} VAR STEP) test both of
the first two opened with becomes ITERATION-STEP-VALUE, and
CONVERGED-TYPE-OF-COMBINATION is the fixpoint half of
SET-TYPE-OF-COMBINATION.

A step is the only kind of contribution where an optimistic type
reaches a derivation, which is where iterating a union upward would
need widening, since (REC (1- I) (CONS 1 X)) grows X by a level every
round. Neither route iterates: the counter case reads the direction of
the step and keeps only the bound the variable moves away from, and the
fixpoint case derives twice and accepts its answer only if the second
derivation agrees with the first.

This closes the FIXME on the counter case in (:LOCAL-CALL-ARG-TYPE
:CYCLE), which now derives UNSIGNED-BYTE as the imperative loop does.

A step by more than one is still not at parity and is left as a failing
test. Each round of optimization re-derives the step from the
variable's current type and unions one more value in, and the two
spellings get a different number of rounds before they settle: for
(+ X 2) from 1, DO peels 1,3,5,7,9,11 and then takes [13,inf) while the
local call peels 1,3 and then takes [5,inf). Nothing different is
inferred about the loop -- at the variable itself the local call is the
narrower of the two -- and it is only at a reference, where constraint
propagation has had those extra rounds to work with, that DO comes out
ahead.

Implementation and test cases written by Claude Opus 5.
2026-08-11 01:12:38 +02:00
Charles Zhang 30741cecef Have CTU:COMPILER-DERIVED-TYPE return the final dervied type.
By making it an IR2 converter, we get the final type, not some
intermediate type.
2026-08-11 01:12:38 +02:00
Stas Boukarev 13b5e0a8ed x86-64/character-string-utf8-length: support very large strings
Over 4GB of emojis.
2026-08-11 01:52:32 +03:00
Stas Boukarev 6a80d5e791 x86-64/character-string-utf8-length: don't repeat the same instruction 2026-08-11 00:18:49 +03:00
Stas Boukarev 992ff1465e Speed up arm64/character-string-utf8-length
Use clz + tbl instead of multiple range checks.
2026-08-11 00:07:32 +03:00
Douglas Katzman 2df1a2bb30 Silence some output of make-target-2 if --noinform was given 2026-08-10 17:02:08 +00:00
Charles Zhang 4189ab7f19 assignment-convert: Handle tail calls and cleanups better (again).
Instead of trying to compare cleanups modulo harmlessness directly as
in the code disabled in 6cbab77cdb,
check for harmlessness of the cleanup nesting from the call node to
the lambda block directly. This allows us to re-enable the Fluet &
Weeks tests.

We also catch another case of assignment conversion where mutually
tail recursive functions are entered by tail calls from different
functions.
2026-08-10 18:22:01 +02:00
Stas Boukarev b561a0680f arm64 utf8-strlen: test for null and non-ascii at the same time 2026-08-10 07:06:34 +03:00
Stas Boukarev c68fdd2af1 arm64-simd: use a helper function more 2026-08-10 05:16:41 +03:00
Stas Boukarev adcd474725 Don't produce a compile time warning for (setf (char string 0) #\é) 2026-08-09 01:20:46 +03:00
Stas Boukarev 93c205db17 Add a test for character-string-to-utf8 2026-08-09 00:57:39 +03:00
Stas Boukarev e7ec4bec99 arm64, character-string-to-utf8: delay newline tracking
To the end of the loop.
2026-08-08 20:57:43 +03:00
Stas Boukarev 1e9312c5ab arm64: add sqshrn instructions 2026-08-08 09:00:18 +03:00
Stas Boukarev 60b3a47cbf arm64, character-string-to-utf8: faster newline tracking 2026-08-08 07:53:19 +03:00
Douglas Katzman 2e5049cd81 Silence one more compiler-note from bignum
I tried a dozen different ways to get it to stop issuing a coercion note
from BIGNUM-ASHIFT-RIGHT and the only one that worked was a toplevel
proclaim, which strangely did not silence a note from unary-truncate.
2026-08-07 22:25:17 -04:00
Stas Boukarev 2d46affdc0 arm64: full unicode encoding in character-string-to-utf8 2026-08-08 03:41:48 +03:00
Stas Boukarev eb111dddf1 Remove debugging and unused code 2026-08-08 01:54:14 +03:00
Charles Zhang 6cbab77cdb assignment-convert: Don't try to be so smart with cleanups.
Trying to assignment convert more lambdas whose calls have different
cleanups but not modulo harmfulness only *almost* works. While
conceptually it's fine, it causes problems during cleanup
emission. When we merge lambdas, we anchor to a specific
lexenv/cleanup, not to the messiest common ancestor. Since cleaup
emission itself has no notion of skipping harmless cleanups, it tries
to emit cleanups when it shouldn't, breaking things. I think the
actual correct as in optimal way to do it is to make cleanup emission
also ignore harmless cleanups as well, but that gets a bit hairy with
the existing cleanup sharing code in EMIT-CLEANUPS. So give up and go
back to the slightly dumber cleanup checking code.

No LLM/AI was used to diagnose this issue, so the responsibility for
this rambling is mine.

Unfortunately, a few of the assignment conversion tests (but not all of
the new ones) have to be turned off because the block tag introduced
by labels gets in the way of the optimization. Even for these tests we
still contify more than before though.

Fixes #lp2162990.
2026-08-07 23:05:56 +02:00
Stas Boukarev 4727a49892 read-byte transform: refill the buffer instead of just calling n-bin
Which does not touch the buffer.
2026-08-07 22:42:41 +03:00
Charles Zhang ae55fe6443 Propagate local call argument types optimistically as well.
PROPAGATE-LOCAL-CALL-ARGS computes a local function's parameter types
by unioning the argument types across its call sites, starting each
parameter at T and narrowing. That descends the lattice, and it cannot
converge once the argument flow has a cycle in it: a call that hands a
parameter back to itself contributes the parameter's own current type,
so the union comes out (UNION <whatever> T) = T on every round and
stays there.

This means that a loop written tail recursively often gets less
precise types than its imperative variant:

  (do ((i n (1- i)) (x (list 1) x)) ((zerop i) x))     => CONS

  (labels ((rec (i x) (if (zerop i) x (rec (1- i) x))))
    (rec n (list 1)))                                  => T

We solve this by solving the local call argument type equations from
the bottom of the type lattice (i.e. from the empty type) as well,
only propagating the final optimistic type once the least fixpoint is
hit.

Fixes lp#486416.

Test cases and implementation sketch written by Claude Opus 5, code
and comments heavily simplified and edited by me.
2026-08-07 21:35:57 +02:00
Stas Boukarev 59adbea07c Fix file-position when ansi-stream-in-buffer is used 2026-08-07 22:13:22 +03:00
Stas Boukarev 00034f235f Remove ansi-stream-csize-buffer 2026-08-07 21:22:14 +03:00
Stas Boukarev b2a1d003f4 Move some code to the caller of external-format-char-size 2026-08-07 19:49:46 +03:00
Stas Boukarev cb64b7018a Declare that unread-char returns nil 2026-08-07 03:26:32 +03:00
Stas Boukarev b74f5c4ef4 Change how file-position works on variable encodings
Don't maintain a vector with character sizes.
Calculate the size from the byte buffer up to the current character
buffer position.
Reduces code duplication, reduces work if no file-position is needed.
2026-08-07 02:59:43 +03:00
Stas Boukarev 75a2118b33 read-sequence: don't test for lists first
It's a rare thing to do.
2026-08-06 19:00:46 +03:00
Douglas Katzman 1b0d28f480 Use correct test for a slot that can hold fixnum 2026-08-06 11:41:54 -04:00
Stas Boukarev ac330720f3 Fix a test 2026-08-06 06:58:17 +03:00
Douglas Katzman 40aa19c169 Guard a thing with backend-subfeatures 2026-08-06 01:42:54 +00:00
Stas Boukarev 4d06d766bb x86-64: fix debugger access to stack complex double-floats
Fixes lp#2162932
2026-08-06 01:51:01 +03:00
Stas Boukarev ffb6f743c0 ppc, ppc64: add %raw-instance-cas/signed-word 2026-08-06 00:44:13 +03:00
Douglas Katzman 341713c776 Add sb-vm:%atomic-exchange 2026-08-05 20:53:48 +00:00
Stas Boukarev 0a17885e27 x86-64: sign-extend logand constants to make them encodable
If it doesn't affect the result.
2026-08-05 23:43:58 +03:00
Douglas Katzman 5710e793ff Disable CSE logic 2026-08-04 15:45:52 +00:00
Stas Boukarev fa6891bcd1 Avoid creating bignums for (zerop (mask-field ...))
Which is a transformation of (ldb-test ...)
2026-08-04 17:38:18 +03:00
Stas Boukarev 81a76a6346 Improve the (zerop (ldb ..)) transform
Extend to words.
Transform (> (ldb ..) 0) as well.
2026-08-04 17:26:43 +03:00
Vasily Postnicov 86c7cb9eb9 Rewrite (zerop (ldb ...)) as (zerop (logand ...)) 2026-08-04 16:47:40 +03:00
Douglas Katzman 503f9b8a34 Return NIL from ok-to-flush for potentially trapping special refs
Some people will complain if we don't do this at least for safety 3.
2026-08-04 03:18:14 +00:00
Stas Boukarev 8b4b67101a functional-kind can't be zombie and let at the same time 2026-08-04 05:32:25 +03:00
Douglas Katzman 9c53205f5f Skip common subexpr elim for lambda enclosed in a let 2026-08-04 02:23:32 +00:00
Douglas Katzman 100c9c2bdc Perform local common subexpression elimination for some memory loads
The technique is to find "equivalent" loads in between which there is no
computation that affects the result of the load. Also it needs a surrounding
LET, which is augmented with a new temp variable as if the user did that.
This is slightly deficient for various reasons:
1. it won't do anything without the LET
2. the more kinds of common subexpressions we allow (such as math),
   the slower IR1-OPTIMIZE-COMBINATION is going to run
3. there are possibly other node types that should be allowed to intervene

On the plus side, it's not all that hard to extend the logic to accept
other functions as participants in common subexpressions.

All test cases plus a little bit of assistance from Gemini
2026-08-04 00:58:21 +00:00
Stas Boukarev b541f2f25b Fix a test on windows
"nul" returns NIL for file-position.
2026-08-04 01:35:04 +03:00
Stas Boukarev 588d0d281a Fix a test
lseek on /dev/zero returns zero on linux
2026-08-04 00:34:17 +03:00
Stas Boukarev bf87e9ab2c Fix file-position on copmosite streams
concatenated-stream wasn't processing buffered input correctly.
two-way-stream and echo-stream should just return NIL, as
file-position can't apply to both streams.
2026-08-04 00:12:14 +03:00
Stas Boukarev 8ee5b24141 sb-simd: separate x86-64 and arm64 things 2026-08-02 17:02:43 +03:00
Sylvia Harrington 1f70cb412c sb-simd: Implement vector sap-ref for arm64 2026-08-02 16:31:11 +03:00
arthur a659610f72 sb-simd: support for load/store to and from SAPs 2026-08-02 16:30:49 +03:00
Douglas Katzman 1a8c99523f Remove questionable profiling result
A profile from linux perf shows CONSET-ADJOIN at about 1.25% of total time.
I'm not sure how sb-sprof could be so wrong, though to be fair, the
profile in the comment was taken a month ago, before many changes.
2026-08-01 16:47:52 -04:00
Stas Boukarev d28fd45be7 Fix do-conset-elements for big-endian 2026-08-01 07:54:17 +03:00
Stas Boukarev 8619c09be1 Don't break M-. by manipulating *features* at compile-time, actually 2026-08-01 07:16:54 +03:00
Stas Boukarev a7547672be Don't break M-. by manipulating *features* at compile-time 2026-08-01 07:09:08 +03:00
Stas Boukarev efed523236 Avoid infinite recursion in remove-moves
Fixes lp#2162597
2026-08-01 01:46:49 +03:00
Douglas Katzman ed2340f71a Speed up looking in the ctype-list-hash-set
In a particular compile-file, this hashset grew to have a maximum probe
sequence length of 14, and with 2 million lookups, it was a performance
bottleneck. A better hash mixer cut the max PSL down to 7.
2026-07-31 03:13:59 +00:00
Douglas Katzman 1285374c8c Hack load_core_files by moving a static var
The purpose of this change is that if you expressly want to use read()
instead of mmap() to load core pages, you can set buggy_map_private=1
in your working copy.  A reason to do this is that certain versions of
linux perf will only look in /tmp/perf-N.map if an unknown function is
not in a file-backed memory range. As the title says- it's a hack.
2026-07-31 03:00:06 +00:00
Stas Boukarev 131e63dfc4 arm64, utf8-crlf-to-character-string: exit in time 2026-07-31 05:18:55 +03:00
Stas Boukarev 5f1c338ca6 arm64: simd utf8-crlf-to-character-string-sized 2026-07-31 04:38:07 +03:00
Charles Zhang f45092cdcd Assignment convert all the things.
Improve assignment conversion even more with what I believe to be a
maximal contification algorithm, finally closing the loop on the
comments headed by ###. It can now handle transitive tail calls, even
in mutual recursive scenarios. The cleanup limitation was also relaxed
to allow more local functions to get converted. We now have 356
assignment converted lambdas compared to the baseline of 340 in
self-build. State machine code using local functions heavily should
benefit even more (where higher order control flow gets transformed
into first-order TAGBODY/GO-like code, which is beneficial
particularly for dataflow analyses).

Here is the list of functions in self-build where we now assignment
convert more. The codegen can be easily verified to be better by
e.g. disassembling the code component for
DFO-SCAVENGE-DEPENDENCY-GRAPH.

* PROCESS-REF, PROCESS-LVAR in SB-C::NODE-CONSTANT
* FAST-NTHCDR in CL:NTHCDR
* SET-VALUE in SB-KERNEL::RESTART-UNBOUND
* (LAMBDA (K)) in PRINT-FLOAT, FLONUM-TO-DIGITS, FLONUM-EXPONENT
* EMIT-STRING in SB-FORMAT::COMBINE-DIRECTIVES
* CURRENT-FRAME in SB-DEBUG::BACKTRACE-START-FRAME
* TERMINATE-INITS in ATTEMPT-PSEUDO-ATOMIC-STORE-BUNCHING
* SCAVENGE-POSSIBLY-DELETED-LAMBDA in DFO-SCAVENGE-DEPENDENCY-GRAPH
* FAIL in CL:NCONC, FINISH in SB-SEQUENCE:DELETE-IF-NOT,
RETURN-NO-TIMEOUT in DECODE-TIMEOUT, BOUNDS-ERROR in ir1util.lisp,
CALL-NEXT-METHOD-0 in sb-simple-streams

As a side note for those interested in AI benchmarking: I tried to use
Claude Code Opus 4.6 for this task after writing the Fluet and Weeks
5.1 and 5.2 test cases manually. It completely failed and did nothing
useful after several days of grinding and even tripped over mismatched
close parentheses several times. The task was too difficult.

Opus 5 essentially one-shotted the task. The code from it is used here
almost verbatim with some minor changes, though the comments were
heavily edited to be more concise and understandable. It was checked
thoroughly to be close to something I would write myself and it even
came up with some more test cases here that exercise additional cases
that need to be considered while fixing them immediately after
prompting. So, color me impressed.
2026-07-30 22:28:04 +02:00
Stas Boukarev 0a4f44a4f2 arm64: off by one in utf8-to-character-string-sized 2026-07-30 06:12:38 +03:00
Stas Boukarev 87357677a4 arm64: full unicode decoding in utf8-crlf-to-character-string 2026-07-30 05:52:58 +03:00
Stas Boukarev ff3913b277 Fix a test for :interpreter 2026-07-30 01:02:18 +03:00
Charles Zhang a56065fe38 Fix test. 2026-07-29 23:01:48 +02:00
Douglas Katzman 629a0df182 Fix failure to choose a jump table for a key type of (MOD 4)
Ironically it was working when the key's derived type was _not_ known
to be exactly (MOD 4) with a CASE over 4 keys.
2026-07-29 20:56:46 +00:00
Douglas Katzman 52d8f80c92 Make character-set unparser more useful when cross-compiling
It's still possible to get it to fail in the way described in the comment,
but it's much more likely not to now.
2026-07-29 14:59:57 -04:00
Charles Zhang b8eb8dc486 Add some failing contification test cases from Fluet and Weeks.
Which can and should be optimized eventually.
2026-07-29 20:10:17 +02:00
Gabor Melis 7ee5314861 sb-manual: skip undefined things when building the manual 2026-07-29 09:41:59 +02:00
Gabor Melis 980d22466f Micro-optimize READ-STRING
No more calls to GENERIC-+.
2026-07-29 09:41:59 +02:00
arthur 05b15081a2 Correct the user facing function for vpsubusb instruction 2026-07-29 08:15:58 +03:00
Douglas Katzman 98ec86bb12 Clarify a comment 2026-07-29 00:05:47 -04:00
Stas Boukarev 773469344b Encode the remaining bmi1/2 instructions, movbe 2026-07-29 05:11:14 +03:00
Douglas Katzman 76d957fcc7 Change #-conset-is-sset to #+bitmapped-conset
Allowing a third mutually exclusive choice of #+adaptive-conset.
Also remove the FLET from do-conset-constraints-intersection.
2026-07-28 16:26:05 +00:00
Stas Boukarev 250bd9f167 The cerror in cold-fset works fine
Useful especially for slam.sh
2026-07-28 19:08:11 +03:00
Douglas Katzman b576ceb33f Grow consets more lazily
Start at 0 size because at least 10% of all CONSETs never get an element
inserted. And power-of-2 growth is too aggressive; the nearest dualword
works fine. About 75% of all consets have fewer than 3 dualwords.
This of course varies depending on the files being compiled, but held
true for self-build as well as many other things.
2026-07-28 15:24:31 +00:00
Douglas Katzman 10d014d56b Detection redefs in genesis for #+linkage-space
And there's no reason to allow continuing, as the error indicates
with near certainly that cold-init will fail on your screw up.
2026-07-28 14:42:28 +00:00
Gabor Melis 10cab6fb1c Micro-optimize %LOOKUP-SYMBOL 2026-07-28 11:29:07 +02:00
Gabor Melis 30cbf6b31b Micro-optimize GET-OUTPUT-STREAM-STRING
It's smaller now, and it does not do a full call to ASH.
2026-07-28 11:29:07 +02:00
Stas Boukarev f2ce4b2cf5 Better (dpb 0 (byte s 0) x) and (dpb -1 (byte s p) x) 2026-07-28 11:36:07 +03:00
Stas Boukarev fee81d4483 arm64: try sign-extending when encoding constants for logand 2026-07-28 11:34:37 +03:00
Stas Boukarev ac74dc12c4 arm64: use BIC instead of AND if it can load a smaller constant 2026-07-28 11:34:37 +03:00
Stas Boukarev 34977e0407 arm64: don't translate (dpb x (byte ..) 0) to bfm 2026-07-28 11:34:37 +03:00
Stas Boukarev e42312feda arm64: prefer orr + lsl to bfm 2026-07-28 11:34:36 +03:00
Stas Boukarev 32b3f5f79e Exclude 0 from fd-stream-element-size 2026-07-28 11:34:36 +03:00
Christophe Rhodes 09782c9c16 2.6.7: will be tagged as "sbcl-2.6.7" 2026-07-28 09:09:19 +01:00
Stas Boukarev 5fff18b78a substitute-single-use-lvar: don't avoid casts for multiple uses
Make them silent instead.

Fixes lp#1910289
2026-07-28 07:52:29 +03:00
Stas Boukarev 4331687bb8 Don't delete blocks during constraint propagation
When deleting SETs.

Fixes lp#2161789
2026-07-25 18:40:13 +03:00
Gabor Melis e45c5c70b5 sb-manual: fix indented code block parsing
... when the first line of the block looks like a list item.
2026-07-24 16:47:02 +02:00
Stas Boukarev c56f9b9d3c Typos 2026-07-24 15:55:57 +03:00
Christophe Rhodes 7969fb58e8 more draft NEWS 2026-07-24 11:37:41 +01:00
Stas Boukarev 27e9e4b0ca Fix a test
[skip ci]
2026-07-24 00:35:31 +03:00
Stas Boukarev 392382ba0b Add a test for utf8-to-character-string 2026-07-23 23:50:10 +03:00
Gabor Melis 223bc344bd Add documentation changes to NEWS 2026-07-23 16:12:31 +02:00
Stas Boukarev 2f717abb9c Mark a test as broken
[skip ci]
2026-07-22 04:55:55 +03:00
Douglas Katzman 7c1fd2b82f loongarch: Implement integer-length without a loop 2026-07-21 23:38:10 +00:00
Stas Boukarev 5476c17bad arm64: full unicode processing in utf8-to-character-string
This one is used by fd-streams.
2026-07-22 01:52:37 +03:00
Douglas Katzman 8a0d86c58f loongarch: Adhere to architectural spec for amor_db.d instruction
Section 2.2.7 Atomic Memory Access Instructions
 "If the AM* atomic memory access instruction has the same register number
  [for] rd and rk, the execution result is uncertain."
https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_amswapaddandorxormaxmindb_wd_ammaxmin_db_wudu

While "uncertain" could just mean that the result is unpredictable and it's
fine if you don't care, QEMU version 11 gives you a SIGILL in this case.
2026-07-21 19:51:40 +00:00
Stas Boukarev 7ab7c5accb arm64, utf8-strlen: unify some parts 2026-07-21 18:47:03 +03:00
Stas Boukarev 1e3e9bc7f6 Better addv umov usage
No need to turn #xFF into 1 by shifting right, sign extend with SMOV
and flip SUB to ADD.
2026-07-21 10:18:53 +03:00
Stas Boukarev b8c49e66c1 dup directly from a vector register 2026-07-21 09:24:04 +03:00
Stas Boukarev b7740944df Use dword sized registers after vpmovmskb 2026-07-21 07:00:42 +03:00
Stas Boukarev cead2bb637 Remove "simd-copy-" prefixes from functions 2026-07-21 07:00:38 +03:00
Stas Boukarev fdd4aeb23c simd-utf8-strlen: add a fast path for 1/2 bytes. 2026-07-21 06:33:47 +03:00
Douglas Katzman 83ec17c0a0 Implement sparse sets having greater storage density than SSET
Not compiled in yet but potentially part of the adaptive CONSET which
dynamically chooses between simple-bit-vector or sparse set of integers.
(Since constraints are indexed by small integers, CONSETs don't need SSETs
that store the constraints themselves - integers will do just fine.)
2026-07-21 03:12:46 +00:00
Douglas Katzman 52b2af5b94 Avoid type and array bound checks in loops of SSET operations
Particularly in the deletion algorithm, any object already in the set
is an SSET-ELEMENT and has a non-nil sset-element-number.
2026-07-20 18:14:46 +00:00
arthur c315c378e4 add vpsadbw, vpalignr and vpsubusb to sb-simd 2026-07-20 18:00:36 +03:00
Douglas Katzman a7e50f3c4a Improve the early return from SSET-DELETE and -MEMBER 2026-07-20 12:07:47 +00:00
Stas Boukarev f55213a95b Move instructions around in simd-copy-utf8-sap-to-character-string 2026-07-20 08:46:22 +03:00
Douglas Katzman da7d90ca9a Optimize SSET-INTERSECTION
Impose a stricter upper bound on consing as explained in the comments.
Test cases by Gemini
2026-07-19 11:33:20 -04:00
Stas Boukarev 0843efc927 x86-64, utf8-sap-to-string: remove redundant moves 2026-07-19 07:49:35 +03:00
Douglas Katzman 26a27bc8d8 Optimize SSET-DIFFERENCE
Iterating over the second set is preferred as it avoids an intermediate list,
and is worse only if the second set is much larger than the first.

Test cases by Gemini
2026-07-18 23:06:28 -04:00
Stas Boukarev 246af00412 Don't signal errors for (log qnan)
Fixes lp#2160268
2026-07-19 02:10:15 +03:00
Douglas Katzman 3751ecd356 Restore the ability to use SSETs as CONSETs
The bit-vector choice is still the default, however now we can run experiments
to see if an adaptive approach would make sense. First of all most consets are
small (< 64 bits) so they really could use just 1 word in the CONSET struct
instead of a separately allocated bit-vector. Over 64 bits the bit-vector is ok
but only up to a certain size. Eventually the vector waste so much more space
compared to an SSET because most CONSETs in large universes are not dense.
2026-07-18 17:10:26 -04:00
Stas Boukarev 3b5740a297 x86-64, utf8-sap-to-string: use a single ymm register for two xmm 2026-07-18 13:58:34 +03:00
Stas Boukarev 9939d74866 Use a memory operand instead of loading into a register, 2 2026-07-18 13:44:16 +03:00
Stas Boukarev 88b11e8094 Use a memory operand instead of loading into a register 2026-07-18 13:34:21 +03:00
Stas Boukarev 121f13c48b Correct #- 2026-07-18 06:09:49 +03:00
Stas Boukarev eb3e4d50f8 x86-64: simd encoding of the whole utf8 range for C strings 2026-07-18 05:28:37 +03:00
Stas Boukarev 094a492c82 Add utf8 strlen test 2026-07-18 05:28:05 +03:00
Stas Boukarev d6129e1920 Add tests for simd-copy-ascii 2026-07-18 05:28:05 +03:00
Douglas Katzman d3fa62156f Limit the scope of warning suppressions
* Rev 906a406a quieted all compiler notes coming from make-host-1,
  rendering moot the muffle-conditions code-deletion-note in shared.lisp,
  not to mention (satisfies unable-to-optimize-note-p) there as well.
* Prevent introduction of new occurrences of the optional+key warning
  by confining the suppression to precisely where there is old code.

We need to fix whatever is wrong with cross-typep so that make-host-2
correctly utilizes the &OPTIONAL-AND-&KEY-IN-LAMBDA-LIST condition.
2026-07-17 23:59:27 +00:00
Douglas Katzman 9c82bf8bdc Add missing feature to arm64 crossbuild test 2026-07-17 22:18:51 +00:00
Douglas Katzman 9bc6ee5903 Silence a bunch of gcc warnings
of this variety
  warning: suggest parentheses around ‘-’ in operand of ‘&’
2026-07-17 21:43:12 +00:00
Douglas Katzman 940bb873d1 build-all-cores 2026-07-17 21:06:42 +00:00
Douglas Katzman 81c43250dc Heed the optional+key style warning 2026-07-17 20:58:00 +00:00
Douglas Katzman 573b76f069 Revert do-conset-elements to older logic on 3 backends 2026-07-17 20:17:33 +00:00
Douglas Katzman 0aeedbcaf6 mips: Implement integer-length vop without looping 2026-07-17 19:51:05 +00:00
Douglas Katzman e4cd2e2548 Improve DO-CONSET-ELEMENTS a little more 2026-07-17 17:37:25 +00:00
Stas Boukarev 13527b1f60 x86-64: simd decoding of the whole unicode range for C strings 2026-07-17 07:05:36 +03:00
Stas Boukarev 3f1f44a4be x86-64: support byte-array inline constants 2026-07-17 04:55:59 +03:00
Stas Boukarev b30453bed8 arm64: speed up length calculation in copy-character-string-to-utf8 2026-07-17 04:29:33 +03:00
Stas Boukarev 0c48a0eec1 arm64, utf8-sap-to-character-string: reduce instruction dependencies 2026-07-17 03:06:41 +03:00
Stas Boukarev a6183f3c0d arm64: better bit packing in copy-utf8-sap-to-character-string 2026-07-16 21:59:16 +03:00
Douglas Katzman 8796281182 Fix arena-related crash 2026-07-16 15:46:05 +00:00
Stas Boukarev e3c2db021f Don't fmakunbound functions present in *handled-conditions*
Otherwise they themselves can't be compiled.
2026-07-16 18:01:32 +03:00
Stas Boukarev eda10e3e57 Fix a compile-time type error on bad arguments to concatenate
Fixes lp#2160747
2026-07-16 17:24:54 +03:00
Douglas Katzman b1c1f00f62 Add yet another way to run the parallelized build of cold-sbcl.core
Using a Bazel rule - which we can certainly commit to our git repo though
probably nobody will use it - I was able to get the end-to-end build time
excluding contribs down to 30 seconds using 300 execution machines.
The usual caveat pertains about *DERIVE-FUNCTION-TYPES* not informing
subsequent files of learned information.  But it's great for making
small algorithmic changes and running some basic smoke tests.
2026-07-16 03:06:24 +00:00
Douglas Katzman 6bd776dee6 Remove a line of output from genesis
Also fix some stype warnings if muffler gets reloaded
2026-07-16 02:56:38 +00:00
Stas Boukarev 3025a181b0 Replace a MUL with USHL 2026-07-16 04:45:53 +03:00
Stas Boukarev 0e34c1c4a8 More optimizations in copy-utf8-sap-to-character-string 2026-07-16 04:16:54 +03:00
Stas Boukarev ab04e16dd5 Micro-optimizations in copy-utf8-sap-to-character-string 2026-07-15 06:49:44 +03:00
Stas Boukarev 280e13f233 arm64: simd decoding of the whole unicode range for C strings 2026-07-15 04:12:18 +03:00
Stas Boukarev 4d6772fd1b arm64: support byte-array inline constants
Fewer instructions to load.
Saves registers on not having to pin in a descriptor register.
2026-07-15 00:32:12 +03:00
Douglas Katzman 2d6b8ff746 Move assembly step first in make-host-2
In my attempt to infer a somewhat graph-based compilation order rather than
simply a linear order, my build was telling me that the assembly routines
depended on output/ucd/* because they follow (by a lot) target-char linearly
and therefore must depend on anything that target-char does. Obviously that's
wrong. Putting the asm files first proves that they depend on no other file.

I would not have been surprised if this failed the crossbuild test because
some asm file depends on a constant that isn't defined until later,
but it seems they're actually all fine this way.
2026-07-14 17:40:47 +00:00
Douglas Katzman 83c7aafa19 Delete work files without pre-testing for existence 2026-07-14 15:18:42 +00:00
Stas Boukarev 6927ec50b9 arm64: encode more vector shift instructions 2026-07-14 00:43:39 +03:00
Douglas Katzman 809276aedd Avoid zillons of lstat() calls from %sbcl-homedir-pathname 2026-07-13 19:58:13 +00:00
Douglas Katzman cfbeebabb3 Set *derive-function-types* to T in make-contrib 2026-07-13 16:08:32 +00:00
Hayley Patton 90ce44aad5 Get the encodable ranges right for SAP-REF-{8,16,32} 2026-07-12 22:51:38 +03:00
Stas Boukarev 99af116141 arm64: encode prfm 2026-07-12 22:51:38 +03:00
Stas Boukarev 3bd658d129 arm64: better copy-character-string-to-utf8-byte-array
Use a single TBL instead of multiple BSL and multiple different TBLs.
2026-07-12 22:51:38 +03:00
Douglas Katzman 8aa85ec581 Enable *derive-function-types* in PCL build
Trade one hack for another basically
2026-07-12 19:13:27 +00:00
Stas Boukarev ba08d271de source-transform-union-typep: eql complexes are not numeric-types
Some checks failed
CL-host / ecl (push) Has been cancelled
CL-host / clisp (push) Has been cancelled
CL-host / ccl (push) Has been cancelled
CL-host / cmucl (push) Has been cancelled
CL-host / sbcl (push) Has been cancelled
Linux arm / build (push) Has been cancelled
Linux arm64 / build () (push) Has been cancelled
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Has been cancelled
Linux qemu / build (ppc64le) (push) Has been cancelled
Linux qemu / build (riscv64) (push) Has been cancelled
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Has been cancelled
Linux / build (x86, --with-sb-thread, ) (push) Has been cancelled
Linux / build (x86, --without-sb-thread, ) (push) Has been cancelled
Linux / build (x86, --without-sb-unicode, ) (push) Has been cancelled
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Has been cancelled
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Has been cancelled
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Has been cancelled
Linux / build (x86-64, --with-sb-thread, ) (push) Has been cancelled
Linux / build (x86-64, --without-sb-thread, ) (push) Has been cancelled
Linux / build (x86-64, --without-sb-unicode, ) (push) Has been cancelled
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Has been cancelled
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Has been cancelled
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Has been cancelled
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Has been cancelled
CL-host / compare-xc-host-fasls (cmucl, false) (push) Has been cancelled
CL-host / compare-xc-host-fasls (ccl, false) (push) Has been cancelled
CL-host / compare-xc-host-fasls (clisp, false) (push) Has been cancelled
CL-host / compare-xc-host-fasls (self, false) (push) Has been cancelled
Fixes lp#2160429
2026-07-11 21:18:44 +03:00
Stas Boukarev 14d60e26b1 Avoid using avx512 registers in generic routines
Some checks are pending
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Which forces avx512-capable allocation tramps.

Fixes lp#2160413
2026-07-11 18:03:41 +03:00
Douglas Katzman 173185836f Improve SSET capacity tracking and SSET-ADJOIN
Some checks are pending
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
* Since tombstones do not exist, there is no reason to separately
  record the available cell count and in-use element count.
* SSET-ADJOIN need not eagerly grow the SSET except when the vector
  length is 0. Only if it discovers that it must insert and the
  capacity is reached should it call SSET-GROW.
* SSET-GROW can avoid some conditional branching now that it won't
  be called with a vector length of 0.

Test cases and some assistance by Gemini
2026-07-10 21:11:40 +00:00
Douglas Katzman eba8865cfd Add test manifest entry
Some checks are pending
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
2026-07-10 15:23:54 +00:00
Douglas Katzman 1ce38f9567 Change SSET to not use tombstones
Some checks are pending
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Avoids 1 comparison and branch in the probe loop
2026-07-10 01:15:48 +00:00
Stas Boukarev 81229e243f Optimize instructions in copy-character-string-to-utf8-byte-array 2026-07-10 02:47:17 +03:00
Stas Boukarev 9f7e4928b8 arm64: simd encoding of the whole unicode range for C strings
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-07-10 02:25:55 +03:00
Douglas Katzman 794e689152 Delay decision to use MPH generator program until make-host-2
This works better for a sandboxed build by removing the presence check
during make-host-1 of an executable disk file that never gets executed.
2026-07-09 20:21:33 +00:00
Stas Boukarev 7cd3645c34 Adjust a test for windows 2026-07-09 21:10:01 +03:00
Stas Boukarev acf8f1e893 t 2026-07-09 20:31:17 +03:00
Stas Boukarev 77215fb2f3 mv-bind-unused-p: skip preceding mv-call arguments
Fixes lp#2160207
2026-07-09 20:02:05 +03:00
Douglas Katzman c5c0dba535 Possibly eliminate 1 or 2 instructions from DEREF of integer arrays 2026-07-09 17:01:07 +00:00
Stas Boukarev 2dc5c051b7 arm64: add vector clz cls
Some checks are pending
Linux arm64 / build () (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-07-09 10:17:29 +03:00
Stas Boukarev 117122e16d Skip an unreliable test
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-07-09 05:36:52 +03:00
Stas Boukarev 6ae12b7cd8 Out of bounds in simd-copy-character-string-to-utf8-byte-array too 2026-07-09 04:46:32 +03:00
Stas Boukarev c61d1ca77b Off by one in simd-copy-character-string-to-utf8-byte-array-avx2
Some checks are pending
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
2026-07-08 23:31:49 +03:00
Stas Boukarev 262b56a6e8 Fix out of bound writes in simd-copy-utf8-sap-to-character-string 2026-07-08 21:47:01 +03:00
Stas Boukarev 16b4097932 Improve x86-64 simd instruction sequences 2026-07-08 21:10:32 +03:00
Stas Boukarev 5d765ef0e2 Optimize some instruction sequences
Some checks are pending
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-07-08 08:25:21 +03:00
Stas Boukarev 2995327a38 Reduce register moves in string-to-utf8-byte-array 2026-07-08 06:54:38 +03:00
Douglas Katzman 0f19605f3d Get rid of a redundant sign-extend in SB-ALIEN:DEREF
Some checks are pending
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
2026-07-08 02:22:23 +00:00
Stas Boukarev da33c975a6 neon simd-copy-character-string-to-utf8-byte-array 2026-07-08 04:11:54 +03:00
Douglas Katzman d445661d42 Add remark on known bugs
Some checks are pending
Linux arm64 / build () (push) Waiting to run
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-07-07 19:24:17 +00:00
Stas Boukarev 51517b0a81 avx2 simd-copy-character-string-to-utf8-byte-array 2026-07-07 19:02:16 +03:00
Stas Boukarev 719c1bceb0 Slightly faster generic simd-copy-character-string-to-utf8-byte-array
Using sap-ref-8/16/32
2026-07-07 16:53:35 +03:00
Douglas Katzman c36b941e34 Overwrite the _first_ tombstone in a probing sequence
Some checks are pending
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
Taking the last, as was done, tends to lengthen the probing loop
2026-07-06 16:59:33 +00:00
Stas Boukarev e5edefadf3 Shrink the table in simd-copy-utf8-sap-to-character-string
Some checks are pending
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
From 4KB to 2.6KB by using an inverted index.
2026-07-06 02:57:56 +03:00
Douglas Katzman 9104b7ce06 Delete obsolete comments 2026-07-05 23:22:56 +00:00
Stas Boukarev de09ec440d avx2 simd-copy-utf8-sap-to-character-string 2026-07-06 02:16:30 +03:00
Douglas Katzman 41b8f562f4 Use COPY-SEQ in COPY-SSET
Some checks are pending
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
The remark that REPLACE lacked optimization was true in early 2007
when written and COPY-SEQ got a transform only in Dec 2007 (19efdada)
2026-07-05 17:16:30 +00:00
Douglas Katzman c09560decb Flip order of COND clauses in sset-member
Assuming the first probe is a hit, this is better. Otherwise no difference.
2026-07-05 14:34:24 +00:00
Douglas Katzman b3185f3806 Change sset-hash1 to MIX
When sset-hash1 was first implemented (rev 2df8b5a0) the MIX function was
in a target-only file. Google Antigravity said that the total latency of
the add-and-shift sequence is worse on most CPUs because it's a longer
serially-dependent instruction chain, despite looking cheaper than MUL.
2026-07-05 14:21:48 +00:00
Douglas Katzman a89ff67e77 Remove some type declarations
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
This generates better code because in FIND-OR-CREATE-CONSTRAINT the declaration
on Y is redundant with type tests in FIND-CONSTRAINT, and in FIND-CONSTRAINT it
is redundant with the ETYPECASE.
2026-07-04 20:55:43 +00:00
Douglas Katzman 74f07eb8f4 Fix crossbuild-runner
It doesn't work to omit avx512 from the darwin config which may have been
inadvertent. It's suspicious that a new non-working Makefile was checked in.
And I'm not sure why there are 5 features keywords to do one thing
if all of them are in fact mandatory as of now.
2026-07-04 20:42:56 +00:00
Stas Boukarev 85ea9b08c1 Save instructions in simd-copy-utf8-sap-to-character-string 2026-07-04 21:20:43 +03:00
Stas Boukarev 43b5018966 arm64: add BIC <Vd>.<T>, #imm8
Some checks are pending
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-07-04 17:53:45 +03:00
Stas Boukarev d0d9c0df6f Remove a couple of instructions
Some checks are pending
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-07-04 05:54:29 +03:00
Stas Boukarev a238aa5c91 Adjust a test.
Some checks are pending
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
2026-07-04 00:04:37 +03:00
Stas Boukarev a3e000bbd4 arm64: decode 1/2-byte utf8 C strings using SIMD 2026-07-03 23:22:02 +03:00
Gabor Melis 2be4173812 various documentation changes
Some checks are pending
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux arm / build (push) Waiting to run
Linux arm64 / build () (push) Waiting to run
Linux qemu / build (ppc64le) (push) Waiting to run
Linux qemu / build (riscv64) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread --with-nonstop-foreign-call, sse4) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (arm64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc --with-nonstop-foreign-call) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread --with-nonstop-foreign-call) (push) Waiting to run
Windows arm64 / build (arm64, clang-aarch64, clangarm64) (push) Waiting to run
Windows / build (x86-64, ucrt-x86_64, ucrt64) (push) Waiting to run
- make bug reporting instructions more consistent

- add DOCUMENTATION file

- deduplicate Texinfo @cindex lines

- fix typos and URLs

- update obsolete references to Texinfo

- standardize the spelling of HyperSpec
2026-07-02 14:47:25 +02:00
Stas Boukarev ff7a653710 avx2 simd-copy-character-string-to-utf8-byte-array 2026-07-02 03:11:34 +03:00
Stas Boukarev 8b5a25e7cd count transforms: accept :key and :test 2026-07-01 22:11:52 +03:00
Stas Boukarev 23aa0d832b Remove ymm-reg zmm-reg SCs
Shouldn't be used, int-avx2/512-reg exist for that.
2026-07-01 17:32:00 +03:00
Stas Boukarev 05b1b82412 context-float-register: support integer ZMMs 2026-07-01 17:27:52 +03:00
Gabor Melis 739a65fe11 doc: fix some typos and readability issues
Thanks to Štěpán Němec.
2026-07-01 15:14:58 +02:00
Gabor Melis 34dda2dde1 Don't canonicalize whitespace in Texinfo files
Almost all of them are generated.

Also, fix some comments.
2026-07-01 15:14:58 +02:00
Gabor Melis 2c524ff00b Reduce core size impact of docstring normalization
- Conditionalize it on #+sb-doc.

- Drop Markdown blockquote support (it's not needed by any docstring
  currently).

- Make the code more compact.

Without :SB-DOC, the core size impact is thus zero. With :SB-DOC, the
core size is increased by ~0.05% (~10kB).
2026-07-01 15:14:37 +02:00
Stas Boukarev b76c7fe958 Save avx512 state in separate alloc tramp routines 2026-07-01 06:00:38 +03:00
arthur bdc8c073cf Basic support for avx512 2026-07-01 04:31:38 +03:00
Stas Boukarev db2b204bb1 emit-evex: fix encoding of high zmm registers 2026-07-01 04:13:41 +03:00
Robert Smith 36fceec808 avx512 assembler support 2026-07-01 04:13:39 +03:00
Sylvia Harrington cb716e24d6 sb-simd: arm64 support 2026-07-01 01:15:08 +03:00
Sylvia Harrington bb63ab41bf arm64: More simd instructions 2026-07-01 00:50:34 +03:00
Sylvia Harrington ba8d93710c arm64: Implement SIMD-PACK 2026-07-01 00:50:26 +03:00
Sylvia Harrington f99638c4e0 sb-simd: Portability fixes
This is mostly just building on what already existed, primarily
only defining and calling VOPs where the instruction set exists.
Also a phony simd-pack-256 type to allow building when that
type doesn't exist.
And disable the vref vop implementation outside x86oids, as it's entirely
specific to that instruction set.
2026-07-01 00:44:25 +03:00
Gabor Melis 1b4ec23342 doc: remove unnecessary markup 2026-06-30 17:00:48 +02:00
Gabor Melis 27621b01ca Make DOCUMENTATION strip markup from SBCL definitions
... and normalize the indentation of their docstrings, too.

Doing this lazily in DOCUMENTATION allows interactive work on
docstrings (e.g. change a docstring, recompile its definition,
generate documentation from the image). I don't think the overhead in
DOCUMENTATION is a factor.
2026-06-30 16:59:49 +02:00
Stas Boukarev 3335c2b150 #+ 2026-06-30 04:34:43 +03:00
Stas Boukarev 55322d716c NEON simd-copy-utf8-to-base-string 2026-06-30 04:23:08 +03:00
Stas Boukarev 3f79152d61 delete-no-op-vops: transfer tn-readers too
To avoid confusing peephole optimizers

Reported by Scott L. Burson.
2026-06-30 02:46:42 +03:00
Stas Boukarev ca75aca96a Make sb-int:misc-index foldable, flushable 2026-06-29 17:14:19 +03:00
Gabor Melis ab6fa91796 sb-manual: add links from/to PAX world 2026-06-29 14:01:32 +02:00
Gabor Melis 34812e52a1 sb-manual: readd concepts 2026-06-29 14:01:32 +02:00
Gabor Melis 40658bfd6a sb-manual: implement concept indexing 2026-06-29 14:01:32 +02:00
Gabor Melis 2e9dc0721f manual: arrays are row-major
Thanks to Scott L. Burson (lp#2158033)
2026-06-29 14:01:32 +02:00
Gabor Melis 6e2bcf1d9b doc: make PAX PDF much shorter
... by reducing the font size and the margins.
2026-06-29 14:01:31 +02:00
Gabor Melis 7901ac4063 doc: fix compilation on windows 2026-06-29 14:01:31 +02:00
Gabor Melis c50ce6dcaf sb-manual: fix CONVERT-DOCSTRING-PACKAGE-OVERRIDES-TO-PAX 2026-06-29 14:01:31 +02:00
Gabor Melis 61e352d105 sb-manual: add support for [label](uri) and [label][id] 2026-06-29 14:01:31 +02:00
Gabor Melis 79e63158c9 make-pax-docs: muffle source location warnings 2026-06-29 14:01:31 +02:00
Gabor Melis 4499dc6430 sb-manual: automatically USE-PAX
Put a magic marker on the value of the variable holding the dummy
section. Variables with these markers are recognized by PAX (from
v0.4.12) as lazy sections. So, (DREF @FAKE 'SECTION) works. Then,
whenever such a reference is RESOLVEd, the function following the
magic marker is called. That function is USE-PAX in this case.

The net effect of this hack is that PAX:DOCUMENTing a fake section
will unfake it.

Export USE-PAX for the remaining cases.
2026-06-29 14:01:31 +02:00
Gabor Melis 98d37dc3e3 sb-manual: USE-PAX automatically if PAX is already loaded
... when sb-manual is loaded.

SWITCH-TO-PAX was renamed to USE-PAX.
2026-06-29 14:01:31 +02:00
Gabor Melis 55fe2df553 doc: fix overlapping section numbers and title in the PDF toc 2026-06-29 14:01:31 +02:00
Gabor Melis f319e996d1 sb-manual: make GENERATE-TEXINFO unaffected by SWITCH-TO-PAX 2026-06-29 14:01:31 +02:00
Gabor Melis 7c2785fe2a Add support for (DOCUMENTATION ... 'declaration)
- Add docstrings for user-facing declaration.

- Fix the hacks for declarations in the manual.

- Add documentation of DOCUMENTATION extensions to the manual.

- Add a "Declaration Index" appendix to the manual.
2026-06-29 14:01:31 +02:00
Gabor Melis b3bfe02876 doc: update generated texinfo files 2026-06-29 14:01:31 +02:00
Gabor Melis 316291e371 doc: update lisp definition docstrings for Markdown
This is a follow up to the "PAXlike docs" commit.
2026-06-29 14:01:31 +02:00
Gabor Melis 4271a2f375 doc: PAXlike docs
Summary
-------

Implement of a subset of PAX so that we can write PAX:DEFSECTIONlike
forms that supports the same restricted Markdown that we use for
docstrings and generate doc/manual/*.texinfo files from them.

Without PAX
-----------

There is no hard dependency on PAX. When the new SB-MANUAL contrib is
loaded, one can M-. around in documentation (sections are variables),
and function docstrings can now link to sections.

The generated Texinfo files are quite close to the originals, with
some loss of "semantic" markup: e.g. Markdown has `FOO` but no
@var{FOO} and @code{FOO}. We didn't derive much practical benefit from
that distinction.

With PAX
--------

(SB-MANUAL::SWITCH-TO-PAX) ensures that PAX is loaded and patches things
up, as if everything had been defined with PAX to begin with. Now, we
get PAX::@BROWSING-LIVE-DOCUMENTATION for low-latency, interactive
documentation work and PAX::@GENERATING-DOCUMENTATION for auto-linked
documentation.

Notable features:

- auto-generated links within the manual: if SB-EXT:EXIT is mentioned,
  then it's linked to its documentation.

- auto-generated links to the CLHS (these links are red in PDF)

- locatives (e.g. the "[function]" in "- [function] SB-EXT:EXIT" are
  also links and they go to the sources on GitHub (in live browsing,
  they tell Slime to open the definition)

Details
-------

- Factor out the Markdown-to-Texinfo code into a new SB-MANUAL
  contrib.

- Convert doc/manual/*.texinfo files to PAXlike DEFSECTION format and
  add each chapter as a contrib/sb-manual/doc/<chapter>.lisp file.

- Fix a *lot* of small issues during the conversion.

- Make doc/make-doc.sh regenerate the all .texinfo files except
  sbcl.texinfo and backmatter.texinfo.

- Fix docstrings of Lisp definitions used in the manual to conform to
  the supported Markdown syntax.

- Retain the Texinfo function, variable and type indicies but drop the
  concept index. There is no obvious way to support that in Markdown,
  and it was used rather sporadically rather incomplete.

- Even with  the new features, the  amount of Lisp code  didn't change
  significantly.

- See contrib/sb-manual/README for the Todo list
2026-06-29 14:01:31 +02:00
Gabor Melis e20983b2ad doc: add new lisp manual files
This is in preparation for the "PAXlike docs" commit.
2026-06-29 14:01:31 +02:00
Gabor Melis 3dc327b828 Silence "<internal-feature> no longer present on *FEATURES*"
... warnings when *READ-SUPPRESS*.
2026-06-29 14:01:31 +02:00
Gabor Melis 6ac843434a Fortify SB-INTROSPECT:FIND-DEFINITION-SOURCES a bit
Not sure how to reproduce the failure.
2026-06-29 14:01:31 +02:00
Stas Boukarev 1d412776bb style-warning 2026-06-29 05:43:23 +03:00
Stas Boukarev b6b1188ebf x86-64, load-fp-immediate: dispatch on the value, not destination
Fixes lp#2158587
2026-06-29 05:35:13 +03:00
Stas Boukarev d8a8a93405 Remove redundant parameters in x86-64/float.lisp 2026-06-29 03:11:25 +03:00
Stas Boukarev 8a9a573add x86-64: fix complex float VOP macros after changing to fp-immediate
Fixes lp#2158580
2026-06-29 02:46:57 +03:00
Stas Boukarev 6049350858 Unused variable 2026-06-29 01:28:57 +03:00
Stas Boukarev f7c75a2020 sse2 simd-copy-utf8-sap-to-character-string 2026-06-29 01:11:15 +03:00
Stas Boukarev c0bf0a6cd8 read-from-c-string/utf-8/lf: use memcpy for all-ascii to base-string 2026-06-29 00:56:48 +03:00
Stas Boukarev db02ba3bce arm64: implement simd-copy-utf8-sap-to-character-string using NEON 2026-06-28 23:39:48 +03:00
Stas Boukarev 7e81a161c7 arm64: add stX simd multiple structure instructions
Based on a patch by Sylvia Harrington.
2026-06-28 23:39:28 +03:00
Stas Boukarev 2206fab7cc avx2 simd-character-string-utf8-length 2026-06-28 19:46:04 +03:00
Stas Boukarev e2165ebf76 x86-64-simd: more compact loading of -1 2026-06-28 19:01:32 +03:00
Stas Boukarev 74add191be AVX2 simd-utf8-strlen 2026-06-28 18:51:37 +03:00
Stas Boukarev cd361d1a4d arm64: use fmov to move complex immediates 2026-06-28 16:02:13 +03:00
Stas Boukarev ed6a7c9a44 arm64: better complex float array VOPs 2026-06-28 16:02:13 +03:00
Stas Boukarev a549f8c135 arm64: unify all float immediates 2026-06-28 16:02:13 +03:00
Stas Boukarev 5b6a30331b x86-64: unify all float immediates 2026-06-28 16:02:13 +03:00
Stas Boukarev 225e9c1f80 Don't cons constant complexes for local calls
If they end up in descriptor registers.
2026-06-28 16:02:13 +03:00
Stas Boukarev b81fef15a6 x86-64: remove fp-...-zero-scs
No different from fp-immedaite-scs, frees up four SC numbers.
2026-06-28 16:02:13 +03:00
Christophe Rhodes 8fbf3824e4 2.6.6: will be tagged as "sbcl-2.6.6" 2026-06-28 09:33:48 +01:00
Christophe Rhodes cbdaa062e9 Try to defend against releasing binaries with a hash suffix version
(I have only attempted write the check to stop the build if it's
wrong, not tested it.)
2026-06-27 20:36:15 +01:00
Stas Boukarev a248b46823 NEWS 2026-06-27 16:02:13 +03:00
Christophe Rhodes 73c2618272 Draft NEWS for sbcl-2.6.6 2026-06-27 12:56:07 +01:00
Stas Boukarev 140cb5c479 arm64/simd-utf8-strlen: use a different register 2026-06-26 04:44:39 +03:00
Stas Boukarev 31404b70cb arm64-simd: off-by-one in check-ascii 2026-06-25 04:17:44 +03:00
Stas Boukarev c217354fa1 arm64, simd-copy-character-string-to-utf8: use correct lane width 2026-06-25 03:55:47 +03:00
Stas Boukarev 20da80749a arm64: fix simd-copy-utf8-crlf-to-character-string
A loop increment got removed while editing
2026-06-25 03:41:01 +03:00
Stas Boukarev f03e003693 Add a test for output-to-c-string/utf-8/lf 2026-06-24 23:20:36 +03:00
Douglas Katzman 0907b4329e Stop trying to make deterministic standard-class hashes 2026-06-24 07:48:07 -04:00
Stas Boukarev 61b916416d Add a test for simd-character-string-utf8-length 2026-06-24 03:31:06 +03:00
Stas Boukarev 5afb7d8a0a Adjust a test 2026-06-22 21:50:41 +03:00
Stas Boukarev 46780e0666 Add tests for simd-utf8-strlen 2026-06-22 21:04:07 +03:00
Stas Boukarev b4c1ff116f arm64: disassemble shifted immediates directly 2026-06-19 06:55:55 +03:00
Stas Boukarev 2deb9c3043 arm64: optimize simd-character-string-utf8-length some more 2026-06-19 06:34:08 +03:00
Stas Boukarev 91b54fdda8 arm64: optimize simd-character-string-utf8-length 2026-06-19 06:25:37 +03:00
Stas Boukarev 19cf152c1d amr64: encode movi immediates without requiring manual shifting 2026-06-18 18:32:38 +03:00
Stas Boukarev 830f654b93 arm64: implement simd-character-string-utf8-length using NEON 2026-06-18 08:45:15 +03:00
Stas Boukarev 836190da1c Speed up output-to-c-string/utf-8/lf 2026-06-18 03:52:46 +03:00
Stas Boukarev 7ee71e8a92 Fix interpreted calls to c-string-to-string 2026-06-17 22:48:33 +03:00
Stas Boukarev ff7e3a1ca6 Don't cons SAPs for sb-alien::c-string-to-string for :utf-8 2026-06-17 17:27:17 +03:00
Stas Boukarev 8db96a30b5 Optimize read-from-c-string/utf-8/lf
With better portable functions with some SWAR.
With a SIMD utf8 validator on arm64.
2026-06-17 06:07:43 +03:00
Sahil Kang d1eead8b25 Optimize sb-thread:barrier for arm64
When using sb-thread:barrier before, a full DMB SY instruction was being
emitted. This patch updates the :memory, :read, and :write args to emit
DMB ISH, DMB ISHLD, and DMB ISHST instructions, respectively.

This change still aligns with the sb-thread:barrier docstring.
2026-06-16 09:13:51 +03:00
Stas Boukarev 6a3653971d arm64: restore bic, orn disassembly 2026-06-16 08:09:01 +03:00
Stas Boukarev 6e0c24685d Derive the type of (coerce n `(simple-array ,e (*))) 2026-06-15 21:44:12 +03:00
Stas Boukarev 9f4f424b4e arm64: implement FMOV <Xd>, <Vn>.D[1] 2026-06-14 16:55:00 +03:00
Stas Boukarev 1c657e05b2 arm64: add uqsub 2026-06-14 06:47:40 +03:00
Stas Boukarev 9e13318991 arm64: better umaxv disassembly 2026-06-14 06:47:37 +03:00
Stas Boukarev c236112864 arm64: always require vector sizes for simd instructions
Instead of defaulting to :16b
2026-06-14 02:26:47 +03:00
Stas Boukarev cfab1dd144 arm64: remove the remaining s- prefixes 2026-06-13 02:02:04 +03:00
Stas Boukarev 150d542e63 Fix do-conset-elements 2026-06-13 02:01:44 +03:00
Douglas Katzman 90ee741bec Fix CONSET-ADJOIN and CONSET-UNION
Those two are easy but in general rescanning for lowest/highest used indices
on every operation won't be a win. (We could store a "recompute" flag which
the iterator macro notices, and tries to tighten the bounds)
DELETE could test whether you're deleting the lowest or highest element as
a special case, and I'm not certain if interection and set-difference admit
any simple improvement at all.
2026-06-12 18:52:10 -04:00
Douglas Katzman 9ea5804624 Speed up DO-CONSET-ELEMENTS using CTZ if available
Often these vectors grow to 8K bits but have only 5 bits set. The iterator
naively visited every bit. Instead, skip over nonzero words, and then look
directly at the 1 bits. Also, supposedly the lowest and highest used bit are
tracked, but the logic to do it seems incorrect in a safely wrong way,
meaning we have failed to tighten the bounds in many different places.

This change alone was enough for 2x bottom-line improvement on compile-file in
some files that spent 5% of their compilation time in JOIN-TYPE-CONSTAINTS.
2026-06-12 18:41:56 -04:00
Stas Boukarev ce243bfe33 arm64: unify some neon and ordinary instructions
Without the s- prefix.
2026-06-12 17:37:49 +03:00
Stas Boukarev ef6c771846 arm64: add neon shl 2026-06-11 04:19:03 +03:00
Stas Boukarev 1b5d6e2582 describe: call unencapsulated-function 2026-06-11 02:43:32 +03:00
Stas Boukarev a2eed39dab sb-introspect:function-lambda-list: employ sb-ext:unencapsulated-function 2026-06-11 02:34:24 +03:00
Stas Boukarev 00bf2651cc Don't change :test for subst based on the sequence type
It descends multiple levels.

Fixes lp#2156394
2026-06-10 23:16:41 +03:00
Stas Boukarev 0298a35f89 Don't cons a new list for (length (intersection a b)) 2026-06-10 18:32:57 +03:00
Douglas Katzman 3991dc73d6 Return constant string from NATURALIZE if length is 0 2026-06-10 09:38:41 -04:00
Stas Boukarev aa2788ebf7 Skip a test 2026-06-10 06:44:25 +03:00
Douglas Katzman 007463a97a Improve receiving some C strings from foreign function on 64-bit Unicode
If the string's EF is :ASCII and the desired element-type is BASE-CHAR then just memcpy.
2026-06-09 23:06:59 -04:00
Douglas Katzman 2df3f8071b Mix package-id into fun-name hashes
Indeed 32-bit x86 was observed to lack adequate randomization
2026-06-09 15:18:43 -04:00
Stas Boukarev 4336f7a1a4 Change static space address for darwin-arm64
The latest macOS can't mmap there.

Fixes lp#2156072
2026-06-09 21:13:03 +03:00
Stas Boukarev b0916688cb Check types for concatenate-subseq 2026-06-09 02:31:59 +03:00
Stas Boukarev ddedba2289 arm64: can't call sc-is on unused tns
Fixes lp#2155788
2026-06-07 04:44:38 +03:00
Piotr Kubaj db0328683b ppc64: fix big-endian ELFv2 build
There are numerous assumptions that big-endian => ELFv1, little-endian
=> ELFv2. That is incorrect, there are systems running on big-endian
ELFv2.
2026-06-06 18:36:03 +02:00
Douglas Katzman 3efad92f20 Add a missing opaque-identity 2026-06-05 13:06:43 -04:00
Douglas Katzman f3d711cd2a Sketch out a way to trace/intercept foreign calls 2026-06-05 12:52:23 -04:00
Stas Boukarev 9deb748799 Turn (copy-list small-constant) into (list ,@constant) 2026-06-05 03:16:36 +03:00
Stas Boukarev a3cfdde6a3 lvar-constants: combine functions and refs from multiple uses 2026-06-05 02:59:50 +03:00
Stas Boukarev 898313d8e7 More constant modification pass-throughs 2026-06-05 02:58:13 +03:00
Stas Boukarev ac5a3f378a constant-sequence-element-type: ignore circular lists 2026-06-05 02:13:20 +03:00
Stas Boukarev b378f284ea Add a type deriver for ELT
It's not always transformed to NTH or AREF.
2026-06-05 01:30:34 +03:00
Stas Boukarev de8f08567e Unify the sequence element-type derivers 2026-06-05 01:30:10 +03:00
Stas Boukarev a7b2d403a2 Derive AREF type for multiple uses with constants 2026-06-04 22:59:14 +03:00
Stas Boukarev 5881276137 check-concatenate: consider each constant value 2026-06-03 04:16:51 +03:00
Stas Boukarev 91b8b81d14 More thorough type checking for concatenate arguments
Using sequence-elements-type, which works for constant lists and vectors.
2026-06-02 23:50:22 +03:00
Stas Boukarev 2329ddf0dc coerce derive-type: exclude rational types 2026-06-01 06:34:40 +03:00
Stas Boukarev 8c7db50607 (coerce 1 'list) should signal an error 2026-05-30 17:21:47 +03:00
Stas Boukarev 54d7e2b902 coerce type derivation: preserve simple array dimensions 2026-05-30 17:21:47 +03:00
Stas Boukarev f5195f65be coerce type exclusion: add (and array (not simple-array)) 2026-05-30 17:21:47 +03:00
Gabor Melis 2868d4dd0e doc: define and clean up docstring syntax
Previously, the format was ad-hoc and implicitly defined by
doc/manual/docstrings.lisp. Now, it is a bit less ad-hoc and still
implicitly defined docstrings.lisp.

The syntax is now a simple, strict subset of Markdown with escaping
extensions. The long comment near the top of docstrings.lisp has the
documentation.

Some notable changes:

- Markdown backticks are supported (e.g. `exit`(3),
  `/usr/local/bin/`).

- When the heuristic codification is overly eager, use backslashes to
  prevent codification (e.g. \\HTTP, where the backslash is doubled
  assuming that this is in a docstring).

- It is now possible to have code that's not downcased
  (`\\\\AC_LOCAL`, backslashes doubled again).

- Fenced code blocks are supported (but use them sparingly).

- Texinfo @itemize is used instead of @table.

- Texinfo @var was inconsistently used at best. What used to be @var
  is now simply @code.

For the user, the most visible effect of this change is that the
manual has much fewer errors in codification, and a few docstrings
have backticks and escapes in them, which should be acceptably
readable in the sources or via CL:DOCUMENTATION.
2026-05-30 11:14:29 +02:00
Gabor Melis cec8b39657 doc: improve @code{}ification in the user manual
1. Previously, all uppercase words were downcased and enclosed in
texinfo @code{}, which didn't handle many common cases correctly. With
this change, only words that name interned symbols or packages are
codified:

        POSIX -> POSIX (was @code{posix})
        UDP -> UDP (was @code{udp})

    The symbol name is looked up in the heuristically determined package,
    which tries to match the package in the IN-PACKAGE form in effect
    where the docstring is in the sources. This means that if M-. works in
    Slime, then the documentation generator should be able to figure out
    that it's code.

    This change revealed several typos in the docstrings where the all
    uppercase word did not correspond to the name of an interned
    symbol.

2. Lowercase suffixes are now stripped from the word:

    STRINGs -> @code{string}s (was STRINGS)
    CLASSes -> @code{class}es (was CLASSes)
    SETFable -> @code{setf}able (was SETFable)

3. #\' is now a delimiter, so this works:

    ARRAY's -> @code{array}'s (was ARRAY's)

4. Trailing #\: characters followed by whitespace are considered
delimiters:

    NIL: -> @code{nil}: (was @code{nil:})

5. Fixed the *NOT-SYMBOLS* opt-out mechanism (renamed to *NOT-CODE*)
and added an opt-in (*CODE*).

Overall, the new heuristics work much better with current docstring
style. However, there is no way to get all cases right, so explicit
markup in docstrings will be needed. Fixing that would require even
more of MGL-PAX, so I'm stopping here.

Also, we should probably have the generated documentation (a single
file, in a format suitable for diffing) under version control so that
we can detect documentation typos more easily.
2026-05-30 11:14:29 +02:00
Gabor Melis 02bd195c1a doc: tweaks 2026-05-30 11:14:29 +02:00
Gabor Melis 39ea7adbef Bind *PRINT-READABLY* to NIL when printing TRACE "returned" message
It was already bound to NIL for the "call" message.
2026-05-30 11:01:45 +02:00
Gabor Melis 92d060d082 Housekeeping: whitespace, typos, comments, credits 2026-05-30 10:57:36 +02:00
Gabor Melis e1c2bc15e2 Improve reporting of NOTINLINE full calls in make-host-2.lisp
Previously, make-host-2.lisp reported full calls of inline functions
even if all full calls were NOTINLINE. This was because the diagnostic
loop failed to check the 0th bit of the EMITTED-FULL-CALLS cell (via
ODDP), which PONDER-FULL-CALL specifically uses to track whether any
of the calls lacked a NOTINLINE declaration.

Background: When accommodating compilation dependencies in other
ways (such as changing the build order) is too difficult, NOTINLINE is
used to avoid the compilation failures that a full call to a function
that's later inlined would cause.

With this change, there are no "Likely suspicious" calls reported on
the default x86-64 build.
2026-05-30 10:57:36 +02:00
Gabor Melis 48063e4170 doc: document sb-introspect 2026-05-30 10:57:36 +02:00
Gabor Melis 480584f800 pcl: Remove GDEFINITION
Since encapsulation of generic functions is implemented not with
wrappers but within the discriminator function, GDEFINITION is
equivalent to FDEFINITION for them.

(SETF GDEFINITION): was also removed, as I couldn't find a reason for
calling NOTE-NAME-DEFINED before (SETF FDEFINITION).
2026-05-30 10:55:46 +02:00
Gabor Melis d9b4878a31 Make FDEFINITION not strip encapsulation
This fixes the ANSI non-compliance passed down from early
CMUCL (1991-10-31). The bug was that FDEFINITION did not return the
same value as SYMBOL-FUNCTION for symbols (lp#799533). The fix is an
incompatible change but only affects encapsulated (e.g. TRACEd and
SP-PROFILE:PROFILEd) non-generic functions.

However, encapsulations belong to the definition (the name) and not to
the function associated with the name, so (SETF (FDEFINITION NAME) FN)
strips encapsulations from FN and keeps the encapsulations of NAME.

- SB-EXT:UNENCAPSULATED-FUNCTION was added.

- Encapsulated functions are printed as

    #<FUNCTION FOO ENCAPSULATED>

  or, if they have no proper name, as

    #<FUNCTION FOO ENCAPSULATED {B1782332}>

  This is the same as for unencapsulated functions except for the
  additional " ENCAPSULATED".

- Unused slots were removed from SB-PROFILE:PROFILE-INFO.

- Since generic function identity is stable in face of encapsulation,
  CLOS is largely unaffected by this change.
2026-05-30 10:55:46 +02:00
Stas Boukarev 6f4581f924 More coerce type exclusion derivation 2026-05-30 00:51:06 +03:00
Stas Boukarev 8f0bf3b286 (coerce (the (not real) x) y) => (not real) 2026-05-30 00:51:06 +03:00
Stas Boukarev c418c07469 Lower :test for remove-duplicates 2026-05-30 00:51:06 +03:00
Stas Boukarev ad49eb3051 Lower :test for search and mismatch 2026-05-30 00:51:06 +03:00
Stas Boukarev dbfff0d07a Remove unused instructions in arm64/simd-copy-utf8-crlf-to-base-string 2026-05-30 00:51:05 +03:00
Stas Boukarev 300478c4e1 Unbreak generate-version.sh
Don't include the hash if it's at a release tag
2026-05-30 00:21:48 +03:00
Christophe Rhodes 85913ede1f 2.6.5: will be tagged as "sbcl-2.6.5" 2026-05-29 20:30:14 +01:00
Christophe Rhodes ca665565e5 Draft NEWS for sbcl-2.6.5 2026-05-28 21:36:13 +01:00
Douglas Katzman 891c77819e Suppress low-level event logging for #-sb-thread
Could be made to avoid mention of pthread_self() but I doubt anyone needs it
2026-05-26 05:28:18 +00:00
Stas Boukarev 4ad7155f4f Fix off-by-one errors in crlf swar routines 2026-05-24 05:58:11 +03:00
Stas Boukarev 8817a07e6c Fix a read-char transform
ansi-stream-in might return multiple values.

Reported by J Klein.
2026-05-24 03:49:38 +03:00
Stas Boukarev 8bd1830874 More specifier-type type mismatches 2026-05-24 02:47:50 +03:00
Stas Boukarev 9bebe3a395 Resolve an editing mistake in the char-code type deriver
Fixes lp#2154086
2026-05-24 02:33:16 +03:00
Stas Boukarev 828b918e05 Avoid a metacircle when finding component names
Don't turn them into strings. Printing can produce a pcl cache miss
that won't get resolved because it will try to print the name of the
new dispatch function.
2026-05-22 00:48:33 +03:00
Stas Boukarev 8d1ca5121c arm64, arch_do_displaced_inst: add SIMD LDR (literal) 2026-05-21 03:03:57 +03:00
Stas Boukarev f716ffe01c Resolve more potential issues in arch_do_displaced_inst
Update the link register.
Handle CBZ on 32-bit registers.
2026-05-21 02:39:40 +03:00
Stas Boukarev eb1a8630eb arm64, arch_do_displaced_inst: don't lose on prfm (literal) 2026-05-21 02:18:03 +03:00
Stas Boukarev b5895fddc9 arm64, arch_do_displaced_inst: handle ldrsw (literal) 2026-05-21 02:13:38 +03:00
Stas Boukarev 8225c3f22b arm64: fix arch_do_displaced_inst for LDR 2026-05-21 01:49:04 +03:00
Charles Zhang a7ee538661 Work around some Windows issue.
No idea.
2026-05-20 21:44:02 +02:00
Stas Boukarev a72425d87f sb-posix: more robust structure round-trips
Save and restore any unnamed fields.
2026-05-20 20:54:11 +03:00
Stas Boukarev f825ab5db6 Restore building sb-posix on musl
Which gives different names to termios slots

Fixes lp#2153432
2026-05-20 18:37:29 +03:00
Charles Zhang 5c1cd2227f Fix accessing debug vars at post-call locations. 2026-05-20 12:08:56 +02:00
Charles Zhang f982475b0b arm64-arch.c: Fix soft-simulation of some instructions.
For breakpoint support.
2026-05-20 12:08:56 +02:00
Stas Boukarev 07f82d3591 Don't incorrectly lower sublis to :test #'eq
The first argument isn't actually the item it searches for.
2026-05-19 03:53:58 +03:00
Stas Boukarev 93b87fc504 Fix the SYMBOL restart for missing packages
Fixes lp#2153092
2026-05-19 03:27:50 +03:00
Charles Zhang 5b647a0f63 Muffle compiler notes correctly when compile-evaluating.
Limit the scope of the handler to just the compilation portion of the
form, not for execution which may include another compilation.
2026-05-18 23:54:19 +02:00
Stas Boukarev 259cd408e6 Return one value from (eval `(lambda ())) 2026-05-18 17:46:59 +03:00
Charles Zhang c8376074c6 Block compile some compiler related things together. 2026-05-18 12:50:29 +02:00
Charles Zhang 1f5238fe0b Allow the compile-evaluator to evaluate forms directly.
This change has the overall effect of having the evaluator properly
separate out top level code from any defined functions. See the new
test :EVAL-TOP-LEVEL-CODE-SEPARATE-COMPONENT and the existing tests
:STRUCTURE-SLOT-VALUE-IN-METHOD-NO-CALLEES and
:STRUCTURE-MISSING-SLOT-VALUE-IN-METHOD-SINGLE-CALLEE. As a bonus,
self call recognition works for COMPILE now. As a side effect,
we (correctly) get more redefinition warnings as well (for example for
WARN during bootstrap), which were missing before for some reason.

In order to achieve this, the following needs to be done:

* COMPILE does not have its own special way of doing ir1 conversion
for lambdas anymore, instead relying on the top level lambda machinery
to separate out the actual compiled code. This gives the correct
semantics for policy and compilation etc. for free without special or
duplicate logic, and removes all the stuff around
HAS-EXTERNAL-REFERENCES-P, which was an idea that was never really
finished. This allows us to extend COMPILE-IN-LEXENV to evaluate forms
directly and hence allow %SIMPLE-EVAL to not have to manually wrap the
lambdas either, so evaluation-via-compilation behaves like top-level
evaluation by the file compiler (of course without file compilation
semantics). LTV processing and fasteval also can just evaluate forms
directly with EVAL-WITH-COMPILE-IN-LEXENV.
* Storing source forms should always be off for PCL generated
functions, revealed by the clos-arena test. This was probably not
detected before because the policy inheritance was subtly wrong.
* Fix some tests to not rely on questionable behavior of how named
COMPILE interacts with global type information. Such behavior should
only work in compile file mode.
* The TL-XEP debug name had nothing to do with the actual TL-XEP
functional kind, which was confusing.
* TIME now counts all lambda conversions. Just ignoring the entry
points produced by COMPILE for the top level lambda didn't make much
sense since all other kinds of entry points get counted. It's there
purely to give a hint to the user how much work the compiler is doing,
not to count anything in the source being compiled.
* Core components need to have patch tables again. The fact that they
are exercised in warm bootstrap now means that we are likely actually
using the load time code stripping functionality not just in theory,
vut in practice as well.
* Add post ir1-toplevel processing smashing of names onto compiled
functions again to get names right. As an added bonus, this allows us
to get recognize self calls working for COMPILE functions.
* core debug source infos never actually used the function slot, and
it's not clear what function to give it when evaluating top level
forms, so delete it.
* Also fix > 3 decade old bug in MAKE-LISP-SOURCE-INFO in which a
plain vector was used when one with a fill pointer was expected. I
guess this code path hadn't been exercised in a long time.
2026-05-18 12:50:29 +02:00
Jan Moringen 2720527dfa Fix TAKE-NEW restart in EXPORT 2026-05-17 19:57:31 +02:00
Jan Moringen 7743b9db56 tests: Add a few missing IGNORE declaration in packages.impure.lisp 2026-05-17 15:06:28 +02:00
Stas Boukarev 772ca5717f sb-simd: fix shifting of s64.2 and u32.4
Fixes lp#2152791
2026-05-16 22:22:35 +03:00
Jan Moringen 7aee69c495 Fix KEEP-OLD restart in ADD-PACKAGE-LOCAL-NICKNAME 2026-05-16 12:39:15 +02:00
Stas Boukarev a8ba1ef64f substitute: warn about unfindable items 2026-05-16 03:28:08 +03:00
Stas Boukarev 1d3cebea7e Fix argument order for a transform 2026-05-16 03:15:44 +03:00
Stas Boukarev 0ede01cab4 Lower :tests for more functions 2026-05-16 03:07:08 +03:00
Stas Boukarev 02992badc6 Lower (member #\1 str :test #'char-equal) to :test #'char= 2026-05-16 01:44:16 +03:00
Stas Boukarev 8007e82231 Do not cons for (when (intersection a b))
(Except for a possible hash-table).
2026-05-16 01:20:50 +03:00
Stas Boukarev 1f8a40c435 Reduce recursion in sb-walker
For linear bodies.
2026-05-16 00:37:21 +03:00
Luís Borges de Oliveira f393489239 generate-version.sh: don't assume .git/ layout
Use git symbolic-ref instead of poking directly at the .git directory.
This way we can handle git worktrees where .git is not a directory.
2026-05-15 16:11:16 +01:00
Luís Borges de Oliveira 3a7a5218d4 generate-version.sh: don't print version_n_root=0 for branch builds
Before: "2.0.5.0.foo.12"
After: "2.0.5.foo.12"
2026-05-15 16:11:16 +01:00
Stas Boukarev de7356db63 nintersection and nset-difference do not modify the second list 2026-05-14 00:38:52 +03:00
Stas Boukarev 99cf2439f4 intersection: use hash-tables 2026-05-14 00:06:57 +03:00
Stas Boukarev c2b343bb56 replace: make sure LENGTH is inlined
At least when there are no :start/:end
2026-05-12 16:18:24 +03:00
Stas Boukarev e0efcd56dd Reduce type checks in invoke-fast-method-call 2026-05-11 15:37:09 +03:00
Stas Boukarev c7921a02d8 Faster keyword argument checking in CLOS
Copy what convert-more-entry is doing and inline it.
2026-05-10 00:04:01 +03:00
Stas Boukarev 9ce4f6ccc4 Faster compilation of TYPEP on disjoint numeric types
Fixes lp#2151818
2026-05-08 05:54:56 +03:00
Stas Boukarev 453d81b412 Improve UNION
Don't compute full lengths of lists.
Populate the hash-table with the shorter list.
2026-05-08 04:20:12 +03:00
Stas Boukarev c8aefbf5fe arm64: don't check types in the length/list VOP with zero safety 2026-05-07 03:02:45 +03:00
Stas Boukarev 5598c57d25 Don't verify-arg-count for XEPs with known calls 2026-05-06 22:40:12 +03:00
Stas Boukarev 0056dfb149 lambda-var-ref-lvar: correctly omit the arg-count var 2026-05-06 17:24:00 +03:00
Stas Boukarev f22a5de2af Don't break specialized-xeps by tail calling them 2026-05-06 06:30:00 +03:00
Stas Boukarev 13601a3af1 block-compilation 2026-05-06 04:57:41 +03:00
Stas Boukarev 4de59fbb03 Derive the return type of XEPs 2026-05-06 04:35:44 +03:00
Stas Boukarev 187f57e224 Catch type mismatches when calling XEPs 2026-05-06 04:11:33 +03:00
Christophe Rhodes ec1f07e79a Make sure TYPE-ERRORs have valid DATUM and EXPECTED-TYPE
We should not make generalized instances of TYPE-ERROR with unbound
DATUM or EXPECTED-TYPE, or where the DATUM is actually of type
EXPECTED-TYPE.  With #+sb-devel, provide a special variable to check
for mismatch when creating the condition, and turn that switch on when
running tests.

Fix the issues that this reveals:

- in sequence-related code, make sure any errors relating to the
  length mismatch between expressed type and sequence length have a
  precise size if appropriate.

- also in sequence-related code, special-case the NIL sequence type
  specifier, which is a recognizable subtype of LIST and VECTOR and
  yet not a good type for making sequences.

  (arguably the type error that the standard "expects" us to signal
  for the bad cases of MAKE-SEQUENCE and friends is that the
  constructed sequence is not of the type given by the type specifier,
  rather than that the type specifier is not of some strange
  VALID-MAKE-SEQUENCE-TYPE-SPECIFIER type.  However, that's not what
  we currently have.)

- in stream-related code, make new predicates for
  {BINARY,CHARACTER}-{INPUT-OUTPUT}-STREAM-P and use them in the ILL-X
  stream functions.

- make the PCL-internal MISSING-SLOT condition not be a TYPE-ERROR.

- make accessing an uninitialized structure slot, from &AUX arguments
  in BOA constructors with no defaults, not be a type error (according
  to the standard, accessing an uninitialized slot is undefined
  behaviour).
2026-05-05 21:37:09 +01:00
Stas Boukarev c7b985482a union: preserve the argument order passed to :test
Independent of the lengths of the input lists.
2026-05-05 08:39:38 +03:00
Stas Boukarev 374a5fe50e union: use hash-tables for :test #'string=, #'= 2026-05-05 06:14:23 +03:00
Stas Boukarev 36864b8314 SunOS doesn't have termios.c_ispeed
Reported by Andreas Wacknitz
2026-05-04 21:06:51 +03:00
Piotr Kubaj acd0f7e95a freebsd-ppc64: add missing FP functions 2026-05-04 15:19:57 +02:00
Stas Boukarev 0f4366f0ee sb-x86-64-asm::maybe-note-static-lispobj: use prin1 consistently 2026-05-04 09:14:34 +03:00
Douglas Katzman b5c57d2d40 Improve TYPEP for (and some-instance-type (not some-subtype))
Instead of a hierarchical layout test for the ancestor and then a test
to exclude the child, simply compare for EQness to a single layout.
2026-05-04 01:27:31 -04:00
Stas Boukarev 0c21989ac5 Simplify numeric type construction
Add a new function, make-numeric-type, which looks like
(make-numeric-type 'integer low high), not needing to construct a
list as for (specifier-type `(integer ,low ,high))
2026-05-04 00:46:23 +03:00
Stas Boukarev 206672bf25 digit-char: prefer a conditional move. 2026-05-03 19:24:26 +03:00
Stas Boukarev cd730df2e1 Add explicit-check to character 2026-05-03 01:23:14 +03:00
Christophe Rhodes 39a97c7328 Restore non-simple strings of length 1 as character designators
The 1 in the (STRING 1) type refers to the size of the underlying
array, not the length of the sequence.
2026-05-02 23:07:41 +01:00
Douglas Katzman 072061b567 Pass header as untagged word in alloc_immobile_fixedobj 2026-05-01 22:10:35 -04:00
Douglas Katzman 26add0a4ad Possibly avoid trying to call nonexistent openpty 2026-05-01 00:31:15 -04:00
Douglas Katzman bc13902c28 Bit-pack mutex-owner and state into one slot if #+sb-futex
Only for little-endian 64-bit. And if (and only if) doing it, then
represent mutex-owner as a kernel thread ID, not struct thread.

A slot becomes available for other uses without increasing the struct size
though #-compact-instance-header had a padding slot which could have been
taken. The size concern was for #+compact-instance-header.
2026-04-30 23:15:52 -04:00
Douglas Katzman a48121ddb3 Fix typo noticed when grepping for "contest" 2026-04-30 23:14:20 -04:00
Douglas Katzman 54825aa446 Use linguistically correct terminology
Google says: "Contested" implies an active challenge (like sports),
also used abstractly in nonphysical situations like politics,
whereas "contended" describes a state of resource competition.
It cites these sources as authoritative examples of "contended":
* Intel Architectures Software Developer’s Manual refers to
  Lock Contention and Contended Locks, not "contested locks"
* Computer Architecture: A Quantitative Approach (Hennessy & Patterson)
  refers to "uncontended acquisition", not "uncontested acquisition"
2026-04-30 22:31:14 -04:00
Stas Boukarev 373080b6a4 Don't let the CONJUGATE VOPs be overridden by a transform 2026-05-01 03:06:42 +03:00
Stas Boukarev 64efbd61f7 Replace a bunch of AVERs with better types 2026-05-01 01:56:36 +03:00
Douglas Katzman 9b67e9100d Add some remarks and a utility function 2026-04-30 18:44:54 -04:00
Douglas Katzman 84d5a7b46b Balance out threads.pure test times
8 seconds in semaphore, 7 seconds in threads-slow, the rest can stay
2026-04-30 18:34:46 -04:00
Douglas Katzman 44c6928308 Use a barrier instead of CAS in mutex-owner
Rev 5234b3ca in 20009 added a CAS because BARRIER did not exist.
BARRIER was invented later, rev 65b5ab7e in 2010.

And remove inline which has no reason for being
2026-04-30 13:35:45 -04:00
Christophe Rhodes 4acf4acdbd Test the new :alien-callback definition type in sb-introspect
Both directly, and as a possible type for checking invalid names
2026-04-30 17:07:33 +01:00
Christophe Rhodes 8a15ebb136 Test the previous-relative encoding of xref form-number
The simplest of smoke tests only
2026-04-30 17:06:45 +01:00
Stas Boukarev 7a6a70dbb8 describe: alien types and callbacks 2026-04-30 15:25:39 +03:00
Stas Boukarev 1434677ca0 find-definition-sources-by-name: find alien callbacks 2026-04-30 15:17:13 +03:00
Stas Boukarev 6d83d9db42 Fix map-packed-xref-data
Wasn't fully adjusted to the new pack-xref-data.
2026-04-30 15:01:49 +03:00
Douglas Katzman 6f6ad7d5bc Hoist with-pinned-objects out of a loop
Slightly better than repeated bind/unbind
2026-04-30 05:49:24 -04:00
Douglas Katzman bad56f62b6 Reimplement low-level logging
Store an enum, not a printf format string, in the event buffer
2026-04-30 03:05:42 -04:00
Douglas Katzman c2df85fe12 Delete useless test
This test was trying to assert that no slow TYPEP call existed. Since positive
assertions are generally better than negative ones, it instead asserted that
exactly one LAYOUT existed, which would be expected for %INSTANCE-TYPEP.
And it used to be meaningful because:
* MUTEX stored its owner as a THREAD instance, not a raw word, therefore
* MUTEX and THREAD were mutually referential types.
The compiler could not efficiently deal with a forward-referenced types in
whichever defstruct appeared first in the defining file.  So either it couldn't
optimize TYPEP in (SETF OWNER) or (SETF THREAD-INTERRUPTIONS-LOCK) depending
on which defstruct appeared first.  That defect was eventually rectified.

However, now the test is just bad, as neither of the above points hold.
2026-04-29 22:27:04 -04:00
Stas Boukarev 900e2f1e6e Reverse an accidental change. 2026-04-30 00:11:28 +03:00
Stas Boukarev 3ae56c4c92 sb-grovel: don't add trailing zero-length padding 2026-04-29 23:10:04 +03:00
Stas Boukarev c3fc019edf sb-eval: don't accept (lambda non-list) 2026-04-29 23:10:04 +03:00
Stas Boukarev fc9c2223bc sb-eval: check eval-when syntax 2026-04-29 23:10:04 +03:00
Christophe Rhodes 1a0e4afd51 2.6.4: will be tagged as "sbcl-2.6.4" 2026-04-29 20:26:57 +01:00
Stas Boukarev 7cabf02c65 Spell-check NEWS
[skip ci]
2026-04-28 23:52:26 +03:00
Christophe Rhodes 3fbd492e48 fixes to NEWS 2026-04-28 20:35:36 +01:00
Stas Boukarev 29216741cf Skip a test 2026-04-28 14:24:44 +03:00
Stas Boukarev 7c5b07f38a Add c_ispeed and c_ospeed fields to sb-posix:termios
Should fix a problem with OpenBSD.

Based on a patch by Robert Palm.

Fixes lp#2150499
2026-04-28 14:01:14 +03:00
Stas Boukarev 25215818e2 Disable a test 2026-04-28 04:12:05 +03:00
Douglas Katzman 114538b378 Fix input-manifest 2026-04-27 20:40:10 -04:00
Jesse Bouwman 6a39892471 x86-64, struct-by-value: coordinate arglist transforms 2026-04-27 14:05:06 -07:00
Christophe Rhodes 6fff197f35 First draft of NEWS for sbcl-2.6.4 2026-04-27 18:30:32 +01:00
Stas Boukarev 8ecb4fb731 Revert "Persist the :ucrt feature, if present, into the final image"
Until it's known if users need that.

This reverts commit 4dde13a7c1.
2026-04-27 14:46:42 +03:00
Jesse Bouwman 314b572626 x86-64, struct-by-value: correct ABI classification for nested structs 2026-04-26 17:44:30 -07:00
Jesse Bouwman f484412bc4 x86-64, struct-by-value: prevent overwrites when copying during callbacks 2026-04-26 11:11:18 -07:00
Stas Boukarev f735fd577c x86-64, struct callbacks: leave registers if a struct doesn't fit
Which was copied from arm64.
2026-04-26 19:16:19 +03:00
Jesse Bouwman a190d9710a struct-by-value: don't overwrite when copying values from registers to memory 2026-04-26 12:18:26 +03:00
Jesse Bouwman c4c736c568 tests: failing overwrite cases 2026-04-26 12:18:26 +03:00
Douglas Katzman 71cca79006 Fix strange comment
which made sense only if you knew it so well as to not need the comment.
2026-04-26 01:18:17 -04:00
Douglas Katzman b0cdf28901 Improve RELEASE-MUTEX docstring
"set it to NIL" may have made some sense over 20 years ago when a mutex
was essentially just a container of one value, namely the owning thread.
2026-04-26 00:22:39 -04:00
Stas Boukarev 5c866b5159 x86-64, struct-by-value: leave registers if a struct doesn't fit
Something else might go into that register.
2026-04-25 21:06:13 +03:00
Jesse Bouwman e3d6e48da2 x86-64, struct-by-value: don't read past input struct 2026-04-25 18:33:51 +03:00
Jesse Bouwman fa6a16b5ec tests: struct-by-value parameter overread 2026-04-25 18:27:16 +03:00
Stas Boukarev 0132c442dd Resolve a loop in constraints
Process newly changed blocks always in the same order.

Reported by _death
2026-04-25 02:51:06 +03:00
Christophe Rhodes 4dde13a7c1 Persist the :ucrt feature, if present, into the final image
It's probably not useful for users, but it is necessary for making the
right choice while building our own contribs.  Acting on a report by
Masatoshi SANO.
2026-04-24 12:12:45 +01:00
Stas Boukarev 8a98e7b59d x86-64, struct-by-value: fix record-arg-tn for win32
Correctly write to stack tns.
2026-04-24 00:20:22 +03:00
Stas Boukarev 627064c1dc x86-64, struct-by-value: correctly pass small structs on the stack 2026-04-23 20:16:38 +03:00
Stas Boukarev 467666387e arm64: don't do (ldrsw (32-bit-reg x) ..)
It's supposed to sign extend into a 64-bit register.
The assembler doesn't care, but there's no reason to create
unnecessary tns.
2026-04-23 20:16:38 +03:00
Stas Boukarev f1109de3da arm64, callbacks: return float results in the right register 2026-04-23 13:28:19 +03:00
Stas Boukarev 3d222e98b2 arm64, struct-by-value: don't read past the input struct 2026-04-23 12:24:30 +03:00
Stas Boukarev cd3e8721e3 arm64, struct-by-value: don't consume gprs when running out of fprs 2026-04-23 11:27:20 +03:00
Stas Boukarev 0cb8e863d1 arm64, struct-by-value: don't split stack/registers in callbacks 2026-04-23 11:18:59 +03:00
Stas Boukarev 2c30eafc7e x86-64, struct-by-value: correctly pass small structs on the stack 2026-04-23 10:50:34 +03:00
Stas Boukarev 0e7a0d7981 arm64, struct-by-value: correctly pass small structs on the stack 2026-04-23 10:40:05 +03:00
Stas Boukarev 29a23fdce1 arm64, struct-by-value: look at the stack when running out of GPRs 2026-04-23 08:09:39 +03:00
Stas Boukarev 4b3abf2f8c arm64: fix alien-struct-by-value copying
Don't stop too early.
2026-04-23 07:48:01 +03:00
Stas Boukarev da85ccc9b4 Fix logtest on ppc64
Where n-fixnum-tag-bits is different from ppc32 (and from everything else)
2026-04-23 00:08:42 +03:00
Douglas Katzman b5150429f7 Delete immobile space sigsegv handler 2026-04-22 12:29:11 -04:00
Stas Boukarev 315d1ee568 x86-64: use xorps for conjugate/complex-single-float 2026-04-22 04:21:32 +03:00
Stas Boukarev 77337ebd4a Typos in arm64/float.lisp 2026-04-21 03:11:43 +03:00
Stas Boukarev 82f008f592 arm64: use the right register in ash-inverted 2026-04-20 23:57:16 +03:00
Stas Boukarev 97ecfac9da arm64: fix a potential issue with fast-ash-c/signed=>signed
Which can't be triggered due to VOP selection.
2026-04-20 23:28:47 +03:00
Stas Boukarev d81da0bd3f x86-64: fix mask-signed-field-integer for 64 and any-reg result 2026-04-20 22:57:30 +03:00
Stas Boukarev 79752fb42a Address a FIXME in emit-inline-add-sub 2026-04-20 20:44:18 +03:00
Stas Boukarev 8595450051 Typos 2026-04-20 20:16:27 +03:00
Stas Boukarev 0079393bff let-lvar-dest: ignore NIL lvars
Fixes lp#2148799
2026-04-20 16:09:23 +03:00
Stas Boukarev 3eb58efbbe Transform floor/ceiling to truncate when used as a divisibility test 2026-04-20 04:26:35 +03:00
Douglas Katzman 914726b494 Implement choice of using fastrem in IR1 transform 2026-04-19 18:05:03 -04:00
Stas Boukarev cfdbd482aa x86-64/truncate-c: correctly determine if the quotient is unused
Fixes lp#2148782
2026-04-19 20:06:46 +03:00
Douglas Katzman 566883ab44 Defensively code in type-width-in-bits
The receiving logic already potentially expected NIL
2026-04-19 11:59:56 -04:00
Stas Boukarev c9317d951a check-type: don't include ctypes in the expansion
Which have a hard time when included in inline functions.

Fixes lp#2148777
2026-04-19 17:26:24 +03:00
Douglas Katzman ae89d7be84 x86-64: TRUNCATE using the Lemire, Kaser, Kurz transform
2 MULs outperforms one DIV or IDIV by at least 2x based on my
testing and also Agner Fog's instruction latency tables
2026-04-18 22:17:50 -04:00
Douglas Katzman c41011cb52 Don't forget NIL 2026-04-18 22:00:21 -04:00
Douglas Katzman 5c06950e50 Show raw constants of :DWORD or :QWORD size
For instructions like MUL that can't take an immediate, it is helpful
with "MUL DWORD [RIP-n]" to not have to guess what the operand is.
2026-04-18 21:44:54 -04:00
Stas Boukarev 828810aa33 arm64: fix undefined restarts for call-symbol 2026-04-18 22:02:27 +03:00
Stas Boukarev ca4a747664 Warn about bad subseq ranges after transforming (concatenate .. (subseq ..)) 2026-04-17 23:52:08 +03:00
Douglas Katzman a29743a9a4 Accept immediate sc in symbol-global-value 2026-04-16 14:17:39 -04:00
Stas Boukarev 42a948a8d8 Remove a redundant check from unparse-physical-enough
And add a type declaration.
2026-04-16 03:45:18 +03:00
Stas Boukarev 61143f7eeb Don't lose :character-set when changing pathname case 2026-04-16 03:30:10 +03:00
Stas Boukarev e071985c6e (setf readtable-base-char-preference): assert-not-standard-readtable 2026-04-16 03:02:20 +03:00
Douglas Katzman e1f589db87 Undo a couple lines of prior change
Rev 976cf627 removed the :elide-if which I thought was reasonable, but nope.
2026-04-15 18:08:14 -04:00
Douglas Katzman 976cf62766 Permute FDEFN slots for #+linkage-space
Function-related accessors for symbols and fdefns become one and the same.
2026-04-15 16:48:46 -04:00
Stas Boukarev 2419acbc36 alloc-buffer: check the type of size once 2026-04-15 23:46:59 +03:00
Douglas Katzman dd3bf6030c Transform delete-if-not
Otherwise (delete (complement #'foo) ...) might actually get worse,
because it's no longer open-coded after the IF-NOT-COMPLEMENTER changes
the call to (delete-if-not #'foo)
2026-04-15 20:26:36 +00:00
Stas Boukarev b52e4b75c9 defstruct: disallow (:initial-offset nil) 2026-04-15 22:36:27 +03:00
Douglas Katzman f87df9b1ab Remove unnecessary WHEN and LET 2026-04-15 15:10:17 -04:00
Stas Boukarev 6133cb1677 Better predicates for named list structures 2026-04-15 21:43:31 +03:00
Stas Boukarev e18e2ccd71 Fix an error message from DEFSTRUCT 2026-04-15 21:21:28 +03:00
Stas Boukarev db9ae74c67 unix-fast-select: allow select on FD_SETSIZE - 1 2026-04-15 17:51:54 +03:00
Stas Boukarev b2dc86b47a Check that fd-set/fd-clr don't overflow fd-setsize
Or they will write beyond the stack allocated struct.
2026-04-15 17:43:48 +03:00
Douglas Katzman a80d44a4bc Make fun-name-hashset more hashy 2026-04-14 23:28:58 +00:00
Stas Boukarev df702c1627 constant-fold-call: call lvar-value with ignore-types=t 2026-04-15 00:33:26 +03:00
Stas Boukarev 4c13a73b6a sb-vm:new-arena: move the docstring to the right place
Not after ASSERTS. But also transfer the asserts in to the FTYPE.
2026-04-15 00:08:02 +03:00
Douglas Katzman db01e571c0 Delete alien-linkage-value macro 2026-04-14 15:07:02 -04:00
Douglas Katzman 473201d8fd Mention foreign-symbol-address less
It has the same number of uses, but because the function name is wrong,
I don't like seeing it all over the place.
2026-04-14 14:48:55 -04:00
Douglas Katzman 03acc09c68 Use a global list to hold disassembler instructions 2026-04-14 11:01:44 -04:00
Douglas Katzman b89611cdd6 x86-64: Rearrange the alien linkage table
Instructions are together, and data are together, in batches like so:
; 190:       FF257AFFFFFF     JMP [RIP-134]                   ; &memmove
; 196:       6690             NOP
; 198:       FF257AFFFFFF     JMP [RIP-134]                   ; &memcpy
; 19E:       6690             NOP
; 1A0:       FF257AFFFFFF     JMP [RIP-134]                   ; &os_get_errno
; 1A6:       6690             NOP
; 1A8:       FF257AFFFFFF     JMP [RIP-134]                   ; &os_set_errno
; 1AE:       6690             NOP
2026-04-13 21:30:22 -04:00
Douglas Katzman f4d064cdd0 Do some more renaming
alien-linkage-table-entry-address becomes alien-linkage-index-to-addr.
Add an optional DATAP argument which is needed to do one or both suggestions at
FOREIGN-SYMBOL-SAP in src/compiler/x86-64/c-call - the address returned by
-INDEX-TO-ADDR needs to be aware of how the indexed entry will be used.
2026-04-13 18:52:49 -04:00
Douglas Katzman 2993d7965c Clean up sap-foreign-symbol
Remove maybe-inline, remove old comments
2026-04-13 17:57:46 -04:00
Stas Boukarev f7767f081e pathnames: correctly escape dots in the middle of a pattern 2026-04-13 19:26:15 +03:00
Stas Boukarev b6e0563c8a pathnames: fix dot escaping with multiple preceding escapes 2026-04-13 19:04:32 +03:00
Stas Boukarev 4720de5763 pathnames: mind escape-char when processing []
Don't use \\] as the matching closing bracket.
2026-04-13 17:10:31 +03:00
Stas Boukarev f49582480c run-program: escape empty strings on windows 2026-04-13 06:17:20 +03:00
Stas Boukarev 4e76fe5eb0 Remove closed processes from *active-processes* 2026-04-13 06:02:18 +03:00
Stas Boukarev 656925b3b1 sb-ext:process-kill: remove the option to use :pty-process-group
It has been using kill() instead of killpg() since 2009.
find-current-foreground-process, tasked with finding the foreground
pid, has been returning just (process-pid proc) since 1996.
Actually returning the result of tcgetpgrp() just gives 0.
Which would kill the calling process.
Clearly:
a) nobody has ever used this option
b) nobody knows what it's supposed to do (or :pty t)
2026-04-13 05:48:37 +03:00
Douglas Katzman d482d67519 Remove cold-fixup function
It ceased being distinct from fixup-code-object ever since genesis was
able to emulate (SETF SAP-REF) and some other operations in the host lisp.
2026-04-12 19:04:26 -04:00
Stas Boukarev 91ab23b309 Don't endlessly bounce between ash and logand transforms
Fixes lp#2148056
2026-04-12 01:03:59 +03:00
Stas Boukarev b64590858b Return early from set-exclusive-or if one of the arguments is NIL 2026-04-11 01:04:12 +03:00
Stas Boukarev 561ce4284b char/=: check all arguments for CHARACTER before returning NIL 2026-04-11 01:03:51 +03:00
Stas Boukarev 0ac2618579 Out of line some/every: check if the function is defined early
Before returning on NIL, just like the compiled versions.
2026-04-11 00:39:27 +03:00
Stas Boukarev 1688062998 More type checks for the stream functions 2026-04-11 00:13:02 +03:00
Stas Boukarev 04d757a998 Return one value from (append/nconc (values 1 2)) 2026-04-10 23:15:38 +03:00
Stas Boukarev 41a13309df /=: check all arguments for NUMBER before returning NIL 2026-04-10 23:12:50 +03:00
Stas Boukarev bf6f4d7ae0 find-class: check that the name is a symbol even when errorp is nil 2026-04-10 23:04:18 +03:00
Stas Boukarev 1d77ce646e Return one value from (list* (values 1 2))
Hiding only for 18 years.
2026-04-10 22:01:27 +03:00
Stas Boukarev 57c047b5d5 Better ftype for compiler-macro-function 2026-04-10 20:10:06 +03:00
Stas Boukarev 84d567275c Actually fix check-coerce 2026-04-10 19:56:10 +03:00
Stas Boukarev 3fc33eb8c0 Ensure the types are checked in the set functions
Instead of returning early if something is NIL.
2026-04-10 19:52:05 +03:00
Stas Boukarev 87e2770b92 Check for integers in array-in-bounds-p 2026-04-10 19:36:23 +03:00
Stas Boukarev 563243a3ca Check types in broadcast-stream output routines 2026-04-10 19:30:28 +03:00
Stas Boukarev f7ac72d9f8 Check for characters in unread-char 2026-04-10 19:14:02 +03:00
Stas Boukarev 8e5be95ed2 Check types for standalone byte, byte-size, byte-position
Instead of just transforming them to cons, car, cdr.
2026-04-10 19:06:04 +03:00
Stas Boukarev 2afb32633b Fix win32 build 2026-04-10 16:55:48 +03:00
Seokjun Lee 15976f4832 Make main() a weak symbol for linkable runtime 2026-04-10 07:28:17 -04:00
Douglas Katzman 8e6ef6fb95 x86-64: Rearrange CAS vops for SYMBOL-[GLOBAL-]VALUE
Don't attempt to share logic between SYMBOL-VALUE and SYMBOL-GLOBAL-VALUE
for sb-thread but instead make sb-thread (CAS SYMBOL-GLOBAL-VALUE)
identical to #-sb-thread (CAS SYMBOL-VALUE) and then separately implement
(CAS SYMBOL-VALUE) for threads. Also correct the deficiency of not
accepting immediate SC for the symbol on #-sb-thread.
2026-04-09 22:19:27 -04:00
Stas Boukarev 002e5c99e4 More compact ROUND for integers 2026-04-10 03:26:40 +03:00
Stas Boukarev b8fa70041c Narrow the type of (truncate n d) based on the remainder
If the remainder is non-zero then the divisor is at least 2, cutting
the quotient range in half.
2026-04-10 03:26:40 +03:00
Douglas Katzman 9190402f70 Tidy up the definition of *FINITE-SBS*
Another thing which pre-dated DEFINE-THREAD-LOCAL
2026-04-09 18:53:36 -04:00
Stas Boukarev 87930f9417 Propagate that after (/= (rem n d) 0) D is (not (integer -1 1)) 2026-04-09 21:37:46 +03:00
Douglas Katzman 5d6cba2766 Avoid certain TLS load traps
Prefill indirection words for main and system thread. Other threads (especially
foreign call-in) have high overhead already, which isn't justification to add
even more overhead.  The primary goal was to see whether it's possible to build
without the sigsegv handler. It's still not, but after the build you can
start up that binary and core without installing the sigsegv handler.
2026-04-09 14:31:09 -04:00
Douglas Katzman 526c5fca64 Remove a hack from src/code/signal
We should not set the (INFO :variable :always-bound symbol) property through
ad-hoc techniques. The code and comments pre-date other approaches such as
DEFINE-THREAD-LOCAL. However, that's actually not enough to get
*UNBLOCK-DEFERRABLES-ON-ENABLING-INTERRUPTS-P* to work, because in addition to
the issue cited at the call to INIT-MAIN-THREAD in src/code/cold-init, there
is a problem that always-thread-local specials initialized from Lisp are set
later than the ones intialized in alloc_thread_struct. So entirely-from-lisp
assignment wasn't enough for *UNBLOCK-DEFERRABLES-ON-ENABLING-INTERRUPTS-P*.
2026-04-09 13:44:44 -04:00
Douglas Katzman aab1a9d230 Cons nothing for alien linkage entries that exist 2026-04-09 11:13:37 -04:00
Seokjun Lee d17fc05a83 Base-stringize alien linkage table names
ensure-alien-linkage-index did not coerce names to simple-base-string,
so define-alien-routine could insert simple-character-string names into
the linkage table. This caused os_link_runtime() to crash with "GC
invariant lost" and generate_elfcore_obj() to produce truncated ELF
symbol names when saving :executable :elf-object cores.
2026-04-09 11:01:05 -04:00
Stas Boukarev 186fa8ba9f Fix ash-modfx constant folding 2026-04-09 04:15:09 +03:00
Stas Boukarev df956be426 Don't return the data vector from (replace complex-vector list) 2026-04-09 02:57:22 +03:00
Stas Boukarev 327486b47b Fix a test
[skip ci]
2026-04-08 22:50:24 +03:00
Stas Boukarev 621a78e63f Warn about integer division by zero 2026-04-08 22:36:23 +03:00
Stas Boukarev 52250de6b8 Handle division by zero when deriving (/ integer integer) 2026-04-08 21:56:39 +03:00
Stas Boukarev 9c4550e399 Exclude zeros when deriving truncate types 2026-04-08 21:42:46 +03:00
Stas Boukarev c24646fff5 Better types for (floor/ceiling (integer -5 5) integer) 2026-04-08 21:22:07 +03:00
Stas Boukarev c1f893b2df Lower more things to from EQUALP to EQUAL
Characters and strings without case
2026-04-08 20:45:07 +03:00
Stas Boukarev ce88d7209f Don't put bounds into the complex type for (complex float)
Not only complex parts are now upgraded to exclude bounds, the derived
bound was not correct for imagpart.
2026-04-08 19:22:32 +03:00
Gabor Melis 56b8cb391b Make DEFSETF warn a bit more like DEFMACRO
When (SETF FOO) was assumed to be a function, (DEFSETF FOO ...) used
to signal a full warning, and repeated (DEFSETF FOO ...) signalled the
same warning again.

To bring the behavior closer to that of DEFMACRO, DEFSETF now only
signals a STYLE-WARNING and only the first time around.
2026-04-08 12:00:59 +02:00
Gabor Melis bfd25952d5 Improve SB-INTROSPECT:FIND-DEFINITION-SOURCES-BY-NAME error handling
- Accept string designators names with :PACKAGE.

- Do not signal an error with :COMPILER-MACRO, :FUNCTION,
  :GENERIC-FUNCTION and :METHOD if NAME is not a valid function name.

- Document that SB-INTROSPECT:FIND-DEFINITION-SOURCES-BY-NAME returns
  NIL on invalid NAMEs.

- Document that definition types are disjoint.

- Remove stale TODO.
2026-04-08 12:00:59 +02:00
Stas Boukarev 5249a30f98 x86-64: fix dynbind for -sb-thread 2026-04-08 07:32:18 +03:00
Stas Boukarev 594fbed44b Fix coerce compile-time checking 2026-04-08 06:56:47 +03:00
Douglas Katzman e972a1a2b8 Halve the size of immobile cards 2026-04-07 23:19:54 -04:00
Douglas Katzman 1da3c086e7 Remove ENABLE_PAGE_PROTECTION choice from immobile-space 2026-04-07 23:01:23 -04:00
Stas Boukarev 36c8443d71 Fix EQUALP to EQUAL lowering for constant dotted lists 2026-04-08 05:08:18 +03:00
Stas Boukarev 01ab357945 Better type derivation (truncate x integer-union-with-zero) 2026-04-08 04:53:59 +03:00
Stas Boukarev 1f72eef99e Tidy up some type specifiers 2026-04-08 04:29:13 +03:00
Douglas Katzman 6094278bbe Optimize (BOUNDP 'known-symbol) if #+tls-load-indirect 2026-04-07 19:57:09 -04:00
Douglas Katzman 2d87e918aa Remove another misuse of (DECLARE SPECIAL) for #+tls-load-indirect
Apart from it generally being considered suboptimal style to need local
special declarations, is it actually harmful for DEFINE-THREAD-LOCAL.
SPECIAL says that it has an indirection word, while thread-local says
it _never_ has. I didn't figure out why this wasn't crashing. Probably was,
and some test reported success because after all it's a heap exhaustion.
2026-04-07 19:43:59 -04:00
Douglas Katzman 01126243ca Put back DSD-READER but only for structure-object
Needed in https://github.com/qitab/cl-protobufs/blob/master/optimizer.lisp
2026-04-07 11:26:57 -04:00
Douglas Katzman 141be5be0d Remove stray line noticed by reviewer 2026-04-07 11:12:12 -04:00
Douglas Katzman 5f3bf0b9e4 Use soft card marking on all fixedobj pages 2026-04-07 10:39:16 -04:00
Douglas Katzman d62ed2476f Fix mark-region with permgen
The old way avoided the barrier for non-pointer stores, and so could this
by testing is-lisp-pointer first, but there's really no need.
2026-04-07 10:16:50 -04:00
Douglas Katzman 7376db7c79 Move some things
- put EMIT-SYMBOL-WRITE-BARRIER with EMIT-GENGC-BARRIER
- decrease scope of ACCESS-WIRED-TLS-VAL macro
2026-04-07 05:34:22 -04:00
Douglas Katzman 8f009e1579 Correct some obsolete bit-masking steps
They weren't wrong, but just overly complicated in light of earlier changes
2026-04-07 02:02:12 -04:00
Stas Boukarev d3bd86dd8a Don't create an extra cons in (concatenate 'list ...) 2026-04-07 04:14:29 +03:00
Stas Boukarev 2ef06b7346 Faster (concatenate 'vector ..) for list arguments 2026-04-07 03:54:41 +03:00
Stas Boukarev 5122895aee ir1-optimize-combination: stop if the node is deleted in derive-type
Fixes lp#2147385
2026-04-07 03:03:33 +03:00
Stas Boukarev e1df5f074f check-array-dimensions: be ready for a mv-combination
Fixes lp#2147384
2026-04-07 02:34:15 +03:00
Stas Boukarev 345c44cd62 map-refs: protect against unused results
Fixes lp#2147383
2026-04-07 02:32:38 +03:00
Stas Boukarev 8d178ceef1 Transform (replace simple-vector list) with :start1/:end1 2026-04-07 02:30:37 +03:00
Douglas Katzman 271dd00e2d Change HW to SW card marking on immobile layout pages 2026-04-06 17:37:33 -04:00
Stas Boukarev 9814767a46 Fix ppc64 build 2026-04-06 15:47:49 +03:00
Douglas Katzman c247cda09e Rename DSD-READER to DSD-PRIMITIVES
it returns 2 values. And take the DD rather than a boolean for the 2nd arg.
2026-04-06 01:28:59 -04:00
Douglas Katzman cce821a3c7 Mostly combine all definitions of arch_get_bad_address into one
Only PPC seems to do anything other than read si_addr. I'm not sure it's
correct, but I'm leaving it.
2026-04-05 22:53:33 -04:00
Douglas Katzman f368a022c0 Implement a SIGSEGV mitigation strategy for tls-load-indirect
A certain local test was _incorrectly_ reporting use-after-free under ASan
where the alleged bug was in the TLS trap handler, and it was undebuggable
because the sigcontext itself was the supposed problem.
I gave up, and implemented something hinted at with the initial commit of
the :tls-load-indirect feature, which is that the indirection cells can
be more-or-less prepopulated at thread startup.
My ASan test failure rate went from 10% down to 0 failures in 10,000 runs.
2026-04-05 22:42:20 -04:00
Douglas Katzman 737f780966 Remove dump-segment, fold it into dump-code-object 2026-04-05 00:48:58 -04:00
Douglas Katzman 78ef4a5081 Decode utf8 from C
This improves the benchmark result for long strings and does not
degrade it on short strings.

And fix the benchmark's randomizer. The hacky attempt to avoid the
surrogate pair range inadvertently prevented random strings from
containing any code point requiring exactly 2 encoding bytes.
2026-04-04 23:43:40 -04:00
Douglas Katzman b3478e055b Expose a much simplified utf8-to-string decoder
It comes in two-and-a-half variations: accepting a SAP or ub8 vector,
and if a SAP then either counted or null-terminated. In the case where
it returns base-string as determined by a pre-scan of the input, it runs
nearly twice as fast as octets-to-string
2026-04-04 21:22:33 -04:00
Douglas Katzman 0758784246 Rename call-static-fun to call-lisp-fun
Calling through the linkage table has nothing to do with static space,
static symbols, or any other concept that "static fun" might imply.
2026-04-03 21:13:31 -04:00
Douglas Katzman 17e8361de4 Avoid calling cache-statistics function 2026-04-03 16:00:26 -04:00
Douglas Katzman a708727118 Enable sb-profile test for mark-region
Another one which was skipped with no comment about why.
Style changes: defvar -> defglobal, and do-symbols -> with-package-iterator
2026-04-03 15:47:22 -04:00
Douglas Katzman fb23a27107 Enable a test file for mark-region which passes now
I don't know remember what the problem was. The commit which
added the skip-file was unenlightening.
2026-04-03 15:46:39 -04:00
Douglas Katzman 5ae0e669e6 Move print-object on sb-pcl::cache near its defstruct
Also dont't call cache-statistics which is otherwise an unsed function.
And remove map-all-caches.
2026-04-03 15:27:37 -04:00
Stas Boukarev 88f6037a4f Unroll more things for (equal x '(y)) 2026-04-03 21:30:25 +03:00
Stas Boukarev 3d37c2aa97 find-or-create-equality-constraint: use vector-length as a key
Now that they are EQ.
2026-04-02 15:22:58 +03:00
Stas Boukarev 1e165b38e3 Maybe fix join-equality-constraints 2026-04-02 03:43:54 +03:00
Stas Boukarev b0544e783e x86-64: smaller (funcall (or null function))
Emit an error break directly
2026-04-02 00:28:35 +03:00
Stas Boukarev 947d6c437e Smaller type testing of function for call-symbol
Which %test-lowtag knows how to do
2026-04-02 00:16:25 +03:00
Stas Boukarev 0fb701dae0 Don't mix in NULL for proclaimed &key types
With non-constant defaults.

Fixes lp#2147050
2026-04-01 22:22:47 +03:00
Stas Boukarev defa753575 Better groveling of struct timeval on 32-bit linux with 64-bit time
Where usec is not suseconds_t
2026-04-01 18:10:16 +03:00
Douglas Katzman a5cdf99b77 Make c-callable-fdefns non-static
C just needs to see the functions somehow and Lisp doesn't care how.
This makes each #define for {x}_fname_index come out the nearly the same
for +/-linkage-space (they're off by 1) while also clearly delineating
which fdefns are static because Lisp needs them to be so.
2026-03-31 22:14:52 -04:00
Douglas Katzman cca706d884 Remove subcritical FIXMEs at pad-data-block
A macro is fine, so is the name of it
2026-03-31 19:42:08 -04:00
Douglas Katzman 7b720709bc Compute STATIC-FDEFN-OFFSET more concisely
So there's one fewer place to deal with the length of NIL in words,
as it's already accounted for in LFLIST-TAIL-VALUE-NIL-OFFSET
2026-03-31 19:27:48 -04:00
Douglas Katzman a2ce05bc30 x86-64: always enable tls-load-indirect
Tested on win32 but neither Haiku nor SunOS
2026-03-31 09:19:27 -04:00
Douglas Katzman 857c1ad90f Remove unused lines of code 2026-03-31 08:17:08 -04:00
Douglas Katzman ecc2a21349 x86-64: Implement tls-load-indirect for mark-region-gc 2026-03-30 20:19:02 -04:00
Stas Boukarev accf61b86a join-equality-constraints: better growth termination 2026-03-31 02:48:38 +03:00
Stas Boukarev 5d43f37739 Typo 2026-03-30 15:34:45 +03:00
Stas Boukarev 526a0b98fb Don't redefine a macro 2026-03-30 14:59:11 +03:00
Douglas Katzman 9f392ad9c4 Try a different implementation of reader/writer lock 2026-03-30 04:22:46 -04:00
Douglas Katzman 4961df1c8b Get relocation.test.sh working for x86-64-darwin
In theory it would also pass for arm64, however the hand-picked addresses
that the test tries to relocate into will have to change.
2026-03-30 04:04:36 -04:00
Douglas Katzman ebc99ec9e3 Show number of stored fixups if *show-new-code* 2026-03-30 03:44:00 -04:00
Douglas Katzman 11d264cd93 Improve local var name 2026-03-30 02:51:04 -04:00
Douglas Katzman 1d8a129ea4 Fix comment 2026-03-30 02:46:07 -04:00
Douglas Katzman fd6318357e Clean up apply_absolute_fixups
Delete unreachable case
2026-03-30 02:34:34 -04:00
Douglas Katzman bca795f090 Remove hash slot from PATTERN
The theory was that (SXHASH pathname) should do a bounded amount of
calculation, but it happens once at construction time, so who cares?

Also change type of pattern piece from string to simple-string.
2026-03-30 02:24:46 -04:00
Douglas Katzman 15fcab6795 Change :accessor to :reader in a define-condition 2026-03-30 01:10:33 -04:00
Douglas Katzman c3abe9ca8a Factor out a subtraction that appears too many places 2026-03-30 00:26:51 -04:00
Douglas Katzman 35332792be build-all-cores 2026-03-29 23:59:15 -04:00
Stas Boukarev f93c987d58 join-equality-constraints: set the amount to 0 instead of removing
So that things can converge
2026-03-30 02:47:49 +03:00
Stas Boukarev 6d02707ade Remove redundant float coercions 2026-03-30 01:21:15 +03:00
Stas Boukarev 69ee1590f5 Don't add equality constraints with offsets for types
Types will be adjusted on their own.
2026-03-30 01:19:34 +03:00
Stas Boukarev a8b003f315 (float (/ int1 int2)) => (/ (float int1) (float int2))
If the integers are exact floats. Avoids creating ratios.
2026-03-29 21:00:50 +03:00
Stas Boukarev 0a9028c52d Add a transform for (sqrt rational) 2026-03-29 20:17:12 +03:00
Stas Boukarev 7f3afff18f find-or-create-equality-constraint: more normalization
And do not create duplicates for (eq var1 var2)
2026-03-29 20:17:12 +03:00
Stas Boukarev 922187f418 Don't add equality constraints for types without bounds
Which do not contain any information.
2026-03-29 20:17:12 +03:00
Stas Boukarev 6c7f03c1b2 Simplify join-type-constraints
Trade a little a bit of consing for more clarity.
2026-03-29 20:17:12 +03:00
Stas Boukarev c27660c035 inherit-equality-p: don't treat sets specially
Now that join-equality-constraints detects growing amounts.
2026-03-29 20:17:12 +03:00
Stas Boukarev fe16f669cd Avoid looping in join-equality-constraints
Detect changing constraint amounts and give up.

Fixes lp#2144911
2026-03-29 20:17:12 +03:00
Christophe Rhodes 45d6d63a4b 2.6.3: will be tagged as "sbcl-2.6.3" 2026-03-29 17:01:54 +01:00
Stas Boukarev 8ed6652bd0 Augment NEWS
The x86 thing was just a fallout of a preceding change.
2026-03-28 15:15:21 +03:00
Christophe Rhodes dad5194802 Draft NEWS for sbcl-2.6.3 2026-03-28 11:34:20 +00:00
Stas Boukarev 4135f4c0fb ppc64be: correctly decide whether to use the fsqrt instruction
If a call to sqrt() is not encountered during cross compilation then
the foreign symbol won't be inserted into *linkage-info*, hampering
early init.
2026-03-27 21:40:49 +03:00
Stas Boukarev cb1ef006d3 Make --lose-on-corruption work for binding stack exhaustion
Saving an interrupt context uses the binding stack.
2026-03-27 18:18:11 +03:00
Stas Boukarev 6911ef8d03 Fix a style-warning on openbsd-arm64
Patch by Masatoshi SANO.
2026-03-27 17:08:05 +03:00
Stas Boukarev 3e39901355 Enable >= float VOPs on riscv, loongarch64 2026-03-27 00:06:07 +03:00
Stas Boukarev 207df49235 Fix float comparisons on riscv, loongarch
Negating the result doesn't work for NaNs.
2026-03-26 04:20:25 +03:00
Stas Boukarev e2dec5cbbe Relax a test 2026-03-25 21:17:03 +03:00
Douglas Katzman c5411bf581 Modernize another error message 2026-03-24 15:37:14 -04:00
Douglas Katzman 4144c8e386 Delete remarks about multiple global nicknames
The less said, the better. Rev 482a5df1df changed the behavior
of this example - purposely I believe - so add a test for that.
2026-03-24 11:12:34 -04:00
Douglas Katzman aa847135d4 Fix wrong type declaration 2026-03-23 23:05:04 -04:00
Douglas Katzman ff39333e8d Coerce to base-string in sb-format::expand-directive if possible
tokenize-control-string calls possibly-base-stringize but combine-directives
messes up if changing ~% to literal newline and gluing strings together.
Technically we could coerce every fixed string given to WRITE-STRING
to base-string if possible, but that's more invasive.
2026-03-23 20:49:27 -04:00
Douglas Katzman 5c4ae07e14 Coerce more docstrings to base-string
As in rev d8591b83e4 but get interpreted functions etc.
2026-03-22 22:50:32 -04:00
Stas Boukarev 0cd062b363 Signal an error for (make-array x :element-type undefined) 2026-03-20 17:15:59 +03:00
Stas Boukarev ef81d38974 Better (typep x '(member 1.0 3.0)) 2026-03-20 00:54:07 +03:00
Douglas Katzman 6b58247019 Fix old-fashioned wording 2026-03-19 13:27:19 -04:00
Douglas Katzman 193f2659f3 Fix fasteval's error message for undefined (FUNCTION f) forms
It was saying that every undefined function is a macro.
2026-03-19 12:45:24 -04:00
Andreas Franke 6cc4129c11 Arena compile: fix ensure-generic-function for arenas
Wraps ensure-generic-function-using-class in without-arena so the GF
object and its slots land on the main heap when called inside an arena.
2026-03-19 11:34:31 -04:00
Christophe Rhodes 52a523e627 Fix and re-enable a test
If (make-array <> :element-type 'undefined) succeeds, check that
upgraded-array-element-type is consistent with what it returns.  If it
errors, check that upgraded-array-element-type errors too.
2026-03-18 22:21:19 +00:00
Stas Boukarev 0e79f05047 Speed up upgraded-array-element-type
Call %vector-widetag-and-n-bits-shift
2026-03-18 18:46:29 +03:00
Stas Boukarev 50d0e2206d make-static-vector: don't call upgraded-array-element-type 2026-03-18 18:32:16 +03:00
Stas Boukarev 0e4ad432dd remove-duplicates: use hash-tables for :test #'= 2026-03-18 18:23:48 +03:00
Stas Boukarev c7aa6982c6 remove-duplicates: use hash-tables for :test #'string= 2026-03-18 14:53:07 +03:00
Douglas Katzman 95b53ec87d Transform (SXHASH instance) 2026-03-17 22:51:19 +00:00
Stas Boukarev a52a9e24f4 Balance parenthesis 2026-03-18 01:36:59 +03:00
Stas Boukarev 1f928b59dc Better (typep x '(and number (not fixnum))) 2026-03-18 01:33:20 +03:00
Douglas Katzman 739ed510c2 Fix possible bug in %instance-sxhash for precise GC
Maybe not actually possible to hit the bug that this allegedly fixes, but the
lesser-used platforms are hard to test given lack of physical hardware,
making this a paranoia-based fix.
2026-03-17 18:21:01 -04:00
Stas Boukarev 905ffb7ea3 list-remove-duplicates: reuse deleted conses 2026-03-17 08:03:31 +03:00
Jan Moringen e868dd316f Fix hash-table code path of LIST-REMOVE-DUPLICATES
When fixing up the table after deleting a cell, don't forget to apply
the KEY to (car next). Fixes commit 698d5da5e.
2026-03-17 02:14:16 +01:00
Douglas Katzman af5ecf6e7a Combine test files 2026-03-16 17:15:59 -04:00
Douglas Katzman e204728ac8 Prevent sign-extending moves related to instance_length
There were some silly CDQE instructions in the AMD64 assembly code from gcc
despite INSTANCE_LENGTH_MASK being 0x3FFF. clang was smarter.
2026-03-16 13:32:20 -04:00
Stas Boukarev 11e09049f9 x86: fix backtraces for THROW 2026-03-16 19:38:03 +03:00
Stas Boukarev 698d5da5ee list-remove-duplicates: use hash-tables even when :key is supplied 2026-03-16 18:27:27 +03:00
Douglas Katzman 6ecacda292 Force copy+resize with mark-region-gc 2026-03-16 10:39:23 -04:00
Douglas Katzman c1e8cd4760 Skip inapplicable test 2026-03-16 09:31:32 -04:00
Douglas Katzman 45dc509ce3 Remove another special case for SXHASH and fix a known bug
Don't use layout-clos-hash for sxhash of layouts.
Happily the comment in %INSTANCE-SXHASH about LAYOUT was wrong-
BITMAP-NWORDS stays the same when a stable hash slot is added by GC.
2026-03-16 01:10:10 -04:00
Douglas Katzman 3fa9948ca8 Verify that %instance-length is unchanged after gc_copy_object_resizing 2026-03-16 00:52:59 -04:00
Douglas Katzman da43b02b40 No longer special-case PATHNAME in the implementation of SXHASH
While the hash calculation is exceptional, being derived from
contents of the pathname, the general case of INSTANCE works.
2026-03-15 23:47:49 -04:00
Douglas Katzman a4b64a85b7 Part 1 of removing a special-case of SXHASH for pathnames
Pathnames are the only subtypes of structure-object for which SXHASH computes a
result by looking into the structure. Now that instances can hold an opaque
stable hash, this has an elegant solution: pre-calculate the "lazy" hash based
on data rather than letting it take the object address.

The tricky piece will be to make the header word correct. This change combines
two slots and adds one, which is needed because the instance length is baked in
to *builtin-classoids*. I'm not sure if that is strictly needed, but I do not
want to propagate an aspect of a defstruct into that file, not to mention that
extending pathnames by two words (by letting them grow) isn't an improvement.
2026-03-15 16:25:02 -04:00
Stas Boukarev 1531ef8704 Add a type for environment-info 2026-03-15 22:48:14 +03:00
Douglas Katzman 28fc991481 Insulate describe-object on pathname from representation change 2026-03-15 15:32:35 -04:00
Douglas Katzman 3f8cb17c1c Remove deftype pathname-component-tokens
Most pathname parts are not exactly that type, making it not very useful,
and in fact there were conflicting descriptions of the slot types,
fndb types, and the (redundant) declarations in make-pathname.
Notably the name and type can not be :UNC, but the type implied they could.

Also delete %pathname-type as a type, as it's type= to %pathname-name.
I considered renaming %pathname-name to %pathname-name-or-type but didn't.
2026-03-15 09:23:53 -04:00
Stas Boukarev 8a78c9f79d Use movaps in make-unwind-block 2026-03-15 05:29:22 +03:00
Stas Boukarev 0fc7becda1 Remove a use of make-random-tn 2026-03-15 03:40:05 +03:00
Stas Boukarev c423487651 Restore some basic stack exhaustion handling for windows arm64
The new approach from windows x86 with SetThreadStackGuarantee doesn't
work because the lisp control stack is separate and grows in the
opposite direction.
2026-03-15 01:23:54 +03:00
Stas Boukarev 155348fa9f Fix arch_scrub_control_stack for x86-64-windows
Where the guard pages have a different size.
2026-03-14 23:14:54 +03:00
Stas Boukarev b2e5e1dea4 Scrub control stacks once per GC
Not for each call to garbage_collect_generation.
2026-03-14 23:14:54 +03:00
Stas Boukarev 18e03da718 Remove * suffixes from sequence functions 2026-03-14 19:40:33 +03:00
Stas Boukarev f1387fc17a Do not cons in (length (remove-duplicates x)) 2026-03-14 19:40:30 +03:00
Stas Boukarev 4ea4d43e9b Fix a test 2026-03-14 15:08:44 +03:00
Stas Boukarev b4cbc77d72 mark-region: don't call mr_preserve_ambiguous on the binding stack
There's nothing ambiguous there. It's still pinned, along with the TLS
area, the control stack, etc.
Probably because it doesn't fixup forwarding pointers?
2026-03-14 15:07:05 +03:00
Charles Zhang 40880ed778 Pull out LCA utility for dominator trees. 2026-03-14 12:17:09 +01:00
Douglas Katzman 958bca1133 Delete function unused after rev d64a1049c4 2026-03-13 21:48:41 -04:00
Stas Boukarev a1a15b266d Fix scrub_thread_control_stack on -c-stack-is-control-stack
Stopping once there's been 4KB of zeros is not a sound idea.
2026-03-14 02:49:02 +03:00
Stas Boukarev 7737c06142 Look through MOVEs in stack-consed-p 2026-03-14 01:32:09 +03:00
Douglas Katzman 186fde9e76 Recognize (OR null numbertype) in numeric SXHASH transform 2026-03-13 17:55:46 -04:00
Douglas Katzman 9b08a3fcc9 Fix reorganize-core for altered struct initfunctions 2026-03-13 15:11:02 -04:00
Douglas Katzman 4f26eb011f Workaround broken C compiler 2026-03-13 14:57:17 -04:00
Stas Boukarev f25f57ab0e win32: don't interrupt I/O twice in wake_thread
The original intention is unclear.
2026-03-13 21:40:27 +03:00
Douglas Katzman cbaf832adc Fake get-symbol-tls-index for #-sb-thread 2026-03-13 14:31:14 -04:00
Douglas Katzman a4ec9fa6e5 Delete tls-related junk from init-main-thread 2026-03-13 14:07:29 -04:00
Stas Boukarev 696dfb3448 Fix (sort (or vector null)) transform
Don't use type intersections.

Fixes lp#2144342
2026-03-13 20:01:26 +03:00
Stas Boukarev 760f1617b4 Use MOVAPS instead of MOVAPD 2026-03-13 09:51:33 +03:00
Stas Boukarev 5b9e370eca Use xorps instead of xorpd for zeroing
One byte shorter.
2026-03-13 09:06:17 +03:00
Stas Boukarev 7e0678ef9d x86-64: symbol-value: don't use a register when not needed 2026-03-13 08:14:30 +03:00
Stas Boukarev fade480226 Fix unbound variable reporting on tls-load-indirect 2026-03-13 08:06:57 +03:00
Stas Boukarev 99184ad0b0 Correctly fix binding immediates with +tls-load-indirect 2026-03-13 07:19:57 +03:00
Stas Boukarev d0868066b5 Fix binding immediates with +tls-load-indirect 2026-03-13 06:57:12 +03:00
Douglas Katzman db187b0e29 x86-64: add :TLS-load-indirect feature
Reduces SYMBOL-VALUE to exactly 2 instructions for most specials that
aren't compile-time known to be either always thread-local or global.
Our application got a .5% reduction in code size and about a 1% speedup.

Refer to the comment above EMIT-SYMEVAL in src/compiler/x86-64/tls for
details. When eager TLS assignment is also enabled, this optimization
pertains to every special var except when the symbol itself is not known.
I'm not sure how to expose the extra benefit that comes from eager TLS
assignment because even if recycling indices were done, there would
certainly be users who DEFVAR thousands of interned symbols without
LET-binding a single one of them. So they need lazy TLS assignment.
2026-03-12 23:37:39 -04:00
Stas Boukarev 18592f8702 Remove extraneous ifdefs for windows-arm64 2026-03-13 04:34:29 +03:00
Douglas Katzman 8d2afaa6c8 Prefer base-string for symbol-name when reading #: syntax
Also sb-posix made simple-character-string names and shouldn't.
2026-03-12 22:48:27 +00:00
Stas Boukarev a2041c2456 x86-64: more compact ASCII checking in the SIMD routines 2026-03-13 00:54:15 +03:00
Stas Boukarev 48cca2dec4 arm64: more compact ASCII checking in the SIMD routines 2026-03-12 23:39:29 +03:00
Douglas Katzman e3ba211388 Consider text-space as GC-managed if #-immobile-space 2026-03-12 20:13:20 +00:00
Stas Boukarev f72384c2c7 Fix function call source location on ppc64 2026-03-12 21:23:17 +03:00
Stas Boukarev 3d6eb5dbbb Fix undefined fun backtraces on riscv, loongarch
They don't properly allocate a frame, just add a red-zone for any
backend in build_fake_control_stack_frames, not just arm64.
2026-03-12 20:55:18 +03:00
Douglas Katzman 8281a2891d Ignore tlsindex_to_symbol_map in final GC during save
No visible effect, it's just wasted work
2026-03-12 10:32:02 -04:00
Douglas Katzman 0cfc0c23ae Use small-mixed pages in genesis if relevant
Otherwise construct_tls_map in coreparse can miss symbols unless they
are all in fixedobj or permgen space.
2026-03-12 09:22:23 -04:00
Gabor Melis a9609e47b3 Fortify SB-INTROSPECT:DEFTYPE-LAMBDA-LIST against :UNKNOWN arglists 2026-03-12 12:52:40 +01:00
Douglas Katzman 223369311a build-all-cores 2026-03-11 22:55:23 -04:00
Douglas Katzman b04308d70b Fold RELEASE-FD-STREAM-BUFFERS into -RESOURCES 2026-03-11 19:29:19 -04:00
Douglas Katzman 8789682e05 Cache ansi-stream after-EF-decoding input buffers 2026-03-11 16:05:09 -04:00
Douglas Katzman fdcc81bac8 Omit so-called filler if none in aprof report 2026-03-11 14:51:37 -04:00
Stas Boukarev 0df24a96cf Don't add finalizers to streams opened via with-open-file
They are going to be closed in unwind-protect.

Suggested by John Mallery.
2026-03-11 19:40:59 +03:00
Stas Boukarev edc7d5716c pcl::emit-reader/writer: correctly return from a :makunbound cache hit
Patch by John Mallery.
2026-03-11 18:55:48 +03:00
Stas Boukarev 78b2039f60 Decline to provide an answer for (type= union unknown-type) 2026-03-11 17:50:25 +03:00
Douglas Katzman 9757445daf Increase min-usable-hole-size
For slightly quicker FIND-IF in DYNAMIC-SPACE-CLAIM-N-WORDS
2026-03-11 10:04:54 -04:00
Stas Boukarev be2c2982bf (type/= (or (and symbol (not null)) cons) t) => T
The union =-method was looking for type-might-contain-other-types-p,
which both intersection and negation types are, yet they won't fold
into a non-union type. Look for opaque-type-p, i.e. unknown,
satisfies, classes.
2026-03-11 14:50:49 +03:00
Jan Moringen 0a8a2be220 tests: Fix find-tests.lisp 2026-03-10 16:24:47 +01:00
Jan Moringen f3bc9d50f5 Restore (use-package "KEYWORD" PACKAGE) signaling an error
Before this change, the wrong variable was checked for the presence of
the KEYWORD package so that no error was signaled.

The test :USE-KEYWORD-NOPE was designed to test this behavior but
didn't catch the regression because the specific test case

  (use-package "KEYWORD" "CL-USER")

/did/ signal an error, but not the right one.  The wrong error was a
NAME-CONFLICT between :IF and CL:IF.
2026-03-10 16:24:45 +01:00
Stas Boukarev e9e43d1287 Transform (stable-sort (or null vector)) 2026-03-10 13:57:30 +03:00
Douglas Katzman 73266b0443 Delete the :COMPACT-SYMBOL feature
it's equivalent to #+64-bit at this point
2026-03-09 22:14:03 -04:00
Douglas Katzman d0439a9a17 Move a define-thread-local, remove a local declare 2026-03-09 19:53:10 -04:00
Stas Boukarev 1c40330876 Don't cons a list in (make-array n :element-type `(signed-byte ,x)) 2026-03-10 01:02:47 +03:00
Andrew Berkley 1491c962d0 Faster count on bit vectors for non-simple bit-vectors and start and stop keys 2026-03-09 17:51:05 +03:00
Douglas Katzman 29fbab2ea7 Reorder init-main-thread to assign TLS specials sooner
(though it still occurs surprisingly late in cold-init)
2026-03-09 10:24:34 -04:00
Stas Boukarev 29560538cf Remove reg-code on arm
PC-relative load can address 4KB, 1MB with two instructions.
Put CSP there instead, which was residing in a static symbol.
2026-03-09 14:37:51 +03:00
Stas Boukarev 302a48afba Use CFLAGS instead of EXTRA_CFLAGS for sb-grovel
CFLAGS can be modified to allow cross-compilation, and building the
runtime already respects CFLAGS.
2026-03-09 14:34:18 +03:00
Douglas Katzman c5a0ffc3e8 x86-64: Maintain a mapping of TLS index to symbol 2026-03-08 22:34:35 -04:00
Douglas Katzman fc603f2f6b Mess with some eval-when in def-cpu-feature
Contrary to the comment it seems to dtrt now
2026-03-08 21:46:47 -04:00
Douglas Katzman 1f74e4e97d Improve assoc transform on constant lists
I thought that the case of sequential integers was already handled specially by
the ASSOC transform but aparently not. Consequently +sigfpe-code-error-alist+
demanded a new MPH function when building for Haiku though the range of FPE_*
constants is contiguous.
2026-03-08 20:45:55 -04:00
Douglas Katzman 1e8316ef19 Fix Haiku build (for x86-64 only) 2026-03-08 13:55:55 -04:00
Stas Boukarev 150b6a9130 coerce derive-type: handle negations and other complicated types
Fixes lp#2143671
2026-03-08 19:57:00 +03:00
Stas Boukarev 328765af50 coerce derive-type: SYMBOL includes NIL
Fixes lp#2143670
2026-03-08 19:50:46 +03:00
Stas Boukarev 26594dc007 github actions: increase --dynamic-space-size 2026-03-07 21:45:12 +03:00
Stas Boukarev 9ce4bdb22c Perform clear-ir1-namespace on arm64 too 2026-03-07 21:13:51 +03:00
Douglas Katzman dccc3259fa Defvar -> defglobal or define-thread-local 2026-03-07 10:41:46 -05:00
Stas Boukarev 6a32ac037f Restore building on sunos-x86-64
On the actual Solaris this time.
2026-03-07 14:18:59 +03:00
Stas Boukarev 9bc39b5e14 sb-posix, getpwnam: don't produce an error on ENOENT
Some systems return that.
2026-03-07 13:56:48 +03:00
Stas Boukarev cd235e0b14 Restore building on sunos-x86-64
Or at least on OpenIndiana.

By Andreas Wacknitz.
2026-03-07 13:11:35 +03:00
Douglas Katzman 4c58d9fec4 Fix a gc_gen_report_to_file bug for pmrgc 2026-03-06 21:03:54 -05:00
Stas Boukarev 42e365bd19 coerce derive-type: extended-sequence might be hiding in some types 2026-03-07 00:05:25 +03:00
Stas Boukarev f7dcda06b1 (coerce x (if n 'single-float 'double-float)) => float 2026-03-06 23:08:20 +03:00
Stas Boukarev c1cded70e5 Derive (map `(vector ,p)) => (simple-array * (*)) 2026-03-06 22:53:10 +03:00
Stas Boukarev 87bd0ca1f2 Derive (coerce x `(vector ,p)) => vector 2026-03-06 22:38:12 +03:00
Stas Boukarev fefa8e54ee Declare the type of CHARACTER arguments 2026-03-06 21:41:32 +03:00
Stas Boukarev 74b4fd5219 Derive the type of COERCE based on the input object type 2026-03-06 21:41:32 +03:00
Stas Boukarev d3c3af578a Produce an error for (make-sequence '(and vector (not simple-array))) 2026-03-06 21:41:32 +03:00
Douglas Katzman 57ce36ce66 build-all-cores 2026-03-06 11:11:58 -05:00
Stas Boukarev be7f1e0a58 Don't transform (+ (- n) complex) to (- complex n)
Imaginary zero isn't negated by subtraction.

Fixes lp#2143383
2026-03-06 17:45:24 +03:00
Christophe Rhodes 9092a4268c Fix typo
Reported by qt in a github comment on the change, which is not
displayed in the UI anywhere I can see other than a slightly deeper
line-height.
2026-03-05 09:57:42 +00:00
Douglas Katzman 445375697e Fix gc_assert uses if -DNDEBUG 2026-03-05 00:35:28 -05:00
Stas Boukarev ce53315038 Better encoding of immediates for logand 2026-03-05 02:01:58 +03:00
Stas Boukarev d76e7db3c6 Rearrange the order of VOPs
For fewer redundant transforms.
2026-03-05 00:33:35 +03:00
Stas Boukarev e8860d89af Inline (ash (unsigned-byte 128) -64) 2026-03-04 19:56:56 +03:00
Stas Boukarev 17a4685e13 Reduce ALT_STACK_SIZE on darwin-arm64
Where SIGSTKSZ is 128K and multiplying by 32 gives 4M, which is larger
than the default control stack size.
On linux-x86-64 it's 256K but it's c-stack-is-control-stack over
there.
2026-03-04 09:50:06 +03:00
Stas Boukarev b0a98d71a3 Fix shell syntax 2026-03-04 08:29:57 +03:00
Stas Boukarev 0412da26d1 Unbreak darwin-arm64 2026-03-04 08:27:32 +03:00
Stas Boukarev f5deb79200 Skip inapplicable test 2026-03-04 08:11:31 +03:00
Douglas Katzman 2c8affb085 Zeroize junk at end of heap spaces when saving core
Patch to save.c by Andreas Franke, test case by me
2026-03-03 23:34:21 -05:00
Vasily Postnicov 5f1982b97b Fix erroneous transform for STABLE-SORT 2026-03-03 22:46:11 +03:00
Stas Boukarev c23757ff47 Resolve C warnings on freebsd 2026-03-03 19:33:07 +03:00
Stas Boukarev f113fe83a5 arm64, context-float-register: doesn't work on openbsd
Can't fetch FP registers from sigcontext there.
2026-03-03 19:33:07 +03:00
Douglas Katzman 488deaae70 Ensure native thread join in finalizer-thread-stop 2026-03-03 11:28:11 -05:00
Douglas Katzman ab9bcabd3f Add diagnostic output into prepare_to_save() 2026-03-03 07:03:24 -05:00
Stas Boukarev 4d0dee1796 find-original-source: don't treat (def . x) as a definition
And fail at printing it later.

Fixes lp#2143114
2026-03-03 14:26:39 +03:00
Stas Boukarev 2558856f78 Restore building on openbsd-arm64
Or maybe other architectures too.
2026-03-03 11:55:41 +03:00
Douglas Katzman 4e6c660d52 Decode the two markers in show-tls-map 2026-03-02 22:56:47 -05:00
Douglas Katzman 14a2b90e10 Move vm_thread_name to where standalone ldb could call it
(thread.c is not compiled in to standalone ldb any more)
2026-03-02 22:53:49 -05:00
Stas Boukarev b4a1417381 tests: abstract .so compilation 2026-03-03 05:50:23 +03:00
Stas Boukarev f5914ba427 x86-64: fix int128 FFI
A FIXME was hanging around there only since 2007.

Tests provided by Andreas Franke.
2026-03-03 05:50:23 +03:00
Stas Boukarev aabb04c715 Remove interior-reg
Everything is pinned now.
2026-03-03 05:50:23 +03:00
Stas Boukarev cc8fd61c26 Remove immediate-arg-scn and control-stack-arg-scn
They all have the same values.
2026-03-03 05:50:23 +03:00
Stas Boukarev 54f5e3ead1 make-return-pc-passing-location is always standard now 2026-03-03 05:50:23 +03:00
Douglas Katzman 4edadac8d6 Define *STACK-TOP-HINT* exactly where first needed
No sooner and no later, because the early declaration in globals.lisp
hid the fact that the real definition in debug.lisp did not have the
desired effect of forcing known-thread-local lookup of the symbol
in most functions defined using the DEFINE-ERROR-WRAPPER macro.
2026-03-02 21:41:45 -05:00
Stas Boukarev aef824ed69 Unify more in debug-int 2026-03-03 01:59:37 +03:00
Douglas Katzman bc54f68fd9 Define some PCL specials as always thread-local 2026-03-02 20:46:49 +00:00
Stas Boukarev 1082f536e1 alloc_code_object: accommodate concurrent component_ptr_from_pc
Write the header before releasing the lock.

Fixes lp#2142711 more
2026-03-02 23:01:14 +03:00
Douglas Katzman 19591b8a22 Bundle some internal PCL parameters into a structure 2026-03-02 19:49:43 +00:00
Douglas Katzman e4f764255a Whitespace 2026-03-02 19:39:06 +00:00
Stas Boukarev bc449b5f3b Fix concurrent code object searching on mark-region
compute_allocations runs into a yet unallocated region of a page,
skips two words, and stumbles when the new concurrently allocated
object isn't actually two words long.
compute_allocations doesn't cause fresh lines to become unfresh
when the GC is not running, calling it doesn't help any subsequent
invocations of find_object.
Use linear search when !gc_active_p and the address is in a fresh
region.

Fixes lp#2142711
2026-03-02 22:08:09 +03:00
Douglas Katzman 8a8320b6dc Return a struct from sb-c::generate-code 2026-03-02 09:42:23 -05:00
Douglas Katzman ebd522d1e2 Fix genheaders test if build had --dynamic-space-size= 2026-03-02 09:38:52 -05:00
Stas Boukarev 9288e6c5ee ppc: use emit-block-header 2026-03-02 12:00:35 +03:00
Stas Boukarev f5295351be ppc64: use flags to indicate the number of returned values 2026-03-02 11:36:48 +03:00
Stas Boukarev de660b308a ppc64: correctly disassemble isel 2026-03-02 09:09:41 +03:00
Stas Boukarev 15a552a0b2 Adjust hash-table-equalp
EQUALP is transformed to hash-table-equalp at compile time, defeating
the test.
2026-03-02 08:11:33 +03:00
Douglas Katzman 33b1b4ab1e Fix fencepost bug in debug-info-for-component 2026-03-01 21:38:53 -05:00
Douglas Katzman 4353dd60b6 Fix EQUALP on hash-tables
Relax the 2nd arg type for all layout-equalp-impl functions so that
the function decides how to compare layout of A against B.
An alternate solution would be that all hash-table instances have the
layout of general-hash-table but with potentially the last 4 slots
not physically represented.
2026-03-01 21:26:46 -05:00
Stas Boukarev ba8060eeb0 Remove mentions of LRA and return-pc-widetag 2026-03-02 01:53:08 +03:00
Stas Boukarev 414be3b346 mips: remove LRA 2026-03-02 00:58:57 +03:00
Robert Smith d5336b676a Add ADCX and ADOX instruction definitions 2026-03-01 22:17:13 +03:00
Stas Boukarev b7de739ff6 sparc: remove LRA 2026-03-01 20:49:10 +03:00
Douglas Katzman 54ea7a25b4 Reduce empty hash-table struct size for default rehash params
Now 128 bytes (down from 160 bytes) if #+compact-instance-header
2026-03-01 10:00:03 -05:00
Douglas Katzman 083bf9756d Add remark about a subtle race that should be fixed 2026-03-01 08:29:35 -05:00
Douglas Katzman 7b46ba866f Change some defvars to defglobal 2026-02-28 20:16:45 -05:00
Douglas Katzman e2ac8043a3 Thread-localize load and compile-file pathnames
They can only be LET-bound, and user modification is unspecified.
2026-02-28 19:04:44 -05:00
Stas Boukarev 2deea918e3 Fix cast-externally-checkable-p type erasure
Fixes lp#2142949
2026-03-01 02:50:04 +03:00
Douglas Katzman 3bd172ce85 Thread-localize *current-level-in-print* 2026-02-28 18:48:09 -05:00
Douglas Katzman 132c683d14 Whitespace 2026-02-28 18:47:25 -05:00
Robert Brown 7a693f6d2b Run sbcl without init files in the recipe for target embedcore-sbcl. 2026-02-28 23:28:54 +03:00
Robert Brown 913a2e69b4 Ignore the return value of write() to suppress a compiler warning. 2026-02-28 23:28:43 +03:00
Stas Boukarev a942c53845 arm: remove LRA 2026-02-28 22:51:50 +03:00
Douglas Katzman d928322f48 Fix 32-bit x86
(setf sap-ref-lispobj) doesn't like a fixnum value, whatevs.
2026-02-28 14:48:21 -05:00
Douglas Katzman dde6211989 Define some debug specials as either global or thread-local 2026-02-28 13:45:36 -05:00
Douglas Katzman 787f9b2db2 Abuse forward-declaimed ALWAYS-BOUND in a less hidden way
A var won't be bound until a DEFVAR is seen, so it's strange to assert
anything always-bound until then. cold-init depended critically on the
fiction that *COMPILE-TIME-EVAL* is always bound when it isn't,
because unbound-marker without a BOUNDP check reads as non-NIL.
2026-02-28 13:37:32 -05:00
Douglas Katzman 4b2122a124 Compile init-thread-local-storage in the very last file
allowing DEFINE-THREAD-LOCAL to be used anywhere.
2026-02-27 21:57:38 -05:00
Stas Boukarev 2cfca0fa32 ppc32, ppc64: remove LRA
TODO:
put return-pc-passing-location into the LR special register.
flag-based multiple value returns.
2026-02-28 02:22:29 +03:00
Stas Boukarev b75e1fa8c6 ppc: fix mflr disassembly 2026-02-28 02:13:33 +03:00
853 changed files with 70415 additions and 28242 deletions

View file

@ -29,6 +29,8 @@ jobs:
CC: arm-linux-gnueabihf-gcc
run: ./make.sh --xc-host='sbcl --dynamic-space-size 700MB --lose-on-corruption --disable-ldb --disable-debugger' --arch=arm
- name: build documentation
run: cd ./doc/manual && sh generate-texinfo.sh
- name: test
env:
CC: arm-linux-gnueabihf-gcc

View file

@ -47,6 +47,8 @@ jobs:
name: sbcl-linux-binary-arm64${{ matrix.options }}
path: sbcl-linux-binary-arm64${{ matrix.options }}
- name: build documentation
run: cd ./doc/manual && sh generate-texinfo.sh
- name: test
run: cd tests; ./run-tests.sh --slow
- name: ansi-test

View file

@ -13,7 +13,7 @@ jobs:
arch: [x86, x86-64]
subfeatures: ['']
include:
- { arch: x86-64, subfeatures: sse4, options: --with-sb-thread --with-nonstop-foreign-call }
- { arch: x86-64, subfeatures: sse4, options: --with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return }
- { arch: x86-64, subfeatures: fasteval, options: --with-sb-fasteval --without-sb-eval --with-nonstop-foreign-call }
- { arch: x86-64, options: --with-mark-region-gc --with-nonstop-foreign-call }
@ -50,6 +50,8 @@ jobs:
- name: test-fasteval
if: matrix.subfeatures == 'fasteval'
run: cd tests; ./run-tests.sh --evaluator-mode interpret
- name: build documentation
run: cd ./doc/manual && sh generate-texinfo.sh
- name: test
run: cd tests; ./run-tests.sh --slow
- name: ansi-test

View file

@ -10,7 +10,7 @@ jobs:
strategy:
matrix:
arch: [arm64, x86-64]
options: [--with-sb-thread --with-nonstop-foreign-call, --with-mark-region-gc --with-nonstop-foreign-call]
options: [--with-sb-thread --with-nonstop-foreign-call --with-tls-based-mv-return, --with-mark-region-gc --with-nonstop-foreign-call --with-tls-based-mv-return]
fail-fast: false
steps:
@ -21,7 +21,7 @@ jobs:
env:
SBCL_MAKE_JOBS: -j4
SBCL_MAKE_TARGET_2_OPTIONS: --disable-ldb --disable-debugger
run: ./make.sh ${{ matrix.options }} --with-sb-core-compression --xc-host='sbcl --lose-on-corruption --disable-ldb --disable-debugger'
run: ./make.sh ${{ matrix.options }} --with-sb-core-compression --xc-host='sbcl --lose-on-corruption --disable-ldb --dynamic-space-size 2GB --disable-debugger'
- name: make binary
run: |
name=sbcl-`cat version.lisp-expr | ./run-sbcl.sh --noinform --noprint --eval '(write-line (read))'`-darwin-${{ matrix.arch }}
@ -37,6 +37,8 @@ jobs:
with:
name: sbcl-mac-binary-${{ matrix.arch }}${{ matrix.options }}
path: sbcl-mac-binary-${{ matrix.arch }}${{ matrix.options }}
- name: build documentation
run: cd ./doc/manual && sh generate-texinfo.sh
- name: test
run: cd tests; ./run-tests.sh --slow
- name: ansi-test

View file

@ -58,6 +58,8 @@ jobs:
with:
name: sbcl-windows-installer-${{ matrix.sys }}
path: sbcl-windows-installer
- name: build documentation
run: cd ./doc/manual && sh generate-texinfo.sh
- name: tests
working-directory: tests
run: ./run-tests.sh

View file

@ -49,12 +49,11 @@ jobs:
with:
name: sbcl-windows-installer-${{ matrix.sys }}
path: sbcl-windows-installer
- name: build documentation
run: cd ./doc/manual && sh generate-texinfo.sh
- name: tests
working-directory: tests
run: ./run-tests.sh
- name: ansi-tests
working-directory: tests
run: ./ansi-tests.sh

78
.gitignore vendored
View file

@ -11,42 +11,42 @@
*.diff
*.patch
.gdb_history
output
obj
local-target-features.lisp-expr
customize-target-features.*
customize-backend-subfeatures.*
src/assembly/target
src/compiler/assembly
src/compiler/target
src/runtime/Config
src/runtime/TAGS
src/runtime/genesis
src/runtime/openbsd-sigcontext.h
src/runtime/sbcl
src/runtime/ldb
src/runtime/sbcl.exe
src/runtime/sbcl.mk
src/runtime/shrinkwrap-sbcl*
src/runtime/target-arch-os.h
src/runtime/target-arch.h
src/runtime/target-lispregs.h
src/runtime/target-os.h
src/runtime/embedcore-sbcl
tests/test-status.lisp-expr
tests/test.log
tests/*.so
tests/run-tests-*
tests/last-random-state.lisp-expr
tests/ansi-test/
tools-for-build/avx2*
tools-for-build/determine-endianness
tools-for-build/determine-endianness.exe
tools-for-build/grovel-headers
tools-for-build/grovel-headers.exe
tools-for-build/mmap-rwx
tools-for-build/where-is-mcontext
tools-for-build/perfecthash*
contrib/asdf/asdf-upstream
doc/manual/*.html
version.lisp-expr
/output
/obj
/local-target-features.lisp-expr
/customize-target-features.*
/customize-backend-subfeatures.*
/src/assembly/target
/src/compiler/assembly
/src/compiler/target
/src/runtime/Config
/src/runtime/TAGS
/src/runtime/genesis
/src/runtime/openbsd-sigcontext.h
/src/runtime/sbcl
/src/runtime/ldb
/src/runtime/sbcl.exe
/src/runtime/sbcl.mk
/src/runtime/shrinkwrap-sbcl*
/src/runtime/target-arch-os.h
/src/runtime/target-arch.h
/src/runtime/target-lispregs.h
/src/runtime/target-os.h
/src/runtime/embedcore-sbcl
/tests/test-status.lisp-expr
/tests/test.log
/tests/*.so
/tests/run-tests-*
/tests/last-random-state.lisp-expr
/tests/ansi-test/
/tools-for-build/avx2*
/tools-for-build/determine-endianness
/tools-for-build/determine-endianness.exe
/tools-for-build/grovel-headers
/tools-for-build/grovel-headers.exe
/tools-for-build/mmap-rwx
/tools-for-build/where-is-mcontext
/tools-for-build/perfecthash*
/contrib/asdf/asdf-upstream
/doc/manual/*.html
/version.lisp-expr

View file

@ -20,6 +20,8 @@ David Lichteblau <david@lichteblau.com> <david@knowledgetools.de>
Francois-Rene Rideau <tunes@google.com> <fare@tunes.org>
Gabor Melis <mega@retes.hu> <mega@hotpop.com>
Jim Wise <jimwise@users.sourceforge.net>
Jim Wise <jimwise@users.sourceforge.net> <jimwise>
<jimwise@users.sourceforge.net> <jwise@draga.com>

6
BUGS
View file

@ -14,4 +14,8 @@ Historical note: before Launchpad was adopted this file contained a
list of currently open bugs. If you run into an SBCL bug number in the
range 1-431 inclusive, it refers to that list.
Refer to User Manual for more details.
Refer to the User Manual for more details at
https://www.sbcl.org/manual/#Reporting-Bugs
or SB-MANUAL:@REPORTING-BUGS.

View file

@ -168,7 +168,7 @@ Guy Steele wrote the original character functions
code/char.lisp
They were subsequently rewritten by David Dill, speeded up by Scott
Fahlman, and rewritten without fonts and with a new type system by Rob
MachLachlan.
MacLachlan.
Lee Schumacher made the Spice Lisp version of backquote. The comment
in the CMU CL sources suggests he based it on someone else's code for
@ -695,8 +695,8 @@ Dave McDonald:
Gabor Melis:
He mainly worked on robustness related to signal handling, threads,
timers with small excursions to constraint propagation, weak hash
tables (based on CMUCL code) and optimizing x86/x86-64 calling
convention.
tables (based on CMUCL code), adaptive hash tables, and optimizing
x86/x86-64 calling convention.
Perry E. Metzger:
He ported SBCL to NetBSD with newer signals, building on the

26
DOCUMENTATION Normal file
View file

@ -0,0 +1,26 @@
Files:
- doc/sbcl.1: man page
- doc/manual/sbcl.{info*,pdf,html}: The user manual. See the "INSTALL"
file on how to build them.
A prebuilt manual for the latest release is available for download in
HTML and PDF formats at <https://www.sbcl.org>.
Sections of the manual are defined and exported from the SB-MANUAL
package (available after (REQUIRE :SB-MANUAL)). The top-level section
is SB-MANUAL:@SBCL-MANUAL. You can browse these directly (e.g. with
Slime's M-.) if the SBCL sources are available. Note that all other
formats (including the intermediate Texinfo) are generated from these
sections and the docstrings of individual Lisp definitions (of e.g.
functions, variables).
> An alternative, unofficial (and unsupported by the SBCL project)
> rendering of the manual is available at <https://fixnum.com> in
> HTML, PDF, Markdown and plain text for the latest development
> version. This version is heavily linked both internally and to the
> HyperSpec, and documents e.g. the default values of arguments and
> the initial values of variables. It is generated with MGL-PAX v0.5+
> (<https://fixnum.com/pax-manual.html>), which also supports browsing
> the documentation live.

View file

@ -3,7 +3,7 @@ SBCL Hacking Guide
(This is not a most actively maintained file, but recommended
reading anyways.)
Table of Contests
Table of Contents
* Modifying
* Patch Submissions
@ -49,7 +49,8 @@ We aren't always as well-educated as we'd like to be...
Ready-to-apply patches should be submitted via Launchpad: please add
the tag "review" to the associated bug (create new bug with name if
there isn't one about the issue yet.)
there isn't one about the issue yet). Alternatively, they may be sent
to the sbcl-bugs mailing list.
Patches requiring more widespread discussion and feedback should be
sent to the sbcl-devel mailing list.

20
INSTALL
View file

@ -127,7 +127,7 @@ INSTALLING SBCL
If you don't already have an SBCL binary installed as "sbcl" on your
system, you'll need to tell make.sh what Lisp to use as the
cross-compilation host (cf. make.sh for detailed instructions on
how to cross compile). For example, to use CMUCL (assuming has
how to cross compile). For example, to use CMUCL (assuming it has
been installed under its default name "lisp") as the
cross-compilation host:
@ -145,10 +145,10 @@ INSTALLING SBCL
$ cd ./doc/manual && make
This builds the Info, HTML and PDF documentation from the Texinfo
sources. The manual includes documentation string from the build
SBCL, but if SBCL itself has not been yet built, but one if found
installed documentation strings from the installed version are used.
This builds the Info, HTML and PDF documentation from the SB-MANUAL
contrib. The manual includes documentation strings from the built
SBCL. If SBCL itself has not been built yet, but an installed one is
found, documentation strings from the installed version are used.
Now you should have the same src/runtime/sbcl and output/sbcl.core
files that come with the binary distribution, and you can install
@ -230,7 +230,7 @@ INSTALLING SBCL
files under "src/runtime", down- or upgrading GCC may help.
* Ask for help on the mailing lists referenced from
<http://www.sbcl.org/>.
<https://www.sbcl.org/>.
2.4. Tracking SBCL sources
@ -288,9 +288,7 @@ INSTALLING SBCL
by e.g. testing during the monthly freeze periods, and most
importantly by reporting any problems.
For further support, see Getting Support and Reporting Bugs
in the manual, or
For further support, see "Getting Support and Reporting Bugs"
(SB-MANUAL:@SUPPORT-AND-BUGS) in the manual locally or at
http://www.sbcl.org/manual/Getting-Support-and-Reporting-Bugs.html
if you do not have the manual for some reason.
https://www.sbcl.org/manual/#Getting-Support-and-Reporting-Bugs

253
NEWS
View file

@ -1,4 +1,257 @@
;;;; -*- coding: utf-8; fill-column: 78 -*-
changes in sbcl-2.6.8 relative to sbcl-2.6.7:
* minor incompatible change: FILE-POSITION on composite streams returns a
more accurate result for CONCATENATED-STREAM, and NULL on TWO-WAY-STREAM
and ECHO-STREAM.
* platform support:
** improvements to code generation for the ARM64 backend.
** improved support for AVX512 instruction encoding and decoding. (thanks
to Arthur Miller)
* various enhancements to the SB-SIMD contributed module. (thanks to Sylvia
Harrington and Arthur Miller)
* bug fix: FILE-POSITION on a stream after reading input into a list or
generic sequence returns the correct result.
* bug fix: allow the manual to build on more platforms. (lp#2162021)
* bug fix: infinite loop in the compiler while attempting to remove data
moves. (lp#2162597)
* bug fix: debugger failed to handle (COMPLEX DOUBLE-FLOAT) entities on the
stack. (reported by Clint Seinen)
* bug fix: error reporting from STRING-TO-OCTETS reported using the wrong
string indices. (lp#2164924)
* optimization: the compiler performs assignment conversion in nearly all
possible cases now, along the lines of Fluet and Weeks' "Contification
using Dominators" of 2001., which transforms state-machine-like code
written in terms of local functions into the equivalent tagbody/go control
structures.
* optimization: type inference of parameters is now possible for local
functions which recursively call themselves. (lp#486416, reported by
Tobias Rittweiler)
* optimization: special-case DPB with newbyte of 0 or -1.
* optimization: more improvements to UTF8 encoding and decoding.
* optimization: multiple structure TYPEP tests in sequence can elide
redundant memory loads of layouts.
* optimization: transform ZEROP of (LDB ...) to an equivalent zero test with
a mask. (lp#2162824, thanks to Vasily Postnicov)
changes in sbcl-2.6.7 relative to sbcl-2.6.6:
* new contrib module: SB-MANUAL contains the SBCL manual in docstrings of
section definitions, which tie together the docstrings of normal Lisp
definitions. The manual can thus be explored interactively in the usual
way (e.g. with Slime's M-.), and it is browsable with the MGL-PAX library
(out of tree). Also, https://fixnum.com/ (similarly unrelated to the SBCL
project) provides alternative renderings of the SBCL manual as heavily
linked PDF and HTML documents as well as Markdown and plain text.
* new feature: DOCUMENTATION supports DOC-TYPE DECLARATION.
* platform support:
** the SB-SIMD contrib now supports ARM64. (Thanks to Sylvia Harrington)
** AVX512 instructions are now supported on X86-64. (Thanks to Robert
Smith and Arthur Miller)
** additional support for SIMD instructions on ARM64 and X86-64. (Thanks
to Arthur Miller)
** fix miscompilation of SAP-REF-N on ARM64. (Thanks to Hayley Patton)
** implement INTEGER-LENGTH on primitive types without a loop on MIPS and
LoongArch.
* bug fix: READing with *READ-SUPPRESS* T no longer emits warnings like
"<internal-feature> no longer present on *FEATURES*".
* bug fix: compiler type-error when compiling calls to CONCATENATE with
conditional known non-sequence arguments. (lp#2160747)
* bug fix: (EQL <complex>) types were not being treated as numeric by the
type system. (lp#2160429)
* bug fix: improve the handling of quiet (non-signalling) NaN inputs to LOG.
(lp#2160268, reported by Woodrow Kiang)
* bug fix: miscompilation of MULTIPLE-VALUE-CALL. (lp#2160207, reported by
Vasily Postnicov)
* optimization: passing constant complex numbers to local functions can be
done without consing.
* optimization: where available, use enhanced SIMD routines for UTF-8
conversions.
* optimization: compiler transforms of COUNT are applicable with a wider
variety of keyword arguments.
* optimization: remove at least one redundant instruction from SB-ALIEN:DEREF.
* optimization: the sparse set implementation in the compiler has been tuned
to improve performance on real-world workloads.
* documentation: many typos and typesetting issues were fixed.
* documentation: SB-MANUAL:@FOREIGN-FUNCTION-INTERFACE now correctly states
that arrays are row-major (not column-major). (lp#2158033, thanks to Scott
L. Burson)
* documentation: internally, docstrings now conform to a subset of Markdown,
but DOCUMENTATION (and thus DESCRIBE) strips some of this markup. The
official manual is still generated from Texinfo, but the Texinfo files are
generated from SB-MANUAL.
* documentation: the manual now has a separate index for declarations.
changes in sbcl-2.6.6 relative to sbcl-2.6.5:
* minor incompatible change: FDEFINITION now returns the outermost wrapper
(added e.g. by TRACE, PROFILE) like SYMBOL-FUNCTION. (lp#799533)
* minor incompatible change: in unsafe code, C strings with :EXTERNAL-FORMAT
:ASCII are copied directly as byte-sized quantities without checking
whether the top bit of the byte is set.
* platform support:
** fix the build on big-endian 64-bit PowerPC with ELFv2. (thanks to
Piotr Kubaj)
** move the static space address for macOS 27 on ARM64. (lp#2156072,
reported by Gary Palter)
** optimizations to SB-THREAD:BARRIER for ARM64. (thanks to Sahil Kang)
** fix a compiler crash in MULTIPLE-VALUE-LIST in argument forms on ARM64.
(lp#2155788, reported by Gary Palter)
* bug fix: TRACE no longer fails when trying to print a return value that
cannot be printed readably and *PRINT-READABLY* is true.
* optimization: the compiler is more precise in its type derivation of
COERCE given constraints on its inputs.
* optimization: the compiler is better able to derive the return types of
AREF and ELT.
* optimization: faster encoding and decoding of UTF-8 C strings.
* optimization: (length (intersection a b)) doesn't cons an intermediate
list.
* documentation: the manual now includes a section for SB-INTROSPECT, which
has also seen improvement in its documentation strings and comments.
* documentation: fixed many typesetting problems and typos in the user
manual.
changes in sbcl-2.6.5 relative to sbcl-2.6.4:
* minor incompatible change: the condition signalled when an accessed slot
is missing from an object is no longer a TYPE-ERROR.
* minor incompatible change: the condition signalled when accessing an
uninitialized structure slot is no longer a TYPE-ERROR.
* minor incompatible change: the implementations of standardized functions
treating lists as sets, such as INTERSECTION and UNION, take more
advantage of the freedom to return the elements of the result in any
order.
* platform support:
** add low-level support for floating point state manipulation on
PPC64/FreeBSD. (thanks to Piotr Kubaj)
** improve the software emulation of displaced instructions on ARM64.
** restore building the system using the musl C library. (lp#2153432,
reported by Tom Gillespie)
** fix some SB-SIMD shifting instructions on AVX2. (lp#2152791, reported
by Willem Broekema)
* enhancement: definition sources for alien callbacks are now findable by
name in SB-INTROSPECT.
* bug fix: the SYMBOL restart for finding packages now actually performs a
non-local exit. (lp#2153092, reported by Zach Shaftel)
* bug fix: TYPEP on large disjoint numeric union types compiles faster using
fewer resources. (lp#2151818, reported by James McDonald)
* bug fix: strings of arbitrary size with fill-pointer set to 1 are
character designators. (reported by _death)
* bug fix: the KEEP-OLD restart established by ADD-PACKAGE-LOCAL-NICKNAME
keeps the old nickname instead of going ahead with the change (and the
restart report function no longer returns from ADD-PACKAGE-LOCAL-NICKNAME).
* bug fix: when EXPORT results in a conflict between symbols exported by
different used packages, the TAKE-NEW restart now shadowing-imports the
new symbol instead of doing nothing and leaving the package in an
inconsistent state.
* bug fix: the SB-EVAL interpreter checks program syntax more thoroughly.
* bug fix: compiler cross-reference data is decoded correctly for a
functional with more than one entry for a given name.
* bug fix: TYPE-ERRORs signalled by SBCL are more likely to have a DATUM
that is not of the condition's EXPECTED-TYPE.
* bug fix: the code walker no longer uses the stack to walk PROGN bodies.
* optimization: in various situations, INTERSECTION and UNION will use
hash-tables to perform the operation more quickly.
changes in sbcl-2.6.4 relative to sbcl-2.6.3:
* minor incompatible change: when DEFSETF is called on a name that was
previously used as a (presumed) call to a function, it issues a single
STYLE-WARNING (like DEFMACRO).
* minor incompatible change: SB-EXT:PROCESS-KILL no longer supports the
:PTY-PROCESS-GROUP option (which was never correctly implemented).
* minor incompatible change: the :INITIAL-OFFSET argument for typed
DEFSTRUCT, if given, no longer accepts NIL.
* platform support:
** more likely to support 32-bit linux's struct timeval with 64-bit time_t.
** the runtime's main function is now defined as a weak symbol for
platform/compiler combinations that support it.
** on Windows, individual empty arguments for RUN-PROGRAM are escaped.
** add input/output speed fields for our definition of the termios
structure, addressing a crash in sb-posix:tcsetattr on OpenBSD.
(lp#2150499, thanks to Robert Palm)
* bug fix: address infinite loops in the compiler. (lp#2144911, lp#2148056)
* bug fix: if an FTYPE has been proclaimed for a function, don't mix NULL
with explicitly-typed keyword arguments. (lp#2147050, reported by Vasily
Postnicov)
* bug fix: compiler error from treatment of unused results. (lp#2147383)
* bug fix: compiler error from invalid dimension arguments to MAKE-ARRAY.
(lp#2147384)
* bug fix: compiler error arising from continuing to optimize deleted nodes.
(lp#2147385)
* bug fix: make sure linkage-table alien entries have base-string names.
(lp#2147646, thanks to Seokjun Lee)
* bug fix: make sure CHECK-TYPE's expansion does not include internal
non-externalizable objects. (lp#2148777, reported by Willem Broekema)
* bug fix: alien calls involving passing structs by value are less likely to
read or write wrong areas of memory. (thanks to Jesse Bouwman)
* bug fix: lowering EQUALP to EQUAL handles constant dotted lists correctly.
* bug fix: a number of standard functions perform more explicit type checks
on their arguments.
* bug fix: only return the primary value from (LIST*/APPEND/NCONC <values>).
* bug fix: correct treatment of escaped closing brackets in pathname
patterns.
* bug fix: escape dots in pathnames more correctly.
* bug fix: the hash set for function names will incur collisions less
frequently. (reported by Andrew Wolven)
* bug fix: the system is now capable of expressing select() on the whole
range of possible file descriptors.
* optimization: compiler optimizations for (REPLACE vector list) now apply
given :START1 and/or :END1 keyword arguments.
* optimization: CONCATENATE is faster for concatenating list arguments to a
VECTOR.
* optimization: ROUND for integers is more compact.
* optimization: on 64-bit x86, implement TRUNCATE using the Lemire, Kaser,
Kurz transform.
changes in sbcl-2.6.3 relative to sbcl-2.6.2:
* minor incompatible change: (MAKE-ARRAY X :ELEMENT-TYPE 'UNDEFINED) now
signals an error, consistent with (UPGRADED-ARRAY-ELEMENT-TYPE
'UNDEFINED).
* platform support:
** fix disassembler on ppc for the MFLR and ISEL instructions
** the Lisp Return Address object (as part of the Lisp calling convention)
is no longer needed or supported on PPC, SPARC, MIPS or ARM. (This
also frees up a widetag slot previously held by return-pc-widetag)
** remove sensitivity to SBCL init files when building embedcore-sbcl.
(thanks to Robert Brown)
** add support for the ADCX and ADOX instructions on x86-64. (thanks to
Robert Smith)
** on PPC64, indicate the number of return values through flags, making
function calls four times faster.
** fix FFI involving int128 arguments on x86-64. (thanks to Andreas
Franke)
** fix build on OpenIndiana/x86-64. (thanks to Andreas Wacknitz)
** fix build on Haiku/x86-64.
* bug fix: improved stability of (particularly) the mark-region garbage
collector. (lp#2142711)
* bug fix: compiler type error in complicated expression involving BOOLE and
conditionals. (lp#2142949)
* bug fix: dotted lists involving symbols whose names begins with "DEF" are
not definitions. (lp#2143114, reported by Glenn Thompson)
* bug fix: STABLE-SORT miscompiled on declared union types involving both
LIST and VECTOR. (lp#2143163, reported by akater, thanks to Vasily
Postnicov)
* bug fix: more consistent results between compiler and interpreter in
numerical computations involving negative zeros. (lp#2143383)
* bug fix: USE-PACKAGE once again signals the correct error if an attempt is
made to use the KEYWORD package.
* bug fix: EQUALP on hash tables is no longer sensitive to irrelevant
aspects of the hash table.
* bug fix: SB-INTROSPECT:DEFTYPE-LAMBDA-LIST is more robust against types
defined in low debug situations.
* bug fix: ENSURE-GENERIC-FUNCTION ensures that the allocation of a generic
function does not happen in an arena. (Thanks to Andreas Franke)
* optimization: actually return early when we hit the cache for a
:MAKUNBOUND slot access. (thanks to John Mallery)
* optimization: streams opened with WITH-OPEN-FILE avoid having finalizers.
* optimization: improvement of COUNT on non-simple bit-vectors, or simple
ones with :START/:END arguments. (lp#2142062, thanks to Andrew Berkley)
* optimization: SIMD routines for checking strings for ASCII-only content
are more compact.
* optimization: the reader prefers base-string symbol-names of uninterned
symbols if possible.
* optimization: (length (remove-duplicates a s)) doesn't cons an
intermediate sequence.
* optimization: REMOVE-DUPLICATES uses hash-tables in more situations.
* optimization: UPGRADED-ARRAY-ELEMENT-TYPE is now faster.
changes in sbcl-2.6.2 relative to sbcl-2.6.1:
* minor incompatible change: IMAGPART of a negative float returns 0.0, not
-0.0, consistent with a treatment of reals as complexes with an imaginary

12
README
View file

@ -9,19 +9,17 @@ To find out more about who created the system, see the "CREDITS" file.
If you'd like information about the legalities of copying the system,
see the "COPYING" file.
If you'd like more information about using the system, see the man
page, "sbcl.1", or the user manual in the "doc/manual" subdirectory of
the distribution. (The user manual is maintained as Texinfo in the
source distribution; HTML version is available for download, and
"INSTALL" describes how to build the Texinfo version in HTML and PDF.)
The "DOCUMENTATION" file describes the various formats and ways to
access the documentation.
The system is a work in progress. See the "TODO" file in the source
distribution for some highlights.
See the "BUGS" file for how to view or report bugs.
If you'd like to make suggestions, report a bug, or help to improve the
system, please send mail to one of the mailing lists:
If you'd like to make suggestions or help to improve the system,
please send mail to one of the mailing lists:
sbcl-help@lists.sourceforge.net
sbcl-devel@lists.sourceforge.net
Note that as a spam reduction measure you must subscribe to the lists

8
TLA
View file

@ -3,8 +3,8 @@
abbreviations we try to use pervasively in the system
As Dan Barlow pointed out long ago on the mailing list, unabbreviated
names are easier to deal with than abbreviated names, because you
never need to remember what abbreviation to use. That's true, but in a
names are easier to deal with than abbreviated names because you never
need to remember what abbreviation to use. That's true, but in a
language like Lisp which depends on compound names for important
things like structure accessors, that can lead to painful names like
MAKE-EXTERNAL-ENTRY-POINT-LAMBDA-EXPRESSION and associated indenting
@ -30,8 +30,8 @@ making them more consistent.
SB storage base (in compiler IR2)
SC storage class (in compiler IR2)
TN temporary name (?) (in compiler IR2)
VAR variable (in the lisp entity "noun" sense, not in the
VAR variable (in the lisp entity "noun" sense, not in the
adjectival sense)
XEP external entry point
Making them even more consistent (within the limits of ANSI and
Making them even more consistent (within the limits of ANSI and
MOP compatibility) would probably be good.

5
TODO
View file

@ -65,10 +65,7 @@ ADVICE/FWRAP
SBCL has an internal function encapsulation mechanism, and is able to
install breakpoint to function start/end -- this is used to implement
the instrumentation based profiler and tracing. It would be good to
have this as an exported interface, and it would be good if the
SYMBOL-FUNCTION / FDEFINITION confusion was fixed: currently the
latter returns the underlying definition, whereas the first returns
the encapsulation.
have this as an exported interface.
POLICY MADNESS

102
benchmarks/rwlbench2.lisp Normal file
View file

@ -0,0 +1,102 @@
(defpackage :sbcl-lock-bench
(:use :cl :sb-thread)
(:shadow #:spinlock #:with-spinlock)
(:export :compare-locks))
(in-package :sbcl-lock-bench)
(defparameter *time-wasting-iterations-read* 100)
(defparameter *time-wasting-iterations-write* 150)
;;; spinlock
(defstruct (spinlock)
(state 0 :type sb-ext:word)) ; 0 = unlocked, 1 = locked
(defun spin-lock (lock)
(declare (optimize (speed 3) (safety 0)))
(loop (if (eql 0 (sb-ext:cas (spinlock-state lock) 0 1))
(return t)
(sb-thread:thread-yield))))
(declaim (inline spin-unlock))
(defun spin-unlock (lock)
(declare (optimize (speed 3) (safety 0)))
(setf (spinlock-state lock) 0))
(defmacro with-spinlock ((lock) &body body)
`(progn
(spin-lock ,lock)
(unwind-protect (progn ,@body)
(spin-unlock ,lock))))
(defun run-spinlock-worker (lock operations write-percent)
(let* ((my-random-state (make-random-state t))
(r (random 100 my-random-state)))
(dotimes (i (the fixnum operations))
;; readers and writers use the same lock mechanism
(with-spinlock (lock)
(if (< r write-percent)
(loop repeat *time-wasting-iterations-write*)
(loop repeat *time-wasting-iterations-read*))
;; and do some some work inside the lock
(setq r (random 100 my-random-state))))))
;;; spinlock-based rwlock
(defmacro with-rwlock-read ((lock) &body body)
`(progn (rwspinlock-rdlock ,lock)
(multiple-value-prog1 (progn ,@body) (rwspinlock-rdunlock ,lock))))
(defmacro with-rwlock-write ((lock) &body body)
`(progn (rwspinlock-wrlock ,lock)
(multiple-value-prog1 (progn ,@body) (rwspinlock-wrunlock ,lock))))
(defun run-rwlock-worker (lock operations write-percent)
(let* ((my-random-state (make-random-state t))
(r (random 100 my-random-state)))
(dotimes (i (the fixnum operations))
(if (< r write-percent)
(with-rwlock-write (lock)
(loop repeat *time-wasting-iterations-write*)
(setq r (random 100 my-random-state)))
(with-rwlock-read (lock)
(loop repeat *time-wasting-iterations-read*)
(setq r (random 100 my-random-state)))))))
;; runner
(defun execute-bench (lock-type operations threads write-percent)
(let ((threads-list '())
(start-time (get-internal-real-time))
(lock (if (eq lock-type :rwlock)
(sb-thread::make-rw-spinlock)
(make-spinlock))))
(dotimes (i threads)
(push (sb-thread:make-thread
(lambda ()
(if (eq lock-type :rwlock)
(run-rwlock-worker lock operations write-percent)
(run-spinlock-worker lock operations write-percent))))
threads-list))
(mapc #'sb-thread:join-thread threads-list)
(let* ((end-time (get-internal-real-time))
(elapsed (/ (- end-time start-time) internal-time-units-per-second)))
elapsed)))
(defun compare-locks (&key (threads 4) (ops-per-thread 100000))
(format t "~%================================================~%")
(format t "Comparing spinlock-based RWLOCK vs MUTEX~%")
(format t "Threads: ~D | Ops/Thread: ~D~%" threads ops-per-thread)
(format t "================================================~%~%")
(format t "~10A | ~15A | ~15A | ~A~%" "Write %" "RW-Lock Time" "Mutex Time" "Speedup (RW / Mutex)")
(format t "------------------------------------------------------------------~%")
(dolist (pct '(0 1 2 3 5 10 20 30 40 50 60 70 80 90 100))
(let ((rw-time (execute-bench :rwlock ops-per-thread threads pct))
(mutex-time (execute-bench :mutex ops-per-thread threads pct)))
(format t "~10D | ~14,3Fs | ~14,3Fs | ~,2Fx~%"
pct
rw-time
mutex-time
(/ mutex-time rw-time))))) ; Speedup > 1.0x means RWLock was faster

View file

@ -0,0 +1,125 @@
(defun calc-et (from-sec from-ns to-sec to-ns)
(let ((from (floor (+ (* 1000000000 from-sec) from-ns) 1000))
(to (floor (+ (* 1000000000 to-sec) to-ns) 1000)))
(- to from)))
(defmacro my-timing (form)
(let ((clockid #+linux sb-unix:clock-thread-cputime-id
#+darwin sb-unix:clock-process-cputime-id))
`(sb-int:binding* (((sec-before nsec-before) (sb-unix:clock-gettime ,clockid))
(nil ,form)
((sec-after nsec-after) (sb-unix:clock-gettime ,clockid)))
(calc-et sec-before nsec-before sec-after nsec-after))))
(defparameter *validate* nil)
(defun compare (testcases &optional (validate *validate*))
(declare (simple-vector testcases))
(declare (optimize speed))
(declare (notinline sb-ext:octets-to-string)) ; because unsafely flushable
(when validate ; make sure they agree
(sb-int:dovector (x testcases)
(let ((way1 (sb-unicode:utf8-decode-from-octets x))
(way2 (sb-ext:octets-to-string x)))
(assert (string= way1 way2)))))
;; These tests cons a lot and can be easily skewed by having very random
;; places at which they GC. We get fairly consistent results when both the
;; baseline and experiment have a manual GC done beforehand.
(gc)
;; run the new way first to give the benefit-of-doubt to the old way
;; in terms of bringing memory into L1 cache
(let ((et-new (my-timing
(sb-int:dovector (x testcases) (sb-unicode:utf8-decode-from-octets x)))))
(gc)
(let ((et-old (my-timing
(sb-int:dovector (x testcases) (sb-ext:octets-to-string x)))))
(format t "~D ~D (~f%)~%" et-old et-new (* 100 (/ (- et-new et-old) et-old))))))
(defun random-string (stringlen percent-ascii &aux (unicode (- 100 percent-ascii)))
(let ((s (make-string stringlen)))
(dotimes (i stringlen s)
(setf (char s i)
(code-char (if (< (random 100.0) unicode)
(loop (let ((c (max 1 (random char-code-limit))))
(when (sb-unicode:scalar-p c) (return c))))
(max 1 (random 128))))))))
(defun bench ()
(dolist (stringlen '(5 100 1000 10000 1000000))
(dolist (percent-ascii '(100 99 98 97 96 95 90 80 70 60 50 40))
(let ((n-trials (ceiling 10000000 stringlen)))
(format t "~&~3D% ASCII, length=~d [~d iterations]: " percent-ascii stringlen n-trials)
(force-output)
(let ((testcases
(coerce
(loop repeat n-trials
collect
(string-to-octets (random-string stringlen percent-ascii)))
'vector)))
(compare testcases))))))
#|
My results on an x86-64 macbook (negative percent diff means new is is better)
and the deltas are either very similar or show slightly less of an improvement
for arm64 macbook, but still always an improvement over the baseline.
100% ASCII, length=5 [2000000 iterations]: 426481 89626 (-78.984764%)
99% ASCII, length=5 [2000000 iterations]: 469787 60676 (-87.08436%)
98% ASCII, length=5 [2000000 iterations]: 471085 65415 (-86.11397%)
97% ASCII, length=5 [2000000 iterations]: 488598 68924 (-85.89352%)
96% ASCII, length=5 [2000000 iterations]: 482445 74787 (-84.49834%)
95% ASCII, length=5 [2000000 iterations]: 481117 77478 (-83.896225%)
90% ASCII, length=5 [2000000 iterations]: 491657 87709 (-82.16053%)
80% ASCII, length=5 [2000000 iterations]: 515252 103540 (-79.904976%)
70% ASCII, length=5 [2000000 iterations]: 539165 116004 (-78.484505%)
60% ASCII, length=5 [2000000 iterations]: 569675 136532 (-76.033356%)
50% ASCII, length=5 [2000000 iterations]: 589356 143996 (-75.56723%)
40% ASCII, length=5 [2000000 iterations]: 613356 144063 (-76.51234%)
100% ASCII, length=100 [100000 iterations]: 140443 3974 (-97.17038%)
99% ASCII, length=100 [100000 iterations]: 149191 50945 (-65.8525%)
98% ASCII, length=100 [100000 iterations]: 139345 77090 (-44.67688%)
97% ASCII, length=100 [100000 iterations]: 154108 74434 (-51.700108%)
96% ASCII, length=100 [100000 iterations]: 144111 87651 (-39.178135%)
95% ASCII, length=100 [100000 iterations]: 162271 79519 (-50.996174%)
90% ASCII, length=100 [100000 iterations]: 157988 92868 (-41.21832%)
80% ASCII, length=100 [100000 iterations]: 196840 91016 (-53.76143%)
70% ASCII, length=100 [100000 iterations]: 209938 108707 (-48.219475%)
60% ASCII, length=100 [100000 iterations]: 248108 109260 (-55.962727%)
50% ASCII, length=100 [100000 iterations]: 254467 121921 (-52.087696%)
40% ASCII, length=100 [100000 iterations]: 285208 114461 (-59.867535%)
100% ASCII, length=1000 [10000 iterations]: 105570 1546 (-98.53557%)
99% ASCII, length=1000 [10000 iterations]: 112052 87494 (-21.91661%)
98% ASCII, length=1000 [10000 iterations]: 120597 77042 (-36.116154%)
97% ASCII, length=1000 [10000 iterations]: 133759 75267 (-43.729393%)
96% ASCII, length=1000 [10000 iterations]: 124279 76452 (-38.483574%)
95% ASCII, length=1000 [10000 iterations]: 145278 76784 (-47.14685%)
90% ASCII, length=1000 [10000 iterations]: 141478 81126 (-42.658222%)
80% ASCII, length=1000 [10000 iterations]: 177988 89134 (-49.921345%)
70% ASCII, length=1000 [10000 iterations]: 190698 99088 (-48.039307%)
60% ASCII, length=1000 [10000 iterations]: 240096 108468 (-54.82307%)
50% ASCII, length=1000 [10000 iterations]: 241091 113381 (-52.9717%)
40% ASCII, length=1000 [10000 iterations]: 274307 113896 (-58.478638%)
100% ASCII, length=10000 [1000 iterations]: 116469 1521 (-98.69408%)
99% ASCII, length=10000 [1000 iterations]: 122827 84726 (-31.020052%)
98% ASCII, length=10000 [1000 iterations]: 125854 85905 (-31.742336%)
97% ASCII, length=10000 [1000 iterations]: 144160 76104 (-47.208656%)
96% ASCII, length=10000 [1000 iterations]: 149835 76644 (-48.847733%)
95% ASCII, length=10000 [1000 iterations]: 149988 79170 (-47.21578%)
90% ASCII, length=10000 [1000 iterations]: 143812 98798 (-31.300587%)
80% ASCII, length=10000 [1000 iterations]: 188148 89944 (-52.19508%)
70% ASCII, length=10000 [1000 iterations]: 214511 129084 (-39.824066%)
60% ASCII, length=10000 [1000 iterations]: 240322 110871 (-53.865646%)
50% ASCII, length=10000 [1000 iterations]: 237560 122167 (-48.574253%)
40% ASCII, length=10000 [1000 iterations]: 272658 114349 (-58.061382%)
100% ASCII, length=1000000 [10 iterations]: 122355 3950 (-96.77169%)
99% ASCII, length=1000000 [10 iterations]: 127108 70778 (-44.316643%)
98% ASCII, length=1000000 [10 iterations]: 135022 80389 (-40.462296%)
97% ASCII, length=1000000 [10 iterations]: 126778 72913 (-42.487656%)
96% ASCII, length=1000000 [10 iterations]: 144430 74448 (-48.453922%)
95% ASCII, length=1000000 [10 iterations]: 138535 78872 (-43.067097%)
90% ASCII, length=1000000 [10 iterations]: 145037 77884 (-46.3006%)
80% ASCII, length=1000000 [10 iterations]: 190233 89723 (-52.83521%)
70% ASCII, length=1000000 [10 iterations]: 197363 95052 (-51.838997%)
60% ASCII, length=1000000 [10 iterations]: 216470 115180 (-46.791702%)
50% ASCII, length=1000000 [10 iterations]: 244138 108852 (-55.413742%)
40% ASCII, length=1000000 [10 iterations]: 247799 123019 (-50.355328%)
|#

View file

@ -19,6 +19,7 @@ tar -cf $b-binary.tar \
$b/src/runtime/sbcl.mk \
`grep '^LIBSBCL=' $b/src/runtime/sbcl.mk | cut -d= -f2- | while read lib; do echo $b/src/runtime/$lib; done` \
$b/BUGS $b/COPYING $b/CREDITS $b/INSTALL $b/NEWS $b/README \
$b/DOCUMENTATION \
$b/install.sh $b/find-gnumake.sh $b/sbcl-pwd.sh $b/run-sbcl.sh \
$b/doc/sbcl.1 \
$b/pubring.pgp \

View file

@ -32,7 +32,8 @@
;;; This list is: arch-name and ((configuation-name feature ...) ...)
(defparameter *all-configurations*
'(("arm" ("arm" :little-endian :largefile))
("arm64" ("arm64" :little-endian :sb-thread)
("arm64" ("arm64" :little-endian :sb-thread :tls-based-mv-return)
("arm64+simd" :little-endian :sb-thread :sb-simd-pack)
("arm64-darwin" :darwin :bsd :unix :mach-o :little-endian :sb-thread :darwin-jit)
("arm64-reloc" :little-endian :sb-thread :relocatable-static-space :immobile-space)
("arm64-immobile-space" :little-endian :sb-thread :immobile-space))
@ -49,15 +50,15 @@
("x86-ascii" :little-endian :largefile (not :sb-unicode))
("x86-thread" :little-endian :largefile :sb-thread)
("x86-linux" :little-endian :largefile :sb-thread :linux :unix :elf :sb-thread))
("x86-64" ("x86-64" :little-endian :avx2 :gencgc :sb-simd-pack :sb-simd-pack-256)
("x86-64-linux" :linux :unix :elf :little-endian :avx2 :gencgc :sb-simd-pack :sb-simd-pack-256
(not :sb-eval) :sb-fasteval)
("x86-64-darwin" :darwin :bsd :unix :mach-o :little-endian :avx2 :gencgc
:sb-simd-pack :sb-simd-pack-256)
("x86-64-imm" :little-endian :avx2 :gencgc :sb-simd-pack :sb-simd-pack-256
:immobile-space (not :sb-unicode))
("x86-64-permgen" :little-endian :avx2 :gencgc :sb-simd-pack :sb-simd-pack-256
:permgen))))
("x86-64" ("x86-64" :little-endian :avx2 :avx512 :gencgc :sb-simd-pack :sb-simd-pack-256 :sb-simd-pack-512)
("x86-64-linux" :linux :unix :elf :little-endian :avx2 :avx512 :gencgc :tls-based-mv-return
:sb-simd-pack :sb-simd-pack-256 :sb-simd-pack-512 (not :sb-eval) :sb-fasteval)
("x86-64-darwin" :darwin :bsd :unix :mach-o :little-endian :avx2 :avx512 :gencgc
:sb-simd-pack :sb-simd-pack-256 :sb-simd-pack-512)
("x86-64-imm" :little-endian :avx2 :avx512 :gencgc :sb-simd-pack :sb-simd-pack-256
:sb-simd-pack-512 :immobile-space (not :sb-unicode))
("x86-64-permgen" :little-endian :avx2 :avx512 :gencgc :sb-simd-pack
:sb-simd-pack-256 :sb-simd-pack-512 :permgen))))
(setq sb-ext:*evaluator-mode* :compile)
(defun interpolate (string substitutions)
@ -92,7 +93,10 @@
((new
(with-output-to-string (makefile)
(format makefile
"SBCL=src/runtime/sbcl
"###################################################
### THIS FILE IS MACHINE-GENERATED. DO NOT EDIT ###
###################################################
SBCL=src/runtime/sbcl
ARGS=--core output/sbcl.core --noinform --disable-debugger --noprint --no-userinit --no-sysinit
SCRIPT1=crossbuild-runner/pass-1.lisp
SCRIPT2=crossbuild-runner/pass-2.lisp
@ -134,7 +138,7 @@ obj/xbuild/{cfg}.core: obj/xbuild/{cfg}/xc.core
"-k"
"-fcrossbuild-runner/Makefile"
,@(corefiles))
:output t :error t
:input t :output t :error t
:search t))
(when (= (process-exit-code *process*) 0)
(load "src/cold/shared" :verbose t)

View file

@ -3,7 +3,7 @@ vpath %.fasl ../obj/sbcl-home/contrib/
contribs = sb-posix sb-bsd-sockets sb-introspect sb-cltl2 sb-aclrepl \
sb-sprof sb-capstone sb-md5 sb-capstone sb-executable sb-gmp sb-mpfr \
sb-queue sb-rotate-byte sb-rt sb-simple-streams sb-concurrency sb-cover \
sb-simd sb-grovel sb-perf asdf
sb-simd sb-grovel sb-perf sb-manual asdf
active_contribs = $(filter-out $(SBCL_CONTRIB_BLOCKLIST),$(contribs))
@ -21,6 +21,13 @@ sb-queue.fasl: sb-concurrency.fasl
sb-simple-streams.fasl: sb-posix.fasl sb-bsd-sockets.fasl
sb-grovel.fasl: asdf.fasl # for building the module, not for our build
sb_manual_module_deps = sb-aclrepl sb-bsd-sockets sb-cltl2 sb-concurrency \
sb-cover sb-grovel sb-introspect sb-md5 sb-posix sb-rotate-byte \
sb-queue sb-sprof sb-simd sb-simple-streams
sb_manual_unblocked_module_deps = \
$(filter-out $(SBCL_CONTRIB_BLOCKLIST), $(sb_manual_module_deps))
sb-manual.fasl: $(sb_manual_unblocked_module_deps:=.fasl)
# Notes:
# 1. Invoking $(MAKE) for nested make eliminates a warning about jobserver mode.
# 2. This could be made to 'tee' into output/{something} as it used to,

View file

@ -3,7 +3,7 @@ core SBCL functionality, or else they'd be built into the main SBCL
binary automatically. And they're not portable Common Lisp, or they'd
be put elsewhere (see http://sbcl.sf.net/libs.php for pointers)
There are two kinds of contrib module in this directory:
There are two kinds of contrib modules in this directory:
* Newer contrib modules conform to the contrib standard (see
STANDARDS) and are automatically built and installed along with

View file

@ -1,4 +1,4 @@
Proposed contrib standard, $Revision$
Proposed contrib standard
The SBCL contrib mechanism provides a mechanism to
manage code which does not form part of SBCL itself, but which is
@ -71,23 +71,16 @@ good place to test that they still exist, etc.
* Documentation
Each package should provide documentation in Texinfo format. For the
documentation to be included in the sbcl manual, the following must
hold:
Each package should provide documentation in SB-MANUAL format. For the
documentation to be included in the SBCL manual, you must
- Each Texinfo file must have the extension `.texinfo' so the
automatic manual builder will find it.
- add the relevant file to contrib/sb-manual/sb-manual.asd,
- It must contain one @node - @section pair at the top and only
@subsection (or lower) sectioning commands within, e.g.
- modify SB-MANUAL::*PAGES*.
@node Sample Contrib
@section Sample Contrib
...
so that the contrib menu can be created automatically.
Take care to choose unique node names.
Take care to choose globally unique and meaningful section names, as
the names are exported from SB-MANUAL and also visible to the user as
HTML anchors.
[ make install should copy the documentation somewhere that the user
can find it ]

View file

@ -12,7 +12,7 @@ FASL=$(DEST)/$(SYSTEM).fasl
ASD=$(DEST)/$(SYSTEM).asd
ifeq (SunOS,$(UNAME))
EXTRA_CFLAGS+=-D_XOPEN_SOURCE=500 -D__EXTENSIONS__
CFLAGS+=-D_XOPEN_SOURCE=500 -D__EXTENSIONS__
PATH:=/usr/xpg4/bin:${PATH}
endif
ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME)))
@ -22,10 +22,10 @@ ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME)))
CC:=$(shell cygpath -m $(shell readlink -fn $(shell which $(CC))))
endif
ifeq (Linux,$(UNAME))
EXTRA_CFLAGS+=-D_GNU_SOURCE
CFLAGS+=-D_GNU_SOURCE
endif
export CC SBCL EXTRA_CFLAGS
export CC SBCL CFLAGS
all: $(FASL)

View file

@ -46,6 +46,15 @@
(unless (= result 0) (error "C execution failed")))))))
(defparameter +genfile+ "generated-constants")
(defun resolve-up-directory-components (pathname-directory)
(let ((result ()))
(dolist (c pathname-directory)
(if (eq c :up)
(pop result)
(push c result)))
(nreverse result)))
(defun logicalize (path generated)
(make-pathname :host "SYS"
:directory
@ -53,8 +62,9 @@
(if generated
(list "OBJ" "FROM-SELF" "CONTRIB" *system*)
(list* "CONTRIB"
(append (last (pathname-directory *default-pathname-defaults*))
(cdr (pathname-directory path))))))
(resolve-up-directory-components
(append (last (pathname-directory *default-pathname-defaults*))
(cdr (pathname-directory path)))))))
:name (pathname-name path)
:type (pathname-type path)))
@ -134,6 +144,8 @@
;; foreign-glue contains macros needed to compile the generated file
(let ((*evaluator-mode* :compile)) (load "../sb-grovel/foreign-glue")))
(let (wcu-warnings)
;; SETQ is fine, we're going to exit this image soon enough
(setq sb-ext:*derive-function-types* t)
(handler-bind (((and warning (not style-warning))
(lambda (c)
(unless (ignorable-warning-p c)
@ -141,13 +153,15 @@
(with-compilation-unit ()
(loop for (generated-p stem) in (flattened-sources)
do (let ((fasl
(if (string= (pathname-type stem) "fasl")
stem
(multiple-value-bind (output warnings errors)
(compile-file (logicalize stem generated-p)
:output-file (format nil "~A~A.fasl" objdir stem))
(when (or warnings errors) (sb-sys:os-exit 1))
output))))
(if (string= (pathname-type stem) "fasl")
stem
(multiple-value-bind (output warnings errors)
(compile-file
(logicalize stem generated-p)
:output-file (ensure-directories-exist
(merge-pathnames stem objdir)))
(when (or warnings errors) (sb-sys:os-exit 1))
output))))
(fasls fasl)
(load fasl)))))
;; Deferred warnings occur *after* exiting the W-C-U body.

View file

@ -0,0 +1,51 @@
(in-package :sb-manual)
(defsection @sb-aclrepl (:title "sb-aclrepl" :concepts (~repl))
"The `SB-ACLREPL` module offers an Allegro CL-style
Read-Eval-Print Loop for SBCL, with integrated inspector. Adding a
debugger interface is planned.
Allegro CL is a registered trademark of Franz Inc."
(@sb-aclrepl-usage section)
(@sb-aclrepl-customization section)
(@sb-aclrepl-example-initialization section))
(defsection @sb-aclrepl-usage (:title "Usage")
"To start `SB-ACLREPL` as your read-eval-print loop, put the form
(require 'sb-aclrepl)
in your `~/.sbclrc`, one of your @INITIALIZATION-FILES.")
(defsection @sb-aclrepl-customization (:title "Customization")
"The following customization variables are available:"
(sb-aclrepl:*command-char* variable)
(sb-aclrepl:*prompt* variable)
(sb-aclrepl:*exit-on-eof* variable)
(sb-aclrepl:*use-short-package-name* variable)
(sb-aclrepl:*max-history* variable))
(defsection @sb-aclrepl-example-initialization (:title "Example Initialization")
"Here's a longer example of a `~/.sbclrc` file that shows off
some of the features of sb-aclrepl:
(ignore-errors (require 'sb-aclrepl))
(when (find-package 'sb-aclrepl)
(push :aclrepl cl:*features*))
#+aclrepl
(progn
(setq sb-aclrepl:*max-history* 100)
(setf (sb-aclrepl:alias \"asdc\")
#'(lambda (sys) (asdf:operate 'asdf:compile-op sys)))
(sb-aclrepl:alias \"l\" (sys) (asdf:operate 'asdf:load-op sys))
(sb-aclrepl:alias \"t\" (sys) (asdf:operate 'asdf:test-op sys))
;; The 1 below means that two characaters (\"up\") are required
(sb-aclrepl:alias (\"up\" 1 \"Use package\") (package) (use-package package))
;; The 0 below means only the first letter (\"r\") is required,
;; such as \":r base64\"
(sb-aclrepl:alias (\"require\" 0 \"Require module\") (sys) (require sys))
(setq cl:*features* (delete :aclrepl cl:*features*)))
Questions, comments, or bug reports should be sent to Kevin Rosenberg
(kevin@rosenberg.net).")

View file

@ -33,7 +33,7 @@
(defparameter *prompt* #.*default-prompt*
"The current prompt string or formatter function.")
(defparameter *use-short-package-name* t
"when T, use the shortnest package nickname in a prompt")
"When T, use the shortest package nickname in a prompt.")
(defparameter *dir-stack* nil
"The top-level directory stack")
(defparameter *command-char* #\:

View file

@ -1,39 +1,70 @@
@node sb-aclrepl
@section sb-aclrepl
@c Generated by the sb-manual contrib. Do not edit.
@node sb aclrepl
@cindex Read-Eval-Print Loop
@cindex REPL
@section sb-aclrepl
@menu
* Usage: sb aclrepl usage.
* Customization: sb aclrepl customization.
* Example Initialization: sb aclrepl example initialization.
@end menu
@c FIXME: I wanted to use @registeredsymbol{}, but that's
@c only available in Texinfo 4.7. sigh.
The @code{sb-aclrepl} module offers an Allegro CL-style
Read-Eval-Print Loop for SBCL, with integrated inspector. Adding a
Read-Eval-Print Loop for SBCL, with integrated inspector. Adding a
debugger interface is planned.
Allegro CL is a registered trademark of Franz Inc.
@node sb aclrepl usage
@subsection Usage
To start @code{sb-aclrepl} as your read-eval-print loop, put the form
@lisp
@example
(require 'sb-aclrepl)
@end lisp
@end example
in your @file{~/.sbclrc} initialization file.
in your @code{~/.sbclrc}, one of your @ref{initialization files}.
@node sb aclrepl customization
@subsection Customization
The following customization variables are available:
@include var-sb-aclrepl-star-command-char-star.texinfo
@include var-sb-aclrepl-star-prompt-star.texinfo
@include var-sb-aclrepl-star-exit-on-eof-star.texinfo
@include var-sb-aclrepl-star-use-short-package-name-star.texinfo
@include var-sb-aclrepl-star-max-history-star.texinfo
@anchor{Variable sb-aclrepl *command-char*}
@vvindex @sortas{command-char* sb-aclrepl} *command-char* [sb-aclrepl]
@deffn{Variable} sb-aclrepl:*command-char*
Prefix character for a top-level command
@end deffn
@anchor{Variable sb-aclrepl *prompt*}
@vvindex @sortas{prompt* sb-aclrepl} *prompt* [sb-aclrepl]
@deffn{Variable} sb-aclrepl:*prompt*
The current prompt string or formatter function.
@end deffn
@anchor{Variable sb-aclrepl *exit-on-eof*}
@vvindex @sortas{exit-on-eof* sb-aclrepl} *exit-on-eof* [sb-aclrepl]
@deffn{Variable} sb-aclrepl:*exit-on-eof*
If @code{t}, then exit when the EOF character is entered.
@end deffn
@anchor{Variable sb-aclrepl *use-short-package-name*}
@vvindex @sortas{use-short-package-name* sb-aclrepl} *use-short-package-name* [sb-aclrepl]
@deffn{Variable} sb-aclrepl:*use-short-package-name*
When @code{t}, use the shortest package nickname in a prompt.
@end deffn
@anchor{Variable sb-aclrepl *max-history*}
@vvindex @sortas{max-history* sb-aclrepl} *max-history* [sb-aclrepl]
@deffn{Variable} sb-aclrepl:*max-history*
Maximum number of history commands to remember
@end deffn
@node sb aclrepl example initialization
@subsection Example Initialization
Here's a longer example of a @file{~/.sbclrc} file that shows off
some of the features of @code{sb-aclrepl}:
Here's a longer example of a @code{~/.sbclrc} file that shows off
some of the features of sb-aclrepl:
@lisp
@example
(ignore-errors (require 'sb-aclrepl))
(when (find-package 'sb-aclrepl)
@ -51,11 +82,8 @@ some of the features of @code{sb-aclrepl}:
;; such as ":r base64"
(sb-aclrepl:alias ("require" 0 "Require module") (sys) (require sys))
(setq cl:*features* (delete :aclrepl cl:*features*)))
@end lisp
@end example
Questions, comments, or bug reports should be sent to Kevin Rosenberg
(@email{kevin@@rosenberg.net}).
(kevin@@rosenberg.net).
@subsection Credits
Allegro CL is a registered trademark of Franz Inc.

View file

@ -22,7 +22,7 @@
;;; getprotobyname if it's available.
(defun get-protocol-by-name (name)
"Given a protocol name, return the protocol number, the protocol name, and
a list of protocol aliases"
a list of protocol aliases."
(let ((result (cdr (if (keywordp name)
(assoc name *protocols*)
(assoc name *protocols* :test #'string-equal)))))

View file

@ -9,9 +9,9 @@
Examples:
(make-instance 'sb-bsd-sockets:inet-socket :type :stream :protocol :tcp)
(make-instance 'sb-bsd-sockets:inet-socket :type :stream :protocol :tcp)
(make-instance 'sb-bsd-sockets:inet-socket :type :datagram :protocol :udp)
(make-instance 'sb-bsd-sockets:inet-socket :type :datagram :protocol :udp)
")))
(defun address-numbers/v4 (address)

View file

@ -9,9 +9,9 @@
Examples:
(make-instance 'sb-bsd-sockets:inet6-socket :type :stream :protocol :tcp)
(make-instance 'sb-bsd-sockets:inet6-socket :type :stream :protocol :tcp)
(make-instance 'sb-bsd-sockets:inet6-socket :type :datagram :protocol :udp)
(make-instance 'sb-bsd-sockets:inet6-socket :type :datagram :protocol :udp)
")))
(defun address-numbers/v6 (address)

View file

@ -6,8 +6,8 @@
(defclass local-socket (socket)
((family :initform sockint::af-local))
(:documentation
"Class representing local domain (AF_LOCAL) sockets,
also known as unix-domain sockets."))
"Class representing local domain (`\\\\AF_LOCAL`) sockets,
also known as Unix-domain sockets."))
(defmethod socket-namestring ((socket local-socket))
(ignore-errors (socket-name socket)))
@ -41,8 +41,8 @@ also known as unix-domain sockets."))
(defclass local-abstract-socket (local-socket) ()
(:documentation
"Class representing local domain (AF_LOCAL) sockets with addresses
in the abstract namespace."))
"Class representing local domain (`\\\\AF_LOCAL`) sockets with
addresses in the abstract namespace."))
(defmethod make-sockaddr-for ((socket local-abstract-socket)
&optional sockaddr &rest address)

View file

@ -0,0 +1,127 @@
(in-package :sb-manual)
(defsection @networking (:title "Networking")
"The `SB-BSD-SOCKETS` module provides a thinly disguised BSD
socket API for SBCL. Ideas have been stolen from the BSD socket API
for C and Graham Barr's `IO::Socket` classes for Perl.
Sockets are represented as CLOS objects, and the API naming
conventions attempt to balance between the BSD names and good lisp
style."
(@sockets-overview section)
(@general-sockets section)
(@socket-options section)
(@inet-domain-sockets section)
#-win32
(@local-domain-sockets section)
(@name-service section))
(defsection @sockets-overview (:title "Sockets Overview")
"Most of the functions are modelled on the BSD socket API. BSD sockets
are widely supported, portably (by Unix standards, at least)
available on a variety of systems, and documented. There are some
differences in approach where we have taken advantage of some of the
more useful features of Common Lisp -- briefly:
- Where the C API would typically return -1 and set `errno`,
`SB-BSD-SOCKETS` signals an error. All the errors are subclasses
of SB-BSD-SOCKETS:SOCKET-ERROR and generally correspond one for
one with possible `errno` values.
- We use multiple return values in many places where the C API would
use pass-by-reference values.
- We can often avoid supplying an explicit length argument to
functions because we already know how long the argument is.
- IP addresses and ports are represented in slightly friendlier
fashion than \"network-endian integers\".")
(defsection @general-sockets (:title "General Sockets")
(sb-bsd-sockets:socket class)
(sb-bsd-sockets:socket-bind function)
(sb-bsd-sockets:socket-accept function)
(sb-bsd-sockets:socket-connect function)
(sb-bsd-sockets:socket-peername function)
(sb-bsd-sockets:socket-name function)
(sb-bsd-sockets:socket-receive function)
(sb-bsd-sockets:socket-send function)
(sb-bsd-sockets:socket-listen function)
(sb-bsd-sockets:socket-open-p function)
(sb-bsd-sockets:socket-close function)
(sb-bsd-sockets:socket-shutdown function)
(sb-bsd-sockets:socket-make-stream function)
(sb-bsd-sockets:socket-error function)
(sb-bsd-sockets:non-blocking-mode function))
(defsection @socket-options (:title "Socket Options")
"A subset of socket options are supported, using a fairly general
framework which should make it simple to add more as required -- see
`\\\\SYS:CONTRIB;SB-BSD-SOCKETS:SOCKOPT.LISP` for details. The name
mapping from C is fairly straightforward: `\\\\SO_RCVLOWAT` becomes
SB-BSD-SOCKETS:SOCKOPT-RECEIVE-LOW-WATER and `(SETF
SB-BSD-SOCKETS:SOCKOPT-RECEIVE-LOW-WATER)`."
(sb-bsd-sockets:sockopt-reuse-address function)
(sb-bsd-sockets:sockopt-keep-alive function)
(sb-bsd-sockets:sockopt-oob-inline function)
(sb-bsd-sockets:sockopt-bsd-compatible function)
(sb-bsd-sockets:sockopt-pass-credentials function)
(sb-bsd-sockets:sockopt-debug function)
(sb-bsd-sockets:sockopt-dont-route function)
(sb-bsd-sockets:sockopt-broadcast function)
(sb-bsd-sockets:sockopt-tcp-nodelay function))
(defsection @inet-domain-sockets (:title "INET Domain Sockets")
"The TCP and UDP sockets that you know and love. Some representation
issues:
- IPv4 Internet addresses are represented by vectors of
`(UNSIGNED-BYTE 8)` (e.g. `#(127 0 0 1)`). Ports are just
integers. No conversion between network- and host-order data is
needed from the user of this package.
- IPv6 Internet addresses are represented by length 16 vectors of
`(UNSIGNED-BYTE 8)` (e.g. `#(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1)`.
Ports are just integers. As for IPv4 addresses, no conversion
between network- and host-order data is needed from the user of
this package.
- Socket addresses are represented by the two values for address and
port, so for example, `(SB-BSD-SOCKETS:SOCKET-CONNECT SOCKET #(192
168 1 1) 80)` for IPv4 and `(SB-BSD-SOCKETS:SOCKET-CONNECT SOCKET
#(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1) 80)` for IPv6."
(sb-bsd-sockets:inet-socket class)
(sb-bsd-sockets:inet6-socket class)
(sb-bsd-sockets:make-inet-address function)
(sb-bsd-sockets:make-inet6-address function)
(sb-bsd-sockets:get-protocol-by-name function))
#-win32
(defsection @local-domain-sockets (:title "Local Domain Sockets")
"Local domain (`\\\\AF_LOCAL`) sockets are also known as Unix-domain
sockets but were renamed by POSIX presumably on the basis that they
may be available on other systems too.
A local socket address is a string, which is used to create a node
in the local filesystem. This means of course that they cannot be
used across a network."
(sb-bsd-sockets:local-socket class)
"A local abstract socket address is also a string the scope of which is
the local machine. However, in contrast to a local socket address, there
is no corresponding filesystem node."
(sb-bsd-sockets:local-abstract-socket class))
(defsection @name-service (:title "Name Service")
"Presently name service is implemented by calling out to the
`getaddrinfo(3)` and `gethostinfo(3)`, or to `gethostbyname(3)` and
`gethostbyaddr(3)` on platforms where the preferred functions are
not available. The exact details of the name resolving process (for
example the choice of whether DNS or a hosts file is used for
lookup) are platform dependent."
;; Direct links to the asynchronous `resolver(3)` routines would be
;; nice to have eventually, so that we can do DNS lookups in
;; parallel with other things.
(sb-bsd-sockets:host-ent class)
(sb-bsd-sockets:get-host-by-name function)
(sb-bsd-sockets:get-host-by-address function)
(sb-bsd-sockets:host-ent-address function))

View file

@ -67,14 +67,14 @@
(defun get-host-by-name (host-name)
"Returns a HOST-ENT instance for HOST-NAME or signals a NAME-SERVICE-ERROR.
HOST-NAME may also be an IP address in dotted quad notation or some other
weird stuff - see gethostbyname(3) for the details."
weird stuff -- see `gethostbyname(3)` for the details."
(sb-int:with-system-mutex (**gethostby-lock** :allow-with-interrupts t)
(make-host-ent (sockint::gethostbyname host-name))))
(defun get-host-by-address (address)
"Returns a HOST-ENT instance for ADDRESS, which should be a vector of
(integer 0 255), or signals a NAME-SERVICE-ERROR. See gethostbyaddr(3)
for details."
`(INTEGER 0 255)`, or signals a NAME-SERVICE-ERROR. See
`gethostbyaddr(3)` for details."
(sb-int:with-system-mutex (**gethostby-lock** :allow-with-interrupts t)
(sockint::with-in-addr packed-addr ()
(let ((addr-vector (coerce address 'vector)))

View file

@ -58,23 +58,22 @@ peer."))
"Close SOCKET, unless it was already closed.
If SOCKET-MAKE-STREAM has been called, calls CLOSE using ABORT on that
stream. Otherwise closes the socket file descriptor using
close(2)."))
stream. Otherwise closes the socket file descriptor using `close(2)`."))
(defgeneric socket-bind (socket &rest address)
(:documentation
"Bind SOCKET to ADDRESS, which may vary according to socket family.
For the INET family, pass ADDRESS and PORT as two arguments; for FILE
address family sockets, pass the filename string. See also bind(2)"))
For the INET family, pass ADDRESS and PORT as two arguments; for local
address family sockets, pass the filename string. See also `bind(2)`."))
(defgeneric socket-accept (socket)
(:documentation
"Perform the accept(2) call, returning a newly-created connected
"Perform the `accept(2)` call, returning a newly-created connected
socket and the peer address as multiple values"))
(defgeneric socket-connect (socket &rest address)
(:documentation
"Perform the connect(2) call to connect SOCKET to a remote PEER.
"Perform the `connect(2)` call to connect SOCKET to a remote PEER.
No useful return value."))
(defgeneric socket-receive (socket buffer length
@ -82,13 +81,13 @@ No useful return value."))
oob peek waitall dontwait element-type)
(:documentation
"Read LENGTH octets from SOCKET into BUFFER (or a freshly-consed
buffer if NIL), using recvfrom(2). If LENGTH is NIL, the length of
buffer if NIL), using `recvfrom(2)`. If LENGTH is NIL, the length of
BUFFER is used, so at least one of these two arguments must be
non-NIL. If BUFFER is supplied, it had better be of an element type
one octet wide. Returns the buffer, its length, and the address of the
peer that sent it, as multiple values. On datagram sockets, sets
MSG_TRUNC so that the actual packet length is returned even if the
buffer was too small."))
`\\\\MSG_TRUNC` so that the actual packet length is returned even if
the buffer was too small."))
(defgeneric socket-send (socket buffer length
&key
@ -97,12 +96,12 @@ buffer was too small."))
oob eor dontroute dontwait nosignal
#+linux confirm #+linux more)
(:documentation
"Send LENGTH octets from BUFFER into SOCKET, using sendto(2). If
"Send LENGTH octets from BUFFER into SOCKET, using `sendto(2)`. If
BUFFER is a string, it will converted to octets according to
EXTERNAL-FORMAT. If LENGTH is NIL, the length of the octet buffer is
used. The format of ADDRESS depends on the socket type (for example
for INET domain sockets it would be a list of an IP address and a
port). If no socket address is provided, send(2) will be called
port). If no socket address is provided, `send(2)` will be called
instead. Returns the number of octets written."))
(defgeneric socket-listen (socket backlog)
@ -110,7 +109,7 @@ instead. Returns the number of octets written."))
"Mark SOCKET as willing to accept incoming connections. The
integer BACKLOG defines the maximum length that the queue of pending
connections may grow to before new connection attempts are refused.
See also listen(2)"))
See also `listen(2)`."))
(defgeneric socket-shutdown (socket &key direction)
(:documentation

View file

@ -1,192 +1,368 @@
@node Networking
@comment node-name, next, previous, up
@c Generated by the sb-manual contrib. Do not edit.
@node networking
@chapter Networking
@cindex Sockets, Networking
@menu
* Sockets Overview: sockets overview.
* General Sockets: general sockets.
* Socket Options: socket options.
* INET Domain Sockets: inet domain sockets.
* Local Domain Sockets: local domain sockets.
* Name Service: name service.
@end menu
The @code{sb-bsd-sockets} module provides a thinly disguised BSD
socket API for SBCL. Ideas have been stolen from the BSD socket API
for C and Graham Barr's IO::Socket classes for Perl.
for C and Graham Barr's @code{IO::Socket} classes for Perl.
Sockets are represented as CLOS objects, and the API naming
conventions attempt to balance between the BSD names and good lisp style.
conventions attempt to balance between the BSD names and good lisp
style.
@menu
* Sockets Overview::
* General Sockets:: Methods applicable to all sockets
* Socket Options::
* INET Domain Sockets::
* Local (Unix) Domain Sockets::
* Name Service::
@end menu
@node Sockets Overview
@node sockets overview
@section Sockets Overview
Most of the functions are modelled on the BSD socket API. BSD sockets
are widely supported, portably @emph{(``portable'' by Unix standards, at least)}
available on a variety of systems, and documented. There are some
Most of the functions are modelled on the BSD socket API. BSD sockets
are widely supported, portably (by Unix standards, at least)
available on a variety of systems, and documented. There are some
differences in approach where we have taken advantage of some of the
more useful features of Common Lisp - briefly:
more useful features of Common Lisp -- briefly:
@itemize
@item Where the C API would typically return -1 and set @code{errno},
@code{sb-bsd-sockets} signals an error. All the errors are subclasses
of @code{sb-bsd-sockets:socket-error} and generally correspond one for
one with possible @code{errno} values.
@item
Where the C API would typically return -1 and set @code{errno},
@code{sb-bsd-sockets} signals an error. All the errors are subclasses
of @code{sb-bsd-sockets:socket-condition} and generally correspond one
for one with possible @code{errno} values.
@item We use multiple return values in many places where the C API would
use pass-by-reference values.
@item
We use multiple return values in many places where the C API would use
pass-by-reference values.
@item
We can often avoid supplying an explicit @emph{length} argument to
functions because we already know how long the argument is.
@item
IP addresses and ports are represented in slightly friendlier fashion
than "network-endian integers".
@item We can often avoid supplying an explicit length argument to
functions because we already know how long the argument is.
@item IP addresses and ports are represented in slightly friendlier
fashion than "network-endian integers".
@end itemize
@node General Sockets
@node general sockets
@section General Sockets
@include class-sb-bsd-sockets-socket.texinfo
@anchor{Class sb-bsd-sockets socket}
@ttindex @sortas{socket sb-bsd-sockets} socket [sb-bsd-sockets]
@deffn{Class} sb-bsd-sockets:socket
Common superclass of all sockets, not meant to be
directly instantiated.
@end deffn
@anchor{Function sb-bsd-sockets socket-bind}
@ffindex @sortas{socket-bind sb-bsd-sockets} socket-bind [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-bind socket &rest address
Bind @code{socket} to @code{address}, which may vary according to socket family.
For the INET family, pass @code{address} and @code{port} as two arguments; for local
address family sockets, pass the filename string. See also @code{bind(2)}.
@end deffn
@anchor{Function sb-bsd-sockets socket-accept}
@ffindex @sortas{socket-accept sb-bsd-sockets} socket-accept [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-accept socket
Perform the @code{accept(2)} call, returning a newly-created connected
socket and the peer address as multiple values
@end deffn
@anchor{Function sb-bsd-sockets socket-connect}
@ffindex @sortas{socket-connect sb-bsd-sockets} socket-connect [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-connect socket &rest address
Perform the @code{connect(2)} call to connect @code{socket} to a remote @code{peer}.
No useful return value.
@end deffn
@anchor{Function sb-bsd-sockets socket-peername}
@ffindex @sortas{socket-peername sb-bsd-sockets} socket-peername [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-peername socket
Return @code{socket}'s peer; depending on the address family this may
return multiple values
@end deffn
@anchor{Function sb-bsd-sockets socket-name}
@ffindex @sortas{socket-name sb-bsd-sockets} socket-name [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-name socket
Return the address (as vector of bytes) and port that @code{socket} is
bound to, as multiple values.
@end deffn
@anchor{Function sb-bsd-sockets socket-receive}
@ffindex @sortas{socket-receive sb-bsd-sockets} socket-receive [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-receive socket buffer length &key oob peek waitall dontwait element-type
Read @code{length} octets from @code{socket} into @code{buffer} (or a freshly-consed
buffer if @code{nil}), using @code{recvfrom(2)}. If @code{length} is @code{nil}, the length of
@code{buffer} is used, so at least one of these two arguments must be
non-@code{nil}. If @code{buffer} is supplied, it had better be of an element type
one octet wide. Returns the buffer, its length, and the address of the
peer that sent it, as multiple values. On datagram sockets, sets
@code{MSG_TRUNC} so that the actual packet length is returned even if
the buffer was too small.
@end deffn
@anchor{Function sb-bsd-sockets socket-send}
@ffindex @sortas{socket-send sb-bsd-sockets} socket-send [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-send socket buffer length &key address external-format oob eor dontroute dontwait nosignal confirm more
Send @code{length} octets from @code{buffer} into @code{socket}, using @code{sendto(2)}. If
@code{buffer} is a string, it will converted to octets according to
@code{external-format}. If @code{length} is @code{nil}, the length of the octet buffer is
used. The format of @code{address} depends on the socket type (for example
for INET domain sockets it would be a list of an IP address and a
port). If no socket address is provided, @code{send(2)} will be called
instead. Returns the number of octets written.
@end deffn
@anchor{Function sb-bsd-sockets socket-listen}
@ffindex @sortas{socket-listen sb-bsd-sockets} socket-listen [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-listen socket backlog
Mark @code{socket} as willing to accept incoming connections. The
integer @code{backlog} defines the maximum length that the queue of pending
connections may grow to before new connection attempts are refused.
See also @code{listen(2)}.
@end deffn
@anchor{Function sb-bsd-sockets socket-open-p}
@ffindex @sortas{socket-open-p sb-bsd-sockets} socket-open-p [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-open-p socket
Return true if @code{socket} is open; otherwise, return false.
@end deffn
@anchor{Function sb-bsd-sockets socket-close}
@ffindex @sortas{socket-close sb-bsd-sockets} socket-close [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-close socket &key abort
Close @code{socket}, unless it was already closed.
@include fun-sb-bsd-sockets-socket-bind.texinfo
If @code{socket-make-stream} has been called, calls @code{close} using @code{abort} on that
stream. Otherwise closes the socket file descriptor using @code{close(2)}.
@end deffn
@anchor{Function sb-bsd-sockets socket-shutdown}
@ffindex @sortas{socket-shutdown sb-bsd-sockets} socket-shutdown [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-shutdown socket &key direction
Indicate that no communication in @code{direction} will be performed on
@code{socket}.
@include fun-sb-bsd-sockets-socket-accept.texinfo
@code{direction} has to be one of @code{:input}, @code{:output} or @code{:io}.
@include fun-sb-bsd-sockets-socket-connect.texinfo
After a shutdown, no input and/or output of the indicated @code{direction}
can be performed on @code{socket}.
@end deffn
@anchor{Function sb-bsd-sockets socket-make-stream}
@ffindex @sortas{socket-make-stream sb-bsd-sockets} socket-make-stream [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-make-stream socket &key input output element-type external-format buffering timeout auto-close serve-events
Find or create a @code{stream} that can be used for IO on @code{socket} (which
must be connected). Specify whether the stream is for @code{input}, @code{output},
or both (it is an error to specify neither).
@include fun-sb-bsd-sockets-socket-peername.texinfo
@code{element-type} and @code{external-format} are as per @code{open}.
@include fun-sb-bsd-sockets-socket-name.texinfo
@code{timeout} specifies a read timeout for the stream.
@end deffn
@anchor{Function sb-bsd-sockets socket-error}
@ffindex @sortas{socket-error sb-bsd-sockets} socket-error [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:socket-error where &optional errno
Signal an appropriate error for syscall @code{where} and @code{errno}.
@include fun-sb-bsd-sockets-socket-receive.texinfo
@code{where} should be a string naming the failed function.
@include fun-sb-bsd-sockets-socket-send.texinfo
@include fun-sb-bsd-sockets-socket-listen.texinfo
@include fun-sb-bsd-sockets-socket-open-p.texinfo
@include fun-sb-bsd-sockets-socket-close.texinfo
@include fun-sb-bsd-sockets-socket-shutdown.texinfo
@include fun-sb-bsd-sockets-socket-make-stream.texinfo
@include fun-sb-bsd-sockets-socket-error.texinfo
@include fun-sb-bsd-sockets-non-blocking-mode.texinfo
@node Socket Options
When supplied, @code{errno} should be the UNIX error number associated to the
failed call. The default behavior is to use the current value of the
errno variable.
@end deffn
@anchor{Function sb-bsd-sockets non-blocking-mode}
@ffindex @sortas{non-blocking-mode sb-bsd-sockets} non-blocking-mode [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:non-blocking-mode socket
Is @code{socket} in non-blocking mode?
@end deffn
@node socket options
@section Socket Options
A subset of socket options are supported, using a fairly general
framework which should make it simple to add more as required - see
@file{SYS:CONTRIB;SB-BSD-SOCKETS:SOCKOPT.LISP} for details. The name
framework which should make it simple to add more as required -- see
@code{SYS:CONTRIB;SB-BSD-SOCKETS:SOCKOPT.LISP} for details. The name
mapping from C is fairly straightforward: @code{SO_RCVLOWAT} becomes
@code{sockopt-receive-low-water} and @code{(setf
sockopt-receive-low-water)}.
@code{sb-bsd-sockets:sockopt-receive-low-water} and @code{(setf
sb-bsd-sockets:sockopt-receive-low-water)}.
@include fun-sb-bsd-sockets-sockopt-reuse-address.texinfo
@include fun-sb-bsd-sockets-sockopt-keep-alive.texinfo
@include fun-sb-bsd-sockets-sockopt-oob-inline.texinfo
@include fun-sb-bsd-sockets-sockopt-bsd-compatible.texinfo
@include fun-sb-bsd-sockets-sockopt-pass-credentials.texinfo
@include fun-sb-bsd-sockets-sockopt-debug.texinfo
@include fun-sb-bsd-sockets-sockopt-dont-route.texinfo
@include fun-sb-bsd-sockets-sockopt-broadcast.texinfo
@include fun-sb-bsd-sockets-sockopt-tcp-nodelay.texinfo
@node INET Domain Sockets
@anchor{Function sb-bsd-sockets sockopt-reuse-address}
@ffindex @sortas{sockopt-reuse-address sb-bsd-sockets} sockopt-reuse-address [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:sockopt-reuse-address socket
Return the value of the SO-REUSEADDR socket option for @code{socket}. This can also be
updated with @code{setf}.
@end deffn
@anchor{Function sb-bsd-sockets sockopt-keep-alive}
@ffindex @sortas{sockopt-keep-alive sb-bsd-sockets} sockopt-keep-alive [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:sockopt-keep-alive socket
Return the value of the SO-KEEPALIVE socket option for @code{socket}. This can also be
updated with @code{setf}.
@end deffn
@anchor{Function sb-bsd-sockets sockopt-oob-inline}
@ffindex @sortas{sockopt-oob-inline sb-bsd-sockets} sockopt-oob-inline [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:sockopt-oob-inline socket
Return the value of the SO-OOBINLINE socket option for @code{socket}. This can also be
updated with @code{setf}.
@end deffn
@anchor{Function sb-bsd-sockets sockopt-bsd-compatible}
@ffindex @sortas{sockopt-bsd-compatible sb-bsd-sockets} sockopt-bsd-compatible [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:sockopt-bsd-compatible socket
Return the value of the SO-BSDCOMPAT socket option for @code{socket}. This can also be
updated with @code{setf}. Available only on Linux.
@end deffn
@anchor{Function sb-bsd-sockets sockopt-pass-credentials}
@ffindex @sortas{sockopt-pass-credentials sb-bsd-sockets} sockopt-pass-credentials [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:sockopt-pass-credentials socket
Return the value of the SO-PASSCRED socket option for @code{socket}. This can also be
updated with @code{setf}. Available only on Linux.
@end deffn
@anchor{Function sb-bsd-sockets sockopt-debug}
@ffindex @sortas{sockopt-debug sb-bsd-sockets} sockopt-debug [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:sockopt-debug socket
Return the value of the SO-DEBUG socket option for @code{socket}. This can also be
updated with @code{setf}.
@end deffn
@anchor{Function sb-bsd-sockets sockopt-dont-route}
@ffindex @sortas{sockopt-dont-route sb-bsd-sockets} sockopt-dont-route [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:sockopt-dont-route socket
Return the value of the SO-DONTROUTE socket option for @code{socket}. This can also be
updated with @code{setf}.
@end deffn
@anchor{Function sb-bsd-sockets sockopt-broadcast}
@ffindex @sortas{sockopt-broadcast sb-bsd-sockets} sockopt-broadcast [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:sockopt-broadcast socket
Return the value of the SO-BROADCAST socket option for @code{socket}. This can also be
updated with @code{setf}.
@end deffn
@anchor{Function sb-bsd-sockets sockopt-tcp-nodelay}
@ffindex @sortas{sockopt-tcp-nodelay sb-bsd-sockets} sockopt-tcp-nodelay [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:sockopt-tcp-nodelay socket
Return the value of the TCP-NODELAY socket option for @code{socket}. This can also be
updated with @code{setf}.
@end deffn
@node inet domain sockets
@section INET Domain Sockets
The TCP and UDP sockets that you know and love. Some representation
issues:
@itemize
@item IPv4 Internet addresses are represented by vectors of
@code{(unsigned-byte 8)} (e.g. @code{#(127 0 0 1)}). Ports are just
integers. No conversion between network- and host-order data is
needed from the user of this package.
@item
IPv4 Internet addresses are represented by vectors of
@code{(unsigned-byte 8)} - viz. @code{#(127 0 0 1)}. Ports are just
integers: 6010. No conversion between network- and host-order data is
needed from the user of this package.
@item
IPv6 Internet addresses are represented by vectors of 16
@code{(unsigned-byte 8)} - viz. @code{#(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1)}. Ports are just integers. As for IPv4 addresses, no conversion
between network- and host-order data is needed from the user of this
package.
@item
Socket addresses are represented by the two values for address and port,
so for example, @code{(socket-connect socket #(192 168 1 1) 80)} for
IPv4 and @code{(socket-connect socket #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1)
80)} for IPv6.
@item IPv6 Internet addresses are represented by length 16 vectors of
@code{(unsigned-byte 8)} (e.g. @code{#(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1)}.
Ports are just integers. As for IPv4 addresses, no conversion
between network- and host-order data is needed from the user of
this package.
@item Socket addresses are represented by the two values for address and
port, so for example, @code{(sb-bsd-sockets:socket-connect socket #(192
168 1 1) 80)} for IPv4 and @code{(sb-bsd-sockets:socket-connect socket
#(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1) 80)} for IPv6.
@end itemize
@include class-sb-bsd-sockets-inet-socket.texinfo
@anchor{Class sb-bsd-sockets inet-socket}
@ttindex @sortas{inet-socket sb-bsd-sockets} inet-socket [sb-bsd-sockets]
@deffn{Class} sb-bsd-sockets:inet-socket
Class representing TCP and UDP over IPv4 sockets.
@include class-sb-bsd-sockets-inet6-socket.texinfo
Examples:
@include fun-sb-bsd-sockets-make-inet-address.texinfo
@example
(make-instance 'sb-bsd-sockets:inet-socket :type :stream :protocol :tcp)
@include fun-sb-bsd-sockets-make-inet6-address.texinfo
(make-instance 'sb-bsd-sockets:inet-socket :type :datagram :protocol :udp)
@end example
@end deffn
@anchor{Class sb-bsd-sockets inet6-socket}
@ttindex @sortas{inet6-socket sb-bsd-sockets} inet6-socket [sb-bsd-sockets]
@deffn{Class} sb-bsd-sockets:inet6-socket
Class representing TCP and UDP over IPv6 sockets.
@include fun-sb-bsd-sockets-get-protocol-by-name.texinfo
Examples:
@node Local (Unix) Domain Sockets
@section Local (Unix) Domain Sockets
@example
(make-instance 'sb-bsd-sockets:inet6-socket :type :stream :protocol :tcp)
(make-instance 'sb-bsd-sockets:inet6-socket :type :datagram :protocol :udp)
@end example
@end deffn
@anchor{Function sb-bsd-sockets make-inet-address}
@ffindex @sortas{make-inet-address sb-bsd-sockets} make-inet-address [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:make-inet-address dotted-quads
Return a vector of octets given a string @code{dotted-quads} in the format
"127.0.0.1". Signals an error if the string is malformed.
@end deffn
@anchor{Function sb-bsd-sockets make-inet6-address}
@ffindex @sortas{make-inet6-address sb-bsd-sockets} make-inet6-address [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:make-inet6-address colon-separated-integers
Return a vector of octets given a string representation of an IPv6
address @code{colon-separated-integers}. Signal an error if the string is
malformed.
@end deffn
@anchor{Function sb-bsd-sockets get-protocol-by-name}
@ffindex @sortas{get-protocol-by-name sb-bsd-sockets} get-protocol-by-name [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:get-protocol-by-name name
Given a protocol name, return the protocol number, the protocol name, and
a list of protocol aliases.
@end deffn
@node local domain sockets
@section Local Domain Sockets
Local domain (@code{AF_LOCAL}) sockets are also known as Unix-domain
sockets, but were renamed by POSIX presumably on the basis that they
sockets but were renamed by POSIX presumably on the basis that they
may be available on other systems too.
A local socket address is a string, which is used to create a node in
the local filesystem. This means of course that they cannot be used
across a network.
@include class-sb-bsd-sockets-local-socket.texinfo
A local socket address is a string, which is used to create a node
in the local filesystem. This means of course that they cannot be
used across a network.
@anchor{Class sb-bsd-sockets local-socket}
@ttindex @sortas{local-socket sb-bsd-sockets} local-socket [sb-bsd-sockets]
@deffn{Class} sb-bsd-sockets:local-socket
Class representing local domain (@code{AF_LOCAL}) sockets,
also known as Unix-domain sockets.
@end deffn
A local abstract socket address is also a string the scope of which is
the local machine. However, in contrast to a local socket address, there
is no corresponding filesystem node.
@include class-sb-bsd-sockets-local-abstract-socket.texinfo
@node Name Service
@anchor{Class sb-bsd-sockets local-abstract-socket}
@ttindex @sortas{local-abstract-socket sb-bsd-sockets} local-abstract-socket [sb-bsd-sockets]
@deffn{Class} sb-bsd-sockets:local-abstract-socket
Class representing local domain (@code{AF_LOCAL}) sockets with
addresses in the abstract namespace.
@end deffn
@node name service
@section Name Service
Presently name service is implemented by calling out to the
@code{getaddrinfo(3)} and @code{gethostinfo(3)}, or to
@code{gethostbyname(3)} @code{gethostbyaddr(3)} on platforms where
the preferred functions are not available. The exact details of
the name resolving process (for example the choice of whether
DNS or a hosts file is used for lookup) are platform dependent.
@code{getaddrinfo(3)} and @code{gethostinfo(3)}, or to @code{gethostbyname(3)} and
@code{gethostbyaddr(3)} on platforms where the preferred functions are
not available. The exact details of the name resolving process (for
example the choice of whether DNS or a hosts file is used for
lookup) are platform dependent.
@c Direct links to the asynchronous @code{resolver(3)} routines would be
@c nice to have eventually, so that we can do DNS lookups in parallel
@c with other things.
@anchor{Class sb-bsd-sockets host-ent}
@ttindex @sortas{host-ent sb-bsd-sockets} host-ent [sb-bsd-sockets]
@deffn{Class} sb-bsd-sockets:host-ent
This class represents the results of an address lookup.
@end deffn
@anchor{Function sb-bsd-sockets get-host-by-name}
@ffindex @sortas{get-host-by-name sb-bsd-sockets} get-host-by-name [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:get-host-by-name host-name
Returns a @code{host-ent} instance for @code{host-name} or signals a @code{name-service-error}.
@include class-sb-bsd-sockets-host-ent.texinfo
Another @code{host-ent} instance containing zero, one or more IPv6 addresses
may be returned as a second return value.
@include fun-sb-bsd-sockets-get-host-by-name.texinfo
@include fun-sb-bsd-sockets-get-host-by-address.texinfo
@include fun-sb-bsd-sockets-host-ent-address.texinfo
@code{host-name} may also be an IP address in dotted quad notation or some other
weird stuff - see getaddrinfo(3) for the details.
@end deffn
@anchor{Function sb-bsd-sockets get-host-by-address}
@ffindex @sortas{get-host-by-address sb-bsd-sockets} get-host-by-address [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:get-host-by-address address
Returns a @code{host-ent} instance for @code{address}, which should be a vector of
(integer 0 255) with 4 elements in case of an IPv4 address and 16
elements in case of an IPv6 address, or signals a @code{name-service-error}.
See gethostbyaddr(3) for details.
@end deffn
@anchor{Function sb-bsd-sockets host-ent-address}
@ffindex @sortas{host-ent-address sb-bsd-sockets} host-ent-address [sb-bsd-sockets]
@deffn{Function} sb-bsd-sockets:host-ent-address host-ent
Return some valid address for @code{host-ent}.
@end deffn

View file

@ -52,7 +52,10 @@ Code for options that not every system has should be conditionalised:
`(progn
(export ',lisp-name)
(defun ,lisp-name (socket)
,@(when documentation (list (concatenate 'string documentation " " info)))
,@(when documentation
(list (if (plusp (length info))
(format nil "~A ~A" documentation info)
documentation)))
,@(if supportedp
`((sb-alien:with-alien ((size sb-alien:int)
(buffer ,buffer-type))
@ -135,9 +138,9 @@ Code for options that not every system has should be conditionalised:
(defmacro define-socket-option-bool (name level c-name &optional features (info ""))
`(define-socket-option ,name
,(format nil "~@<Return the value of the ~A socket option for SOCKET. ~
,(format nil "~@<Return the value of the ~A socket option for SOCKET. ~
This can also be updated with SETF.~:@>"
(symbol-name c-name))
(symbol-name c-name))
,level ,c-name
sb-alien:int bool-to-foreign-int foreign-int-to-bool sb-alien:addr
,features ,info))

View file

@ -180,18 +180,14 @@ Note that the global function binding may differ from the local one.
This function returns three values. The first indicates the type of
function definition or binding:
NIL
There is no apparent definition for NAME.
- NIL: There is no apparent definition for NAME.
:FUNCTION
NAME refers to a function.
- :FUNCTION: NAME refers to a function.
:MACRO
NAME refers to a macro.
- :MACRO: NAME refers to a macro.
:SPECIAL-FORM
NAME refers to a special operator. If the name refers to both a
macro and a special operator, the macro takes precedence.
- :SPECIAL-FORM: NAME refers to a special operator. If the name refers
to both a macro and a special operator, the macro takes precedence.
The second value is true if NAME is bound locally.
@ -199,26 +195,23 @@ The third value is an alist describing the declarations that apply to
the function NAME. Standard declaration specifiers that may appear in
CARS of the alist include:
DYNAMIC-EXTENT
If the CDR is T, NAME has been declared DYNAMIC-EXTENT. If the CDR
is NIL, the alist element may be omitted.
- DYNAMIC-EXTENT: If the CDR is T, NAME has been declared
DYNAMIC-EXTENT. If the CDR is NIL, the alist element may be omitted.
INLINE
The CDR is one of the symbols INLINE, NOTINLINE, or NIL, to
indicate if the function has been declared INLINE or NOTINLINE. If
the CDR is NIL the alist element may be omitted.
- INLINE: The CDR is one of the symbols INLINE, NOTINLINE, or NIL, to
indicate if the function has been declared INLINE or NOTINLINE. If
the CDR is NIL the alist element may be omitted.
FTYPE
The CDR is the type specifier associated with NAME, or the symbol
FUNCTION if there is functional type declaration or proclamation
associated with NAME. If the CDR is FUNCTION the alist element may
be omitted.
- FTYPE: The CDR is the type specifier associated with NAME, or the
symbol FUNCTION if there is functional type declaration or
proclamation associated with NAME. If the CDR is FUNCTION the alist
element may be omitted.
SB-EXT:DEPRECATED
\(SBCL specific)
The CDR is a plist containing the following properties
- SB-EXT:DEPRECATED: (SBCL specific) The CDR is a plist containing the
following properties:
- :STATE ( :EARLY | :LATE | :FINAL )
:STATE ( :EARLY | :LATE | :FINAL )
Use of :EARLY deprecated functions signals a STYLE-WARNING at
compile-time.
@ -228,14 +221,16 @@ CARS of the alist include:
Use of :FINAL deprecated functions signals a full WARNING at
compile-time and an error at runtime.
:SINCE (SOFTWARE VERSION)
VERSION is a string designating the version since which the
function has been deprecated. SOFTWARE is NIL or the name of
the software to which VERSION refers, e.g. \"SBCL\" for
- :SINCE `(SOFTWARE VERSION)`
`VERSION` is a string designating the version since which the
function has been deprecated. `SOFTWARE` is NIL or the name of
the software to which `VERSION` refers, e.g. `\"SBCL\"` for
deprecated functions in SBCL.
:REPLACEMENTS REPLACEMENTS
When this property is present, REPLACEMENTS is a list of
- :REPLACEMENTS `REPLACEMENTS`
When this property is present, `REPLACEMENTS` is a list of
symbols naming functions that should be used instead of the
deprecated function.
@ -314,27 +309,20 @@ Note that the global binding may differ from the local one.
This function returns three values. The first indicated the type of the variable
binding:
NIL
There is no apparent binding for NAME.
- NIL: There is no apparent binding for NAME.
:SPECIAL
NAME refers to a special variable.
- :SPECIAL: NAME refers to a special variable.
:LEXICAL
NAME refers to a lexical variable.
- :LEXICAL: NAME refers to a lexical variable.
:SYMBOL-MACRO
NAME refers to a symbol macro.
- :SYMBOL-MACRO: NAME refers to a symbol macro.
:CONSTANT
NAME refers to a named constant defined using DEFCONSTANT, or NAME
is a keyword.
- :CONSTANT: NAME refers to a named constant defined using
DEFCONSTANT, or NAME is a keyword.
:GLOBAL
NAME refers to a global variable. (SBCL specific extension.)
- :GLOBAL: NAME refers to a global variable. (SBCL specific extension.)
:ALIEN
NAME refers to an alien variable. (SBCL specific extension.)
- :ALIEN NAME refers to an alien variable. (SBCL specific extension.)
The second value is true if NAME is bound locally. This is currently
always NIL for special variables, although arguably it should be T
@ -344,30 +332,26 @@ The third value is an alist describing the declarations that apply to
the function NAME. Standard declaration specifiers that may appear in
CARS of the alist include:
DYNAMIC-EXTENT
If the CDR is T, NAME has been declared DYNAMIC-EXTENT. If the CDR
is NIL, the alist element may be omitted.
- DYNAMIC-EXTENT: If the CDR is T, NAME has been declared
DYNAMIC-EXTENT. If the CDR is NIL, the alist element may be omitted.
IGNORE
If the CDR is T, NAME has been declared IGNORE. If the CDR is NIL,
the alist element may be omitted.
- IGNORE: If the CDR is T, NAME has been declared IGNORE. If the CDR
is NIL, the alist element may be omitted.
TYPE
The CDR is the type specifier associated with NAME, or the symbol
T if there is explicit type declaration or proclamation associated
with NAME. The type specifier may be equivalent to or a supertype
of the original declaration. If the CDR is T the alist element may
be omitted.
- TYPE: The CDR is the type specifier associated with NAME, or the
symbol T if there is explicit type declaration or proclamation
associated with NAME. The type specifier may be equivalent to or a
supertype of the original declaration. If the CDR is T the alist
element may be omitted.
SB-EXT:ALWAYS-BOUND
\(SBCL specific)
If CDR is T, NAME has been declared as SB-EXT:ALWAYS-BOUND
- SB-EXT:ALWAYS-BOUND: (SBCL specific) If CDR is T, NAME has been
declared as SB-EXT:ALWAYS-BOUND.
SB-EXT:DEPRECATED
\(SBCL specific)
The CDR is a plist containing the following properties
- SB-EXT:DEPRECATED: (SBCL specific) The CDR is a plist containing the
following properties:
- :STATE ( :EARLY | :LATE | :FINAL )
:STATE ( :EARLY | :LATE | :FINAL )
Use of :EARLY deprecated variables signals a STYLE-WARNING at
compile-time.
@ -377,14 +361,16 @@ CARS of the alist include:
Use of :FINAL deprecated variables signals a full WARNING at
compile-time and an error at runtime.
:SINCE (SOFTWARE VERSION)
VERSION is a string designating the version since which the
variable has been deprecated. SOFTWARE is NIL or the name of
the software to which VERSION refers, e.g. \"SBCL\" for
- :SINCE `(SOFTWARE VERSION)`
`VERSION` is a string designating the version since which the
variable has been deprecated. `SOFTWARE` is NIL or the name of
the software to which `VERSION` refers, e.g. `\"SBCL\"` for
deprecated variables in SBCL.
:REPLACEMENTS REPLACEMENTS
When this property is present, REPLACEMENTS is a list of
- :REPLACEMENTS `REPLACEMENTS`
When this property is present, `REPLACEMENTS` is a list of
symbols naming variables that should be used instead of the
deprecated variable.

View file

@ -101,31 +101,30 @@ Readers gain entry to protected regions without waiting, but need to retry if
a writer operated inside the region while they were reading. This makes frlocks
very efficient when readers are much more common than writers.
FRlocks are NOT suitable when it is not safe at all for readers and writers to
operate on the same data in parallel: they provide consistency, not exclusion
between readers and writers. Hence using an frlock to eg. protect an SBCL
hash-table is unsafe. If multiple readers operating in parallel with a writer
would be safe but inconsistent without a lock, frlocks are suitable.
FRlocks are _not_ suitable when it is not safe at all for readers and writers
to operate on the same data in parallel: they provide consistency, not
exclusion between readers and writers. Hence using an frlock to e.g. protect
an SBCL hash-table is unsafe. If multiple readers operating in parallel with
a writer would be safe but inconsistent without a lock, frlocks are suitable.
The recommended interface to use is FRLOCK-READ and FRLOCK-WRITE, but those
needing it can also use a lower-level interface.
Example:
;; Values returned by FOO are always consistent so that
;; the third value is the sum of the two first ones.
(let ((a 0)
(b 0)
(c 0)
(lk (make-frlock)))
(defun foo ()
(frlock-read (lk) a b c))
(defun bar (x y)
(frlock-write (lk)
(setf a x
b y
c (+ x y)))))
"
;; Values returned by FOO are always consistent so that
;; the third value is the sum of the two first ones.
(let ((a 0)
(b 0)
(c 0)
(lk (make-frlock)))
(defun foo ()
(frlock-read (lk) a b c))
(defun bar (x y)
(frlock-write (lk)
(setf a x
b y
c (+ x y)))))"
.
#-new-frlock (
(mutex (make-mutex :name "FRLock mutex") :type mutex :read-only t)
@ -212,14 +211,13 @@ Using FRLOCK-READ instead is recommended.
Example:
(multiple-value-bind (t0 e0) (frlock-read-begin *fr*)
(let ((a (get-a))
(b (get-b)))
(multiple-value-bind (t1 e1) (frlock-read-end *fr*)
(if (and (eql t0 t1) (eql e0 e1))
(list :a a :b b)
:aborted))))
"
(multiple-value-bind (t0 e0) (frlock-read-begin *fr*)
(let ((a (get-a))
(b (get-b)))
(multiple-value-bind (t1 e1) (frlock-read-end *fr*)
(if (and (eql t0 t1) (eql e0 e1))
(list :a a :b b)
:aborted))))"
(barrier (:read))
(values (frlock-pre-counter frlock)
(frlock-epoch frlock)))
@ -247,7 +245,7 @@ set, and returns that as multiple values."
;; 0, they will still be holding on to the old epoch. While it is
;; extremely unlikely, it isn't quite "not before heath death of the
;; universe" stuff: a 30 bit counter can roll over in a couple of
;; seconds -- and a thread can easily be interrupted by eg. a timer for
;; seconds -- and a thread can easily be interrupted by e.g. a timer for
;; that long, so a pathological system could be have a thread in a
;; danger-zone every second. Run that system for a year, and it would
;; have a 1 in 3 chance of hitting the incipient bug. Adding an epoch
@ -268,7 +266,7 @@ set, and returns that as multiple values."
(defun grab-frlock-write-lock (frlock &key (wait-p t) timeout)
"Acquires FRLOCK for writing, invalidating existing and future read-tokens
for the duration. Returns T on success, and NIL if the lock wasn't acquired
due to eg. a timeout. Using FRLOCK-WRITE instead is recommended."
due to e.g. a timeout. Using FRLOCK-WRITE instead is recommended."
(without-interrupts
(allow-with-interrupts (%%grab-frlock-write-lock frlock wait-p timeout))))

View file

@ -22,7 +22,7 @@ SEND-MESSAGE adds a message to the mailbox, RECEIVE-MESSAGE waits till
a message becomes available, whereas RECEIVE-MESSAGE-NO-HANG is a non-blocking
variant, and RECEIVE-PENDING-MESSAGES empties the entire mailbox in one go.
Messages can be arbitrary objects"
Messages can be arbitrary objects."
(queue (missing-arg) :type queue)
(semaphore (missing-arg) :type semaphore)
(name nil))
@ -56,7 +56,7 @@ Messages can be arbitrary objects"
(declaim (ftype (sfunction (mailbox) unsigned-byte) mailbox-count))
(defun mailbox-count (mailbox)
"Returns the number of messages currently in the mailbox."
"Returns the number of messages currently in MAILBOX."
(semaphore-count (mailbox-semaphore mailbox)))
(declaim (ftype (sfunction (mailbox) boolean) mailbox-empty-p))
@ -66,8 +66,8 @@ Messages can be arbitrary objects"
(declaim (ftype (sfunction (mailbox) list) list-mailbox-messages))
(defun list-mailbox-messages (mailbox)
"Returns a fresh list containing all the messages in the
mailbox. Does not remove messages from the mailbox."
"Returns a fresh list containing all the messages in MAILBOX. Does not
remove messages from the mailbox."
(list-queue-contents (mailbox-queue mailbox)))
(declaim (ftype (sfunction (mailbox t) null) send-message))
@ -126,10 +126,10 @@ message could be received."
"Removes and returns all (or at most N) currently pending messages
from MAILBOX, or returns NIL if no messages are pending.
Note: Concurrent threads may be snarfing messages during the run of
this function, so even though X,Y appear right next to each other in
the result, does not necessarily mean that Y was the message sent
right after X."
> _Note_: Concurrent threads may be snarfing messages during the run
> of this function, so even `X` and `Y` appearing right next to each
> other in the result does not necessarily mean that `Y` was the
> message sent right after `X`."
(prog* ((msgs '())
(sem (mailbox-semaphore mailbox))
(queue (mailbox-queue mailbox))

View file

@ -0,0 +1,72 @@
(in-package :sb-manual)
(defsection @sb-concurrency (:title "sb-concurrency")
"Additional data structures, synchronization primitives and tools for
concurrent programming. Similiar to Java's `java.util.concurrent`
package."
(@sb-concurrency-queue section)
(@sb-concurrency-mailbox section)
(@sb-concurrency-gates section)
(@sb-concurrency-frlocks section))
(defsection @sb-concurrency-queue (:title "Queue")
"SB-CONCURRENCY:QUEUE is a lock-free, thread-safe FIFO queue
datatype.
The implementation is based on _An Optimistic Approach to Lock-Free
FIFO Queues_ by Edya Ladan-Mozes and Nir Shavit.
Before SBCL 1.0.38, this implementation resided in its own contrib
(see @SB-QUEUE), which is still provided for
backwards-compatibility, but which has since been deprecated."
(sb-concurrency:queue structure)
(sb-concurrency:dequeue function)
(sb-concurrency:enqueue function)
(sb-concurrency:list-queue-contents function)
(sb-concurrency:make-queue function)
(sb-concurrency:queue-count function)
(sb-concurrency:queue-empty-p function)
(sb-concurrency:queue-name function)
(sb-concurrency:queuep function))
(defsection @sb-concurrency-mailbox (:title "Mailbox (lock-free)")
"SB-CONCURRENCY:MAILBOX is a lock-free message queue where one or
multiple ends can send messages to one or multiple receivers. The
difference to @SB-CONCURRENCY-QUEUE is that the receiving end may
block until a message arrives.
Built on top of the @SB-CONCURRENCY-QUEUE implementation."
(sb-concurrency:mailbox structure)
(sb-concurrency:list-mailbox-messages function)
(sb-concurrency:mailbox-count function)
(sb-concurrency:mailbox-empty-p function)
(sb-concurrency:mailbox-name function)
(sb-concurrency:mailboxp function)
(sb-concurrency:make-mailbox function)
(sb-concurrency:receive-message function)
(sb-concurrency:receive-message-no-hang function)
(sb-concurrency:receive-pending-messages function)
(sb-concurrency:send-message function))
(defsection @sb-concurrency-gates (:title "Gates")
"SB-CONCURRENCY:GATE is a synchronization object suitable for when
multiple threads must wait for a single event before proceeding."
(sb-concurrency:gate structure)
(sb-concurrency:close-gate function)
(sb-concurrency:gate-name function)
(sb-concurrency:gate-open-p function)
(sb-concurrency:gatep function)
(sb-concurrency:make-gate function)
(sb-concurrency:open-gate function)
(sb-concurrency:wait-on-gate function))
(defsection @sb-concurrency-frlocks (:title "Frlocks, aka Fast Read Locks")
(sb-concurrency:frlock structure)
(sb-concurrency:frlock-read macro)
(sb-concurrency:frlock-write macro)
(sb-concurrency:make-frlock function)
(sb-concurrency:frlock-name function)
(sb-concurrency:frlock-read-begin function)
(sb-concurrency:frlock-read-end function)
(sb-concurrency:grab-frlock-write-lock function)
(sb-concurrency:release-frlock-write-lock function))

View file

@ -1,95 +1,336 @@
@node sb-concurrency
@c Generated by the sb-manual contrib. Do not edit.
@node sb concurrency
@section sb-concurrency
@cindex Concurrency
@cindex Sb-concurrency
@menu
* Queue: sb concurrency queue.
* Mailbox (lock-free): sb concurrency mailbox.
* Gates: sb concurrency gates.
* Frlocks, aka Fast Read Locks: sb concurrency frlocks.
@end menu
Additional data structures, synchronization primitives and tools for
concurrent programming. Similiar to Java's @code{java.util.concurrent}
package.
@page
@anchor{Section sb-concurrency:queue}
@node sb concurrency queue
@subsection Queue
@cindex Queue, lock-free
@code{sb-concurrency:queue} is a lock-free, thread-safe FIFO queue
datatype.
@*@*
The implementation is based on @cite{An Optimistic Approach to
Lock-Free FIFO Queues} by Edya Ladan-Mozes and Nir Shavit.
@*@*
The implementation is based on @emph{An Optimistic Approach to Lock-Free
FIFO Queues} by Edya Ladan-Mozes and Nir Shavit.
Before SBCL 1.0.38, this implementation resided in its own contrib
(@pxref{sb-queue}) which is still provided for backwards-compatibility
but which has since been deprecated.
(see @ref{sb queue}), which is still provided for
backwards-compatibility, but which has since been deprecated.
@include struct-sb-concurrency-queue.texinfo
@anchor{Structure sb-concurrency queue}
@ttindex @sortas{queue sb-concurrency} queue [sb-concurrency]
@deffn{Structure} sb-concurrency:queue
Lock-free thread safe FIFO queue.
@include fun-sb-concurrency-dequeue.texinfo
@include fun-sb-concurrency-enqueue.texinfo
@include fun-sb-concurrency-list-queue-contents.texinfo
@include fun-sb-concurrency-make-queue.texinfo
@include fun-sb-concurrency-queue-count.texinfo
@include fun-sb-concurrency-queue-empty-p.texinfo
@include fun-sb-concurrency-queue-name.texinfo
@include fun-sb-concurrency-queuep.texinfo
@page
Use @code{enqueue} to add objects to the queue, and @code{dequeue} to remove them.
@end deffn
@anchor{Function sb-concurrency dequeue}
@ffindex @sortas{dequeue sb-concurrency} dequeue [sb-concurrency]
@deffn{Function} sb-concurrency:dequeue queue
Retrieves the oldest value in @code{queue} and returns it as the primary value,
and @code{t} as secondary value. If the queue is empty, returns @code{nil} as both primary
and secondary value.
@end deffn
@anchor{Function sb-concurrency enqueue}
@ffindex @sortas{enqueue sb-concurrency} enqueue [sb-concurrency]
@deffn{Function} sb-concurrency:enqueue value queue
Adds @code{value} to the end of @code{queue}. Returns @code{value}.
@end deffn
@anchor{Function sb-concurrency list-queue-contents}
@ffindex @sortas{list-queue-contents sb-concurrency} list-queue-contents [sb-concurrency]
@deffn{Function} sb-concurrency:list-queue-contents queue
Returns the contents of @code{queue} as a list without removing them from the
@code{queue}. Mainly useful for manual examination of queue state, as the list may be
out of date by the time it is returned, and concurrent dequeue operations may
in the worse case force the queue-traversal to be restarted several times.
@end deffn
@anchor{Function sb-concurrency make-queue}
@ffindex @sortas{make-queue sb-concurrency} make-queue [sb-concurrency]
@deffn{Function} sb-concurrency:make-queue &key name initial-contents
Returns a new @code{queue} with @code{name} and contents of the @code{initial-contents}
sequence enqueued.
@end deffn
@anchor{Function sb-concurrency queue-count}
@ffindex @sortas{queue-count sb-concurrency} queue-count [sb-concurrency]
@deffn{Function} sb-concurrency:queue-count queue
Returns the number of objects in @code{queue}. Mainly useful for manual
examination of queue state, and in @code{print-object} methods: inefficient as it
must walk the entire queue.
@end deffn
@anchor{Function sb-concurrency queue-empty-p}
@ffindex @sortas{queue-empty-p sb-concurrency} queue-empty-p [sb-concurrency]
@deffn{Function} sb-concurrency:queue-empty-p queue
Returns @code{t} if @code{queue} is empty, @code{nil} otherwise.
@end deffn
@anchor{Function sb-concurrency queue-name}
@ffindex @sortas{queue-name sb-concurrency} queue-name [sb-concurrency]
@deffn{Function} sb-concurrency:queue-name instance
Name of a @code{queue}. Can be assigned to using @code{setf}. Queue names
can be arbitrary printable objects, and need not be unique.
@end deffn
@anchor{Function sb-concurrency queuep}
@ffindex @sortas{queuep sb-concurrency} queuep [sb-concurrency]
@deffn{Function} sb-concurrency:queuep object
Returns true if argument is a @code{queue}, @code{nil} otherwise.
@end deffn
@node sb concurrency mailbox
@subsection Mailbox (lock-free)
@cindex Mailbox, lock-free
@code{sb-concurrency:mailbox} is a lock-free message queue where one
or multiple ends can send messages to one or multiple receivers. The
difference to @ref{Section sb-concurrency:queue, queues} is that the receiving
end may block until a message arrives.
@*@*
Built on top of the @ref{Structure sb-concurrency queue, queue} implementation.
@code{sb-concurrency:mailbox} is a lock-free message queue where one or
multiple ends can send messages to one or multiple receivers. The
difference to @ref{sb concurrency queue} is that the receiving end may
block until a message arrives.
@include struct-sb-concurrency-mailbox.texinfo
Built on top of the @ref{sb concurrency queue} implementation.
@include fun-sb-concurrency-list-mailbox-messages.texinfo
@include fun-sb-concurrency-mailbox-count.texinfo
@include fun-sb-concurrency-mailbox-empty-p.texinfo
@include fun-sb-concurrency-mailbox-name.texinfo
@include fun-sb-concurrency-mailboxp.texinfo
@include fun-sb-concurrency-make-mailbox.texinfo
@include fun-sb-concurrency-receive-message.texinfo
@include fun-sb-concurrency-receive-message-no-hang.texinfo
@include fun-sb-concurrency-receive-pending-messages.texinfo
@include fun-sb-concurrency-send-message.texinfo
@anchor{Structure sb-concurrency mailbox}
@ttindex @sortas{mailbox sb-concurrency} mailbox [sb-concurrency]
@deffn{Structure} sb-concurrency:mailbox
Mailbox aka message queue.
@page
@anchor{Section sb-concurrency:gate}
@code{send-message} adds a message to the mailbox, @code{receive-message} waits till
a message becomes available, whereas @code{receive-message-no-hang} is a non-blocking
variant, and @code{receive-pending-messages} empties the entire mailbox in one go.
Messages can be arbitrary objects.
@end deffn
@anchor{Function sb-concurrency list-mailbox-messages}
@ffindex @sortas{list-mailbox-messages sb-concurrency} list-mailbox-messages [sb-concurrency]
@deffn{Function} sb-concurrency:list-mailbox-messages mailbox
Returns a fresh list containing all the messages in @code{mailbox}. Does not
remove messages from the mailbox.
@end deffn
@anchor{Function sb-concurrency mailbox-count}
@ffindex @sortas{mailbox-count sb-concurrency} mailbox-count [sb-concurrency]
@deffn{Function} sb-concurrency:mailbox-count mailbox
Returns the number of messages currently in @code{mailbox}.
@end deffn
@anchor{Function sb-concurrency mailbox-empty-p}
@ffindex @sortas{mailbox-empty-p sb-concurrency} mailbox-empty-p [sb-concurrency]
@deffn{Function} sb-concurrency:mailbox-empty-p mailbox
Returns true if @code{mailbox} is currently empty, @code{nil} otherwise.
@end deffn
@anchor{Function sb-concurrency mailbox-name}
@ffindex @sortas{mailbox-name sb-concurrency} mailbox-name [sb-concurrency]
@deffn{Function} sb-concurrency:mailbox-name instance
Name of a @code{mailbox}. @code{setf}able.
@end deffn
@anchor{Function sb-concurrency mailboxp}
@ffindex @sortas{mailboxp sb-concurrency} mailboxp [sb-concurrency]
@deffn{Function} sb-concurrency:mailboxp object
Returns true if argument is a @code{mailbox}, @code{nil} otherwise.
@end deffn
@anchor{Function sb-concurrency make-mailbox}
@ffindex @sortas{make-mailbox sb-concurrency} make-mailbox [sb-concurrency]
@deffn{Function} sb-concurrency:make-mailbox &key name initial-contents
Returns a new @code{mailbox} with messages in @code{initial-contents} enqueued.
@end deffn
@anchor{Function sb-concurrency receive-message}
@ffindex @sortas{receive-message sb-concurrency} receive-message [sb-concurrency]
@deffn{Function} sb-concurrency:receive-message mailbox &key timeout
Removes the oldest message from @code{mailbox} and returns it as the primary
value, and a secondary value of @code{t}. If @code{mailbox} is empty waits until a message
arrives.
If @code{timeout} is provided, and no message arrives within the specified interval,
returns primary and secondary value of @code{nil}.
@end deffn
@anchor{Function sb-concurrency receive-message-no-hang}
@ffindex @sortas{receive-message-no-hang sb-concurrency} receive-message-no-hang [sb-concurrency]
@deffn{Function} sb-concurrency:receive-message-no-hang mailbox
The non-blocking variant of @code{receive-message}. Returns two values,
the message removed from @code{mailbox}, and a flag specifying whether a
message could be received.
@end deffn
@anchor{Function sb-concurrency receive-pending-messages}
@ffindex @sortas{receive-pending-messages sb-concurrency} receive-pending-messages [sb-concurrency]
@deffn{Function} sb-concurrency:receive-pending-messages mailbox &optional n
Removes and returns all (or at most @code{n}) currently pending messages
from @code{mailbox}, or returns @code{nil} if no messages are pending.
@quotation
@emph{Note}: Concurrent threads may be snarfing messages during the run
of this function, so even @code{x} and @code{y} appearing right next to each
other in the result does not necessarily mean that @code{y} was the
message sent right after @code{x}.
@end quotation
@end deffn
@anchor{Function sb-concurrency send-message}
@ffindex @sortas{send-message sb-concurrency} send-message [sb-concurrency]
@deffn{Function} sb-concurrency:send-message mailbox message
Adds a @code{message} to @code{mailbox}. Message can be any object.
@end deffn
@node sb concurrency gates
@subsection Gates
@cindex Gate
@code{sb-concurrency:gate} is a synchronization object suitable for when
multiple threads must wait for a single event before proceeding.
@include struct-sb-concurrency-gate.texinfo
@anchor{Structure sb-concurrency gate}
@ttindex @sortas{gate sb-concurrency} gate [sb-concurrency]
@deffn{Structure} sb-concurrency:gate
@code{gate} type. Gates are synchronization constructs suitable for making
multiple threads wait for single event before proceeding.
@include fun-sb-concurrency-close-gate.texinfo
@include fun-sb-concurrency-gate-name.texinfo
@include fun-sb-concurrency-gate-open-p.texinfo
@include fun-sb-concurrency-gatep.texinfo
@include fun-sb-concurrency-make-gate.texinfo
@include fun-sb-concurrency-open-gate.texinfo
@include fun-sb-concurrency-wait-on-gate.texinfo
@page
@anchor{Section sb-concurrency:frlock}
Use @code{wait-on-gate} to wait for a gate to open, @code{open-gate} to open one,
and @code{close-gate} to close an open gate. @code{gate-open-p} can be used to test
the state of a gate without blocking.
@end deffn
@anchor{Function sb-concurrency close-gate}
@ffindex @sortas{close-gate sb-concurrency} close-gate [sb-concurrency]
@deffn{Function} sb-concurrency:close-gate gate
Closes @code{gate}. Returns @code{t} if the gate was previously open, and @code{nil}
if the gate was already closed.
@end deffn
@anchor{Function sb-concurrency gate-name}
@ffindex @sortas{gate-name sb-concurrency} gate-name [sb-concurrency]
@deffn{Function} sb-concurrency:gate-name instance
Name of a @code{gate}. @code{setf}able.
@end deffn
@anchor{Function sb-concurrency gate-open-p}
@ffindex @sortas{gate-open-p sb-concurrency} gate-open-p [sb-concurrency]
@deffn{Function} sb-concurrency:gate-open-p gate
Returns true if @code{gate} is open.
@end deffn
@anchor{Function sb-concurrency gatep}
@ffindex @sortas{gatep sb-concurrency} gatep [sb-concurrency]
@deffn{Function} sb-concurrency:gatep object
Returns true if the argument is a @code{gate}.
@end deffn
@anchor{Function sb-concurrency make-gate}
@ffindex @sortas{make-gate sb-concurrency} make-gate [sb-concurrency]
@deffn{Function} sb-concurrency:make-gate &key name open
Makes a new gate. Gate will be initially open if @code{open} is true, and closed if @code{open}
is @code{nil} (the default.) @code{name}, if provided, is the name of the gate, used when printing
the gate.
@end deffn
@anchor{Function sb-concurrency open-gate}
@ffindex @sortas{open-gate sb-concurrency} open-gate [sb-concurrency]
@deffn{Function} sb-concurrency:open-gate gate
Opens @code{gate}. Returns @code{t} if the gate was previously closed, and @code{nil}
if the gate was already open.
@end deffn
@anchor{Function sb-concurrency wait-on-gate}
@ffindex @sortas{wait-on-gate sb-concurrency} wait-on-gate [sb-concurrency]
@deffn{Function} sb-concurrency:wait-on-gate gate &key timeout
Waits for @code{gate} to open, or @code{timeout} seconds to pass. Returns @code{t}
if the gate was opened in time, and @code{nil} otherwise.
@end deffn
@node sb concurrency frlocks
@subsection Frlocks, aka Fast Read Locks
@cindex Frlock
@cindex Fast Read Lock
@include struct-sb-concurrency-frlock.texinfo
@anchor{Structure sb-concurrency frlock}
@ttindex @sortas{frlock sb-concurrency} frlock [sb-concurrency]
@deffn{Structure} sb-concurrency:frlock
FRlock, aka Fast Read Lock.
@include macro-sb-concurrency-frlock-read.texinfo
@include macro-sb-concurrency-frlock-write.texinfo
Fast Read Locks allow multiple readers and one potential writer to operate in
parallel while providing for consistency for readers and mutual exclusion for
writers.
@include fun-sb-concurrency-make-frlock.texinfo
@include fun-sb-concurrency-frlock-name.texinfo
Readers gain entry to protected regions without waiting, but need to retry if
a writer operated inside the region while they were reading. This makes frlocks
very efficient when readers are much more common than writers.
@include fun-sb-concurrency-frlock-read-begin.texinfo
@include fun-sb-concurrency-frlock-read-end.texinfo
@include fun-sb-concurrency-grab-frlock-write-lock.texinfo
@include fun-sb-concurrency-release-frlock-write-lock.texinfo
FRlocks are @emph{not} suitable when it is not safe at all for readers and writers
to operate on the same data in parallel: they provide consistency, not
exclusion between readers and writers. Hence using an frlock to e.g. protect
an SBCL hash-table is unsafe. If multiple readers operating in parallel with
a writer would be safe but inconsistent without a lock, frlocks are suitable.
The recommended interface to use is @code{frlock-read} and @code{frlock-write}, but those
needing it can also use a lower-level interface.
Example:
@example
;; Values returned by FOO are always consistent so that
;; the third value is the sum of the two first ones.
(let ((a 0)
(b 0)
(c 0)
(lk (make-frlock)))
(defun foo ()
(frlock-read (lk) a b c))
(defun bar (x y)
(frlock-write (lk)
(setf a x
b y
c (+ x y)))))
@end example
@end deffn
@anchor{Macro sb-concurrency frlock-read}
@ffindex @sortas{frlock-read sb-concurrency} frlock-read [sb-concurrency]
@deffn{Macro} sb-concurrency:frlock-read (frlock) &body value-forms
Evaluates @code{value-forms} under @code{frlock} till it obtains a consistent
set, and returns that as multiple values.
@end deffn
@anchor{Macro sb-concurrency frlock-write}
@ffindex @sortas{frlock-write sb-concurrency} frlock-write [sb-concurrency]
@deffn{Macro} sb-concurrency:frlock-write (frlock &key wait-p timeout) &body body
Executes @code{body} while holding @code{frlock} for writing.
@end deffn
@anchor{Function sb-concurrency make-frlock}
@ffindex @sortas{make-frlock sb-concurrency} make-frlock [sb-concurrency]
@deffn{Function} sb-concurrency:make-frlock &key name
Returns a new @code{frlock} with @code{name}.
@end deffn
@anchor{Function sb-concurrency frlock-name}
@ffindex @sortas{frlock-name sb-concurrency} frlock-name [sb-concurrency]
@deffn{Function} sb-concurrency:frlock-name instance
Name of an @code{frlock}. @code{setf}able.
@end deffn
@anchor{Function sb-concurrency frlock-read-begin}
@ffindex @sortas{frlock-read-begin sb-concurrency} frlock-read-begin [sb-concurrency]
@deffn{Function} sb-concurrency:frlock-read-begin frlock
Start a read sequence on @code{frlock}. Returns a read-token and an epoch to be
validated later.
Using @code{frlock-read} instead is recommended.
@end deffn
@anchor{Function sb-concurrency frlock-read-end}
@ffindex @sortas{frlock-read-end sb-concurrency} frlock-read-end [sb-concurrency]
@deffn{Function} sb-concurrency:frlock-read-end frlock
Ends a read sequence on @code{frlock}. Returns a token and an epoch. If the token
and epoch are @code{eql} to the read-token and epoch returned by @code{frlock-read-begin},
the values read under the @code{frlock} are consistent and can be used: if the values
differ, the values are inconsistent and the read must be restated.
Using @code{frlock-read} instead is recommended.
Example:
@example
(multiple-value-bind (t0 e0) (frlock-read-begin *fr*)
(let ((a (get-a))
(b (get-b)))
(multiple-value-bind (t1 e1) (frlock-read-end *fr*)
(if (and (eql t0 t1) (eql e0 e1))
(list :a a :b b)
:aborted))))
@end example
@end deffn
@anchor{Function sb-concurrency grab-frlock-write-lock}
@ffindex @sortas{grab-frlock-write-lock sb-concurrency} grab-frlock-write-lock [sb-concurrency]
@deffn{Function} sb-concurrency:grab-frlock-write-lock frlock &key wait-p timeout
Acquires @code{frlock} for writing, invalidating existing and future read-tokens
for the duration. Returns @code{t} on success, and @code{nil} if the lock wasn't acquired
due to e.g. a timeout. Using @code{frlock-write} instead is recommended.
@end deffn
@anchor{Function sb-concurrency release-frlock-write-lock}
@ffindex @sortas{release-frlock-write-lock sb-concurrency} release-frlock-write-lock [sb-concurrency]
@deffn{Function} sb-concurrency:release-frlock-write-lock frlock
Releases @code{frlock} after writing, allowing valid read-tokens to be acquired again.
Signals an error if the current thread doesn't hold @code{frlock} for writing. Using @code{frlock-write}
instead is recommended.
@end deffn

View file

@ -229,7 +229,7 @@
(prog1 (sb-c::integer-from-octets octets) (setf (fill-pointer octets) 0)))
(defun unpack-pair (packed-pair)
(let ((list (sb-c::unpack-code-fixup-locs packed-pair)))
(let ((list (sb-c:unpack-code-fixup-locs packed-pair)))
(values (1- (car list)) ; 1 as encoded means 0, etc
;; If START and END were =, then the delta is 0, which can't be encoded,
;; so the pair reads back as only one integer, which we just repeat.

View file

@ -102,11 +102,11 @@ If DIRECTORY does not exist, it will be created. The main report will be
printed to the file cover-index.html. The external format of the source
files can be specified with the EXTERNAL-FORMAT parameter.
If the keyword argument FORM-MODE has the value :CAR, the annotations in
the coverage report will be placed on the CARs of any cons-forms, while if
it has the value :WHOLE the whole form will be annotated (the default).
The former mode shows explicitly which forms were instrumented, while the
latter mode is generally easier to read.
If the keyword argument :FORM-MODE has the value :CAR, the annotations
in the coverage report will be placed on the CARs of any cons-forms,
while if it has the value :WHOLE the whole form will be annotated (the
default). The former mode shows explicitly which forms were
instrumented, while the latter mode is generally easier to read.
The keyword argument IF-MATCHES should be a designator for a function
of one argument, called for the namestring of each file with code

View file

@ -0,0 +1,42 @@
(in-package :sb-manual)
;;; FIXME: Write some documentation about how to interpret the results.
(defsection @sb-cover (:title "sb-cover")
"The `SB-COVER` module provides a code coverage tool for SBCL. The
tool has support for expression coverage, and for some branch
coverage. Coverage reports are only generated for code compiled
using COMPILE-FILE with the value of the
SB-COVER:STORE-COVERAGE-DATA optimization quality set to 3.
As of SBCL 1.0.6, `SB-COVER` is still experimental, and the
interfaces documented here might change in later versions.
How to use it:
;;; Load SB-COVER
(require :sb-cover)
;;; Turn on generation of code coverage instrumentation in the compiler
(declaim (optimize sb-cover:store-coverage-data))
;;; Load some code, ensuring that it's recompiled with the new optimization
;;; policy.
(asdf:oos 'asdf:load-op :cl-ppcre-test :force t)
;;; Run the test suite.
(cl-ppcre-test:test)
;;; Produce a coverage report
(sb-cover:report \"/tmp/report/\")
;;; Turn off instrumentation
(declaim (optimize (sb-cover:store-coverage-data 0)))"
(sb-cover:report function)
(sb-cover:reset-coverage function)
(sb-cover:clear-coverage function)
(sb-cover:save-coverage function)
(sb-cover:save-coverage-in-file function)
(sb-cover:restore-coverage function)
(sb-cover:restore-coverage-from-file function)
(sb-cover:merge-coverage function)
(sb-cover:merge-coverage-from-file function))

View file

@ -1,19 +1,20 @@
@node sb-cover
@c Generated by the sb-manual contrib. Do not edit.
@node sb cover
@section sb-cover
@cindex Code Coverage
The @code{sb-cover} module provides a code coverage tool for SBCL. The
tool has support for expression coverage, and for some branch coverage.
Coverage reports are only generated for code compiled using
@code{compile-file} with the value of the
tool has support for expression coverage, and for some branch
coverage. Coverage reports are only generated for code compiled
using @code{compile-file} with the value of the
@code{sb-cover:store-coverage-data} optimization quality set to 3.
As of SBCL 1.0.6 @code{sb-cover} is still experimental, and the
As of SBCL 1.0.6, @code{sb-cover} is still experimental, and the
interfaces documented here might change in later versions.
@subsection Example Usage
How to use it:
@lisp
@example
;;; Load SB-COVER
(require :sb-cover)
@ -32,27 +33,76 @@ interfaces documented here might change in later versions.
;;; Turn off instrumentation
(declaim (optimize (sb-cover:store-coverage-data 0)))
@end lisp
@end example
@c @subsection Output
@c Write some documentation about how to interpret the results
@anchor{Function sb-cover report}
@ffindex @sortas{report sb-cover} report [sb-cover]
@deffn{Function} sb-cover:report directory &key form-mode if-matches external-format
Print a code coverage report of all instrumented files into @code{directory}.
If @code{directory} does not exist, it will be created. The main report will be
printed to the file cover-index.html. The external format of the source
files can be specified with the @code{external-format} parameter.
@subsection Functions
If the keyword argument @code{:form-mode} has the value @code{:car}, the annotations
in the coverage report will be placed on the @code{car}s of any cons-forms,
while if it has the value @code{:whole} the whole form will be annotated (the
default). The former mode shows explicitly which forms were
instrumented, while the latter mode is generally easier to read.
@include fun-sb-cover-report.texinfo
@include fun-sb-cover-reset-coverage.texinfo
@include fun-sb-cover-clear-coverage.texinfo
@include fun-sb-cover-save-coverage.texinfo
@include fun-sb-cover-save-coverage-in-file.texinfo
@include fun-sb-cover-restore-coverage.texinfo
@include fun-sb-cover-restore-coverage-from-file.texinfo
@include fun-sb-cover-merge-coverage.texinfo
@include fun-sb-cover-merge-coverage-from-file.texinfo
The keyword argument @code{if-matches} should be a designator for a function
of one argument, called for the namestring of each file with code
coverage info. If it returns true, the file's info is included in the
report, otherwise ignored. The default value is @code{cl:identity}.
@end deffn
@anchor{Function sb-cover reset-coverage}
@ffindex @sortas{reset-coverage sb-cover} reset-coverage [sb-cover]
@deffn{Function} sb-cover:reset-coverage &optional object
Reset all coverage data back to the @code{Not executed} state.
@end deffn
@anchor{Function sb-cover clear-coverage}
@ffindex @sortas{clear-coverage sb-cover} clear-coverage [sb-cover]
@deffn{Function} sb-cover:clear-coverage
Clear all files from the coverage database. The files will be re-entered
into the database when the FASL files (produced by compiling
@code{store-coverage-data} optimization policy set to 3) are loaded again into the
image.
@end deffn
@anchor{Function sb-cover save-coverage}
@ffindex @sortas{save-coverage sb-cover} save-coverage [sb-cover]
@deffn{Function} sb-cover:save-coverage
Returns an opaque representation of the current code coverage state.
The only operation that may be done on the state is passing it to
@code{restore-coverage}. The representation is guaranteed to be readably printable.
A representation that has been printed and read back will work identically
in @code{restore-coverage}.
@end deffn
@anchor{Function sb-cover save-coverage-in-file}
@ffindex @sortas{save-coverage-in-file sb-cover} save-coverage-in-file [sb-cover]
@deffn{Function} sb-cover:save-coverage-in-file pathname
Call @code{save-coverage} and write the results of that operation into the
file designated by @code{pathname}.
@end deffn
@anchor{Function sb-cover restore-coverage}
@ffindex @sortas{restore-coverage sb-cover} restore-coverage [sb-cover]
@deffn{Function} sb-cover:restore-coverage coverage-state
Restore the code coverage data back to an earlier state produced by
@code{save-coverage}.
@end deffn
@anchor{Function sb-cover restore-coverage-from-file}
@ffindex @sortas{restore-coverage-from-file sb-cover} restore-coverage-from-file [sb-cover]
@deffn{Function} sb-cover:restore-coverage-from-file pathname
@code{read} the contents of the file designated by @code{pathname} and pass the
result to @code{restore-coverage}.
@end deffn
@anchor{Function sb-cover merge-coverage}
@ffindex @sortas{merge-coverage sb-cover} merge-coverage [sb-cover]
@deffn{Function} sb-cover:merge-coverage coverage-state
Merge the code coverage data to include covered code from an earlier
state produced by @code{save-coverage}.
@end deffn
@anchor{Function sb-cover merge-coverage-from-file}
@ffindex @sortas{merge-coverage-from-file sb-cover} merge-coverage-from-file [sb-cover]
@deffn{Function} sb-cover:merge-coverage-from-file pathname
@code{read} the contents of the file designated by @code{pathname} and pass the
result to @code{merge-coverage}.
@end deffn

View file

@ -62,6 +62,7 @@
(setf (sb-int:system-package-p *package*) t))
(defvar *gmp-disabled* nil)
(declaim (sb-ext:always-bound *gmp-disabled*))
(defconstant +bignum-raw-area-offset+
(- (* sb-vm:bignum-digits-offset sb-vm:n-word-bytes)
@ -960,21 +961,26 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)."
(declare (inline mpz-mul-2exp mpz-pow)
(optimize (sb-c:verify-arg-count 0)))
(cond
((or (and (integerp base)
(< (abs power) 1000)
(< (blength base) 4))
(member base '(0 1 -1))
((or (not (typep power '(integer #.(1+ most-negative-fixnum) #.most-positive-fixnum)))
(if (integerp base)
(and
(< (blength base) 4)
(typep power '(signed-byte 10)))
;; EXPT dispatches to INTEXP for a (COMPLEX RATIONAL) base as well,
;; and MPZ-POW below only takes an integer.
(not (typep base 'ratio)))
*gmp-disabled*)
(orig-intexp base power))
(t
(check-type power (integer #.(1+ most-negative-fixnum) #.most-positive-fixnum))
(cond ((minusp power)
(/ (gmp-intexp base (- power))))
(let ((abs-power (- power)))
(sb-kernel:build-ratio (sb-ext:truly-the integer (gmp-intexp (denominator base) abs-power))
(sb-ext:truly-the integer (gmp-intexp (numerator base) abs-power)))))
((eql base 2)
(mpz-mul-2exp 1 power))
((typep base 'ratio)
(sb-kernel::%make-ratio (gmp-intexp (numerator base) power)
(gmp-intexp (denominator base) power)))
(sb-kernel::%make-ratio (sb-ext:truly-the integer (gmp-intexp (numerator base) power))
(sb-ext:truly-the integer (gmp-intexp (denominator base) power))))
(t
(mpz-pow base power))))))

View file

@ -207,6 +207,14 @@
(sb-gmp::gmp-intexp 113/355 -1)
355/113)
;; EXPT dispatches to INTEXP for a (COMPLEX RATIONAL) base as well.
(deftest intexp-complex-rational
(list (sb-gmp::gmp-intexp #c(1/5 1) 1)
(sb-gmp::gmp-intexp #c(1/5 1) 2)
(sb-gmp::gmp-intexp #c(2 3) 5)
(sb-gmp::gmp-intexp #c(1/5 1) -1))
(#c(1/5 1) #c(-24/25 2/5) #c(122 -597) #c(5/26 -25/26)))
(deftest remove-1
(multiple-value-list (mpz-remove 28 2))
(7 2))

View file

@ -80,25 +80,39 @@ code:
(destructuring-bind (cname &rest elements) cstruct
(printf "(sb-grovel::define-c-struct ~A %ld" lispname
(word-cast (format nil "sizeof(~A)" cname)))
(dolist (e elements)
(destructuring-bind (lisp-type lisp-el-name c-type c-el-name &key distrust-length) e
(printf " (~A ~A \"~A\"" lisp-el-name lisp-type c-type)
;; offset
(as-c "{" cname "t;")
(printf " %lu"
(format nil "((unsigned long~A)&(t.~A)) - ((unsigned long~A)&(t))"
#+(and win32 64-bit) " long" #-(and win32 64-bit) ""
c-el-name
#+(and win32 64-bit) " long" #-(and win32 64-bit) ""))
(as-c "}")
;; length
(if distrust-length
(printf " 0)")
(progn
(as-c "{" cname "t;")
(printf " %ld)"
(word-cast (format nil "sizeof(t.~A)" c-el-name)))
(as-c "}")))))
(when elements
(as-c "{" cname "t;")
(dolist (e elements)
(destructuring-bind (lisp-type lisp-el-name c-type c-el-name &key distrust-length) e
(printf " (~A ~A \"~A\"" lisp-el-name lisp-type c-type)
;; offset
(flet ((ifdef (fun c-el-name)
(cond ((typep c-el-name '(cons (eql :if)))
(destructuring-bind (cond then else) (cdr c-el-name)
(as-c "#if" cond)
(funcall fun then)
(as-c "#else")
(funcall fun else)
(as-c "#endif")))
(t
(funcall fun c-el-name)))))
(ifdef (lambda (c-el-name)
(printf " %lu"
(format nil "((unsigned long~A)&(t.~A)) - ((unsigned long~A)&(t))"
#+(and win32 64-bit) " long" #-(and win32 64-bit) ""
c-el-name
#+(and win32 64-bit) " long" #-(and win32 64-bit) "")))
c-el-name)
;; length
(if distrust-length
(printf " 0)")
(ifdef (lambda (c-el-name)
(printf " %ld)"
(word-cast (format nil "sizeof(t.~A)" c-el-name))))
c-el-name)))))
(as-c "}"))
(printf ")")))
(defun print-c-source (stream headers definitions package-name)
@ -195,7 +209,7 @@ int main(int argc, char *argv[]) {
(sb-ext:run-program
cc
(append
(split-cflags (sb-ext:posix-getenv "EXTRA_CFLAGS"))
(split-cflags (sb-ext:posix-getenv "CFLAGS"))
#+(and linux largefile)
'("-D_LARGEFILE_SOURCE" "-D_LARGEFILE64_SOURCE" "-D_FILE_OFFSET_BITS=64")
#+64-bit-time

View file

@ -339,47 +339,46 @@ deeply nested structures."
(defmacro define-c-struct (name size &rest elements)
(multiple-value-bind (struct-elements accessors)
(let* ((root (make-instance 'struct :name name :children nil :offset 0)))
(let ((root (make-instance 'struct :name name :children nil :offset 0)))
(loop for e in (sort (copy-list elements) #'< :key #'fourth)
do (insert-element root (apply 'mk-val e))
finally (return root))
do (insert-element root (apply 'mk-val e)))
(setf (children root)
(nconc (children root)
(list
(mk-padding (max 0 (- size
(size root)))
(size root)))))
(let ((pad (- size (size root))))
(when (> pad 0)
(list
(mk-padding pad (size root)))))))
(generate-struct-definition name root nil))
`(progn
(sb-alien:define-alien-type ,@(first struct-elements))
,@accessors
;; This macro's lambda vars are uninterned so that they don't refer to
;; the SB-GROVEL package, but they don't need to be GENSYMed.
(defmacro ,(sb-int:symbolicate "WITH-" name)
(alien (&rest #1=#:initializers) &body #2=#:body)
`(sb-alien:with-alien ((,alien ,',name))
(alien-funcall (extern-alien "memset"
(function void system-area-pointer int sb-kernel::os-vm-size-t))
(sb-alien:alien-sap ,alien) 0 ,,size)
(let ((,alien (cast ,alien (* ,',name))))
(setf ,@(mapcan
;; The symbol CONS is not in the SB-GROVEL package, making it more
;; clear that this expander works fine in the absence of sb-grovel.
(lambda (cons)
`((,(sb-int:package-symbolicate ,(package-name (symbol-package name))
,(concatenate 'string (string name) "-")
(car cons)) ,alien)
,(cadr cons)))
#1#))
,@#2#)))
(defconstant ,(sb-int:symbolicate "SIZE-OF-" name) ,size) ; why does this exist?
(defun ,(sb-int:symbolicate "ALLOCATE-" name) () ; and this?
(let ((sb-kernel:instance (sb-alien:make-alien ,name)))
;; The allocator returns 0-filled aliens. It's unknowable whether anyone cares.
(alien-funcall (extern-alien "memset"
(function void system-area-pointer int sb-kernel::os-vm-size-t))
(sb-alien:alien-sap sb-kernel:instance) 0 ,size)
sb-kernel:instance)))))
(sb-alien:define-alien-type ,@(first struct-elements))
,@accessors
;; This macro's lambda vars are uninterned so that they don't refer to
;; the SB-GROVEL package, but they don't need to be GENSYMed.
(defmacro ,(sb-int:symbolicate "WITH-" name)
(alien (&rest #1=#:initializers) &body #2=#:body)
`(sb-alien:with-alien ((,alien ,',name))
(alien-funcall (extern-alien "memset"
(function void system-area-pointer int sb-kernel::os-vm-size-t))
(sb-alien:alien-sap ,alien) 0 ,,size)
(let ((,alien (cast ,alien (* ,',name))))
(setf ,@(mapcan
;; The symbol CONS is not in the SB-GROVEL package, making it more
;; clear that this expander works fine in the absence of sb-grovel.
(lambda (cons)
`((,(sb-int:package-symbolicate ,(package-name (symbol-package name))
,(concatenate 'string (string name) "-")
(car cons)) ,alien)
,(cadr cons)))
#1#))
,@#2#)))
(defconstant ,(sb-int:symbolicate "SIZE-OF-" name) ,size) ; why does this exist?
(defun ,(sb-int:symbolicate "ALLOCATE-" name) () ; and this?
(let ((sb-kernel:instance (sb-alien:make-alien ,name)))
;; The allocator returns 0-filled aliens. It's unknowable whether anyone cares.
(alien-funcall (extern-alien "memset"
(function void system-area-pointer int sb-kernel::os-vm-size-t))
(sb-alien:alien-sap sb-kernel:instance) 0 ,size)
sb-kernel:instance)))))
;; FIXME: Nothing in SBCL uses this, but kept it around in case there
;; are third-party sb-grovel clients. It should go away eventually,

View file

@ -0,0 +1,208 @@
(in-package :sb-manual)
(defsection @sb-grovel (:title "sb-grovel")
"The `SB-GROVEL` module helps in generation of foreign function
interfaces. It aids in extracting constants' values from the C
compiler and in generating sb-alien structure and union types,
@DEFINING-FOREIGN-TYPES.
The ASDF (<http://www.cliki.net/ASDF>) component type
GROVEL-CONSTANTS-FILE has its ASDF:PERFORM operation defined to
write out a C source file, compile it, and run it. The output from
this program is Lisp, which is then itself compiled and loaded.
`SB-GROVEL` is used in a few contributed modules, and it is
currently compatible only to SBCL. However, if you want to use it,
here are a few directions."
(@using-sb-grovel section)
(@sb-grovel-constants-file section)
(@sb-grovel-structures section)
(@sb-grovel-traps section))
(defsection @using-sb-grovel (:title "Using sb-grovel in your own ASDF System")
"- Create a Lisp package for the foreign constants/functions to go
into.
- Make your system depend on the `SB-GROVEL` system.
- Create a grovel-constants data file -- for an example, see
`example-constants.lisp` in the `contrib/sb-grovel/` directory in
the SBCL source distribution.
- Add it as a component in your system. For example:
(eval-when (:compile-toplevel :load-toplevel :execute)
(require :sb-grovel))
(defpackage :example-package.system
(:use :cl :asdf :sb-grovel :sb-alien))
(in-package :example-package.system)
(defsystem example-system
:depends-on (sb-grovel)
:components
((:module \"sbcl\"
:components
((:file \"defpackage\")
(grovel-constants-file \"example-constants\"
:package :example-package)))))
Make sure to specify the package you chose in step 1.
- Build stuff.")
(defsection @sb-grovel-constants-file
(:title "Contents of a grovel-constants-file")
"The grovel-constants-file, typically named `constants.lisp`,
comprises lisp expressions describing the foreign things that you
want to grovel for. A `constants.lisp` file contains two sections:
- a list of headers to include in the C program, for example:
(\"sys/types.h\" \"sys/socket.h\" \"sys/stat.h\" \"unistd.h\" \"sys/un.h\"
\"netinet/in.h\" \"netinet/in_systm.h\" \"netinet/ip.h\" \"net/if.h\"
\"netdb.h\" \"errno.h\" \"netinet/tcp.h\" \"fcntl.h\" \"signal.h\")
- A list of sb-grovel clauses describing the things you want to
grovel from the C compiler, for example:
((:integer af-local
#+(or sunos solaris) \"AF_UNIX\"
#-(or sunos solaris) \"AF_LOCAL\"
\"Local to host (pipes and file-domain).\")
(:structure stat (\"struct stat\"
(integer dev \"dev_t\" \"st_dev\")
(integer atime \"time_t\" \"st_atime\")))
(:function getpid (\"getpid\" int )))
There are two types of things that sb-grovel can sensibly extract
from the C compiler: constant integers and structure layouts. It is
also possible to define foreign functions in the constants.lisp
file, but these definitions don't use any information from the C
program; they expand directly to SB-ALIEN:DEFINE-ALIEN-ROUTINE
forms.
Here's how to use the grovel clauses:
- :INTEGER: constant expressions in C. Used in this form:
(:integer lisp-variable-name \"C expression\" &optional doc export)
`\"C expression\"` will be typically be the name of a constant,
but other forms are possible.
- :ENUM:
(:enum lisp-type-name ((lisp-enumerated-name c-enumerated-name) ...)))
An SB-ALIEN:ENUM type with name `LISP-TYPE-NAME` will be
defined. The symbols are the `LISP-ENUMERATED-NAME`s, and the
values are grovelled from the `C-ENUMERATED-NAME`s.
- :STRUCTURE: alien structure definitions look like this:
(:structure lisp-struct-name (\"struct c_structure\"
(type-designator lisp-element-name
\"c_element_type\" \"c_element_name\"
:distrust-length nil)
; ...
))
`TYPE-DESIGNATOR` is a reference to a type whose size (and type
constraints) will be groveled for. sb-grovel accepts a form of
type designator that doesn't quite conform to either lisp nor
sb-alien's type specifiers. Here's a list of type designators
that sb-grovel currently accepts:
- `\\INTEGER`: a C integral type; sb-grovel will infer the exact
type from size information extracted from the C program. All
common C integer types can be grovelled for with this type
designator, but it is not possible to grovel for bit fields
yet.
- `(UNSIGNED N)`: an unsigned integer variable that is `N` bytes
long. No size information from the C program will be used.
- `(SIGNED N)`: an signed integer variable that is `N` bytes
long. No size information from the C program will be used.
- `\\C-STRING`: an array of `\\char` in the structure. sb-grovel
will use the array's length from the C program, unless you
pass it the :DISTRUST-LENGTH keyword argument with non-`NIL`
value (this might be required for structures such as solaris's
`struct dirent`).
- SB-GROVEL::C-STRING-POINTER: a pointer to a C string,
corresponding to the SB-ALIEN:C-STRING type (see
@FOREIGN-TYPE-SPECIFIERS).
- `(ARRAY ALIEN-TYPE)`: an array of the previously-declared
`ALIEN-TYPE`. The array's size will be determined from the
output of the C program and the alien type's size.
- `(ARRAY ALIEN-TYPE N):` an array of the previously-declared
`ALIEN-TYPE`. The array's size will be assumed as being `N`.
Note that `\\C-STRING` and SB-GROVEL::C-STRING-POINTER do not have
the same meaning. If you declare that an element is of type
C-STRING, it will be treated as if the string is a part of the
structure, whereas if you declare that the element is of type
SB-GROVEL::C-STRING-POINTER, a _pointer to a string_ will be the
structure member.
- :FUNCTION: alien function definitions are similar to
DEFINE-ALIEN-ROUTINE definitions, because they expand to such
forms when the lisp program is loaded. See
@FOREIGN-FUNCTION-CALLS.
(:function lisp-function-name
(\"alien_function_name\" alien-return-type
(argument alien-type)
(argument2 alien-type)))")
(defsection @sb-grovel-structures
(:title "Programming with sb-grovel's structure types")
"Let us assume that you have a grovelled structure definition:
(:structure mystruct (\"struct my_structure\"
(integer myint \"int\" \"st_int\")
(c-string mystring \"char[]\" \"st_str\")))
What can you do with it? Here's a short interface document:
- Creating and destroying objects:
- Function `(ALLOCATE-MYSTRUCT)` allocates an object of type
`mystruct` and returns a system area pointer to it.
- Macro `(WITH-MYSTRUCT VAR ((MEMBER INIT) [...]) &BODY BODY)`
allocates an object of type `MYSTRUCT` that is valid in
`BODY`. If `BODY` terminates or performs an non-local exit,
the object pointed to by `VAR` will be deallocated.
- Accessing structure members:
- `(MYSTRUCT-MYINT VAR)` and `(MYSTRUCT-MYSTRING VAR)` return
the value of the respective fields in `MYSTRUCT`.
- `(SETF (MYSTRUCT-MYINT VAR) NEW-VAL)` and
`(SETF (MYSTRUCT-MYSTRING VAR) NEW-VAL)` sets the value of the
respective structure member to the value of `NEW-VAL`. Notice
that in `(SETF (MYSTRUCT-MYSTRING VAR) NEW-VAL)`'s case,
`NEW-VAL` is a lisp string.")
(defsection @sb-grovel-traps (:title "Traps and Pitfalls")
"Basically, you can treat functions and data structure definitions that
sb-grovel spits out as if they were alien routines and types. This has
a few implications that might not be immediately obvious (especially
if you have programmed in a previous version of sb-grovel that didn't
use alien types):
- You must take care of grovel-allocated structures yourself. They
are alien types, so the garbage collector will not collect them
when you drop the last reference.
- If you use the `WITH-MYSTRUCT` macro, be sure that no references
to the variable thus allocated leaks out. It will be deallocated
when the block exits.")

View file

@ -1,42 +1,47 @@
@node sb-grovel
@c Generated by the sb-manual contrib. Do not edit.
@node sb grovel
@section sb-grovel
@cindex Foreign Function Interface, generation
@menu
* Using sb-grovel in your own ASDF System: using sb grovel.
* Contents of a grovel-constants-file: sb grovel constants file.
* Programming with sb-grovel's structure types: sb grovel structures.
* Traps and Pitfalls: sb grovel traps.
@end menu
The @code{sb-grovel} module helps in generation of foreign function
interfaces. It aids in extracting constants' values from the C
compiler and in generating SB-ALIEN structure and union types,
@pxref{Defining Foreign Types}.
compiler and in generating sb-alien structure and union types,
@ref{defining foreign types}.
The ASDF(@uref{http://www.cliki.net/ASDF}) component type
GROVEL-CONSTANTS-FILE has its PERFORM
@c @xref for PERFORM when asdf manual is included?
operation defined to write out a C source file, compile it, and run
it. The output from this program is Lisp, which is then itself
compiled and loaded.
The ASDF (@url{http://www.cliki.net/ASDF}) component type
GROVEL-CONSTANTS-FILE has its @code{asdf:perform} operation defined to
write out a C source file, compile it, and run it. The output from
this program is Lisp, which is then itself compiled and loaded.
sb-grovel is used in a few contributed modules, and it is currently
compatible only to SBCL. However, if you want to use it, here are a
few directions.
@code{sb-grovel} is used in a few contributed modules, and it is
currently compatible only to SBCL. However, if you want to use it,
here are a few directions.
@subsection Using sb-grovel in your own ASDF system
@node using sb grovel
@subsection Using sb-grovel in your own ASDF System
@enumerate
@itemize
@item Create a Lisp package for the foreign constants/functions to go
@end itemize
into.
@item
Create a Lisp package for the foreign constants/functions to go into.
@itemize
@item Make your system depend on the @code{sb-grovel} system.
@item
Make your system depend on the 'sb-grovel system.
@item Create a grovel-constants data file -- for an example, see
@code{example-constants.lisp} in the @code{contrib/sb-grovel/} directory in
the SBCL source distribution.
@item
Create a grovel-constants data file - for an example, see
example-constants.lisp in the contrib/sb-grovel/ directory in the SBCL
source distribution.
@item Add it as a component in your system. For example:
@item
Add it as a component in your system. e.g.
@lisp
@example
(eval-when (:compile-toplevel :load-toplevel :execute)
(require :sb-grovel))
@ -53,34 +58,35 @@ Add it as a component in your system. e.g.
((:file "defpackage")
(grovel-constants-file "example-constants"
:package :example-package)))))
@end lisp
@end example
@end itemize
Make sure to specify the package you chose in step 1
Make sure to specify the package you chose in step 1.
@item
Build stuff.
@end enumerate
@itemize
@item Build stuff.
@end itemize
@node sb grovel constants file
@subsection Contents of a grovel-constants-file
The grovel-constants-file, typically named @code{constants.lisp},
comprises lisp expressions describing the foreign things that you want
to grovel for. A @code{constants.lisp} file contains two sections:
comprises lisp expressions describing the foreign things that you
want to grovel for. A @code{constants.lisp} file contains two sections:
@itemize
@item
a list of headers to include in the C program, for example:
@lisp
@item a list of headers to include in the C program, for example:
@example
("sys/types.h" "sys/socket.h" "sys/stat.h" "unistd.h" "sys/un.h"
"netinet/in.h" "netinet/in_systm.h" "netinet/ip.h" "net/if.h"
"netdb.h" "errno.h" "netinet/tcp.h" "fcntl.h" "signal.h" )
@end lisp
"netdb.h" "errno.h" "netinet/tcp.h" "fcntl.h" "signal.h")
@end example
@item
A list of sb-grovel clauses describing the things you want to grovel
from the C compiler, for example:
@lisp
@item A list of sb-grovel clauses describing the things you want to
grovel from the C compiler, for example:
@example
((:integer af-local
#+(or sunos solaris) "AF_UNIX"
#-(or sunos solaris) "AF_LOCAL"
@ -89,149 +95,151 @@ from the C compiler, for example:
(integer dev "dev_t" "st_dev")
(integer atime "time_t" "st_atime")))
(:function getpid ("getpid" int )))
@end lisp
@end example
@end itemize
There are two types of things that sb-grovel can sensibly extract from
the C compiler: constant integers and structure layouts. It is also
possible to define foreign functions in the constants.lisp file, but
these definitions don't use any information from the C program; they
expand directly to @code{sb-alien:define-alien-routine}
(@pxref{The define-alien-routine Macro}) forms.
There are two types of things that sb-grovel can sensibly extract
from the C compiler: constant integers and structure layouts. It is
also possible to define foreign functions in the constants.lisp
file, but these definitions don't use any information from the C
program; they expand directly to @code{sb-alien:define-alien-routine}
forms.
Here's how to use the grovel clauses:
@itemize
@item
@code{:integer} - constant expressions in C. Used in this form:
@lisp
@item @code{:integer}: constant expressions in C. Used in this form:
@example
(:integer lisp-variable-name "C expression" &optional doc export)
@end lisp
@end example
@code{"C expression"} will be typically be the name of a constant. But
other forms are possible.
@code{"C expression"} will be typically be the name of a constant,
but other forms are possible.
@item
@code{:enum}
@lisp
@item @code{:enum}:
@example
(:enum lisp-type-name ((lisp-enumerated-name c-enumerated-name) ...)))
@end lisp
@end example
An @code{sb-alien:enum} type with name @code{lisp-type-name} will be defined.
The symbols are the @code{lisp-enumerated-name}s, and the values
are grovelled from the @code{c-enumerated-name}s.
An @code{sb-alien:enum} type with name @code{lisp-type-name} will be
defined. The symbols are the @code{lisp-enumerated-name}s, and the
values are grovelled from the @code{c-enumerated-name}s.
@item
@code{:structure} - alien structure definitions look like this:
@lisp
@item @code{:structure}: alien structure definitions look like this:
@example
(:structure lisp-struct-name ("struct c_structure"
(type-designator lisp-element-name
"c_element_type" "c_element_name"
:distrust-length nil)
; ...
))
@end lisp
@end example
@code{type-designator} is a reference to a type whose size (and type
constraints) will be groveled for. sb-grovel accepts a form of type
designator that doesn't quite conform to either lisp nor sb-alien's
type specifiers. Here's a list of type designators that sb-grovel
currently accepts:
constraints) will be groveled for. sb-grovel accepts a form of
type designator that doesn't quite conform to either lisp nor
sb-alien's type specifiers. Here's a list of type designators
that sb-grovel currently accepts:
@itemize
@item
@code{integer} - a C integral type; sb-grovel will infer the exact
type from size information extracted from the C program. All common C
integer types can be grovelled for with this type designator, but it
is not possible to grovel for bit fields yet.
@item @code{integer}: a C integral type; sb-grovel will infer the exact
type from size information extracted from the C program. All
common C integer types can be grovelled for with this type
designator, but it is not possible to grovel for bit fields
yet.
@item
@code{(unsigned n)} - an unsigned integer variable that is @code{n}
bytes long. No size information from the C program will be used.
@item
@code{(signed n)} - an signed integer variable that is @code{n} bytes
long. No size information from the C program will be used.
@item @code{(unsigned n)}: an unsigned integer variable that is @code{n} bytes
long. No size information from the C program will be used.
@item
@code{c-string} - an array of @code{char} in the structure. sb-grovel
will use the array's length from the C program, unless you pass it the
@code{:distrust-length} keyword argument with non-@code{nil} value
(this might be required for structures such as solaris's @code{struct
dirent}).
@item @code{(signed n)}: an signed integer variable that is @code{n} bytes
long. No size information from the C program will be used.
@item
@code{c-string-pointer} - a pointer to a C string, corresponding to
the @code{sb-alien:c-string} type (@pxref{Foreign Type Specifiers}).
@item
@code{(array alien-type)} - An array of the previously-declared alien
type. The array's size will be determined from the output of the C
program and the alien type's size.
@item
@code{(array alien-type n)} - An array of the previously-declared alien
type. The array's size will be assumed as being @code{n}.
@item @code{c-string}: an array of @code{char} in the structure. sb-grovel
will use the array's length from the C program, unless you
pass it the @code{:distrust-length} keyword argument with non-@code{nil}
value (this might be required for structures such as solaris's
@code{struct dirent}).
@item @code{sb-grovel::c-string-pointer}: a pointer to a C string,
corresponding to the @code{sb-alien:c-string} type (see
@ref{foreign type specifiers}).
@item @code{(array alien-type)}: an array of the previously-declared
@code{alien-type}. The array's size will be determined from the
output of the C program and the alien type's size.
@item @code{(array alien-type n):} an array of the previously-declared
@code{alien-type}. The array's size will be assumed as being @code{n}.
@end itemize
@end itemize
Note that @code{c-string} and @code{c-string-pointer} do not have the
same meaning. If you declare that an element is of type
Note that @code{c-string} and @code{sb-grovel::c-string-pointer} do not have
the same meaning. If you declare that an element is of type
@code{c-string}, it will be treated as if the string is a part of the
structure, whereas if you declare that the element is of type
@code{c-string-pointer}, a @emph{pointer to a string} will be the
@code{sb-grovel::c-string-pointer}, a @emph{pointer to a string} will be the
structure member.
@item
@code{:function} - alien function definitions are similar to
@code{define-alien-routine} definitions, because they expand to such
forms when the lisp program is loaded. @xref{Foreign Function Calls}.
@itemize
@item @code{:function}: alien function definitions are similar to
@code{define-alien-routine} definitions, because they expand to such
forms when the lisp program is loaded. See
@ref{foreign function calls}.
@lisp
(:function lisp-function-name ("alien_function_name" alien-return-type
(argument alien-type)
(argument2 alien-type)))
@end lisp
@example
(:function lisp-function-name
("alien_function_name" alien-return-type
(argument alien-type)
(argument2 alien-type)))
@end example
@end itemize
@node sb grovel structures
@subsection Programming with sb-grovel's structure types
Let us assume that you have a grovelled structure definition:
@lisp
(:structure mystruct ("struct my_structure"
(integer myint "int" "st_int")
(c-string mystring "char[]" "st_str")))
@end lisp
@example
(:structure mystruct ("struct my_structure"
(integer myint "int" "st_int")
(c-string mystring "char[]" "st_str")))
@end example
What can you do with it? Here's a short interface document:
@itemize
@item
Creating and destroying objects:
@item Creating and destroying objects:
@itemize
@item
Function @code{(allocate-mystruct)} - allocates an object of type @code{mystruct}and
returns a system area pointer to it.
@item
Macro @code{(with-mystruct var ((member init) [...]) &body body)} -
allocates an object of type @code{mystruct} that is valid in
@var{body}. If @var{body} terminates or control unwinds out of
@var{body}, the object pointed to by @var{var} will be deallocated.
@item Function @code{(allocate-mystruct)} allocates an object of type
@code{mystruct} and returns a system area pointer to it.
@item Macro @code{(with-mystruct var ((member init) [...]) &body body)}
allocates an object of type @code{mystruct} that is valid in
@code{body}. If @code{body} terminates or performs an non-local exit,
the object pointed to by @code{var} will be deallocated.
@end itemize
@item
Accessing structure members:
@item Accessing structure members:
@itemize
@item
@code{(mystruct-myint var)} and @code{(mystruct-mystring var)} return
the value of the respective fields in @code{mystruct}.
@item
@code{(setf (mystruct-myint var) new-val)} and
@code{(setf (mystruct-mystring var) new-val)} sets the value of the respective
structure member to the value of @var{new-val}. Notice that in
@code{(setf (mystruct-mystring var) new-val)}'s case, new-val is a lisp
string.
@item @code{(mystruct-myint var)} and @code{(mystruct-mystring var)} return
the value of the respective fields in @code{mystruct}.
@item @code{(setf (mystruct-myint var) new-val)} and
@code{(setf (mystruct-mystring var) new-val)} sets the value of the
respective structure member to the value of @code{new-val}. Notice
that in @code{(setf (mystruct-mystring var) new-val)}'s case,
@code{new-val} is a lisp string.
@end itemize
@end itemize
@subsubsection Traps and Pitfalls
@node sb grovel traps
@subsection Traps and Pitfalls
Basically, you can treat functions and data structure definitions that
sb-grovel spits out as if they were alien routines and types. This has
a few implications that might not be immediately obvious (especially
@ -239,13 +247,12 @@ if you have programmed in a previous version of sb-grovel that didn't
use alien types):
@itemize
@item
You must take care of grovel-allocated structures yourself. They are
alien types, so the garbage collector will not collect them when you
drop the last reference.
@item You must take care of grovel-allocated structures yourself. They
are alien types, so the garbage collector will not collect them
when you drop the last reference.
@item
If you use the @code{with-mystruct} macro, be sure that no references
to the variable thus allocated leaks out. It will be deallocated when
the block exits.
@item If you use the @code{with-mystruct} macro, be sure that no references
to the variable thus allocated leaks out. It will be deallocated
when the block exits.
@end itemize

View file

@ -17,11 +17,9 @@
;;; own project, there will be much wailing and gnashing of teeth.
;;; Your teeth. If need be, we'll kick them for you. This is a
;;; contrib, we're allowed to look in internals. You're an
;;; application programmer, and are not.
;;; application programmer and are not.
;;; TODO
;;; 1) structs don't have within-file location info. problem for the
;;; structure itself, accessors, the copier and the predicate
;;; 3) error handling. Signal random errors, or handle and resignal 'our'
;;; error, or return NIL?
;;; 4) FIXMEs
@ -69,7 +67,7 @@
;;;
(deftype debug-info ()
"Structure containing all the debug information related to a function.
Function objects reference debug-infos which in turn reference
Function objects reference debug-infos, which in turn reference
debug-sources and so on."
'sb-c::compiled-debug-info)
@ -94,8 +92,10 @@ include the pathname of the file and the position of the definition."
(sb-c::debug-info-source debug-info))
(defun valid-function-name-p (name)
"True if NAME denotes a valid function name, ie. one that can be passed to
FBOUNDP."
"See if NAME is a valid function name. In addition to the ANSI
definition of function name, which is symbols plus lists like (SETF
SYMBOL), SBCL allows (SB-EXT:CAS SYMBOL) and various internal
constructs."
(and (sb-int:valid-function-name-p name) t))
;;;; Utilities for code
@ -110,9 +110,9 @@ FBOUNDP."
(declaim (inline map-allocated-code-components))
(defun map-allocated-code-components (spaces fn)
"Call FN for each allocated code component in one of SPACES. FN
receives the object and its size as arguments. SPACES should be a
list of the symbols :dynamic, :static, :read-only, or :immobile on
#+immobile-space"
receives the object and its size as arguments. SPACES should be a list
of the symbols :DYNAMIC, :STATIC, :READ-ONLY, or :IMMOBILE on
#+IMMOBILE-SPACE. The shorthand (:ALL) is also accepted."
(apply #'sb-vm:map-allocated-objects
(lambda (obj header size)
(when (= sb-vm:code-header-widetag header)
@ -121,7 +121,7 @@ list of the symbols :dynamic, :static, :read-only, or :immobile on
(declaim (inline map-caller-code-components))
(defun map-caller-code-components (function spaces fn)
"Call FN for each code component with a fdefn for FUNCTION in its
"Call FN for each code component with a FDEFN for FUNCTION in its
constant pool."
(let ((function (coerce function 'function)))
(map-allocated-code-components
@ -148,32 +148,112 @@ constant pool."
;;;; Finding definitions
(defstruct definition-source
;; Pathname of the source file that the definition was compiled from.
;; This is null if the definition was not compiled from a file.
(pathname nil :type (or null pathname))
;; Source-path of the definition within the file.
;; This may be incomplete depending on the debug level at which the
;; source was compiled.
(form-path '() :type list)
;; Depth first number of the form.
;; FORM-PATH above usually contains just the top-level form number,
;; ideally the proper form path could be dervied from the
;; form-number and the tlf-number, but it's a bit complicated and
;; Slime already knows how to deal with form numbers, so delegate
;; that job to Slime.
(form-number nil :type (or null unsigned-byte))
;; Character offset of the top-level-form containing the definition.
;; This corresponds to the first element of form-path.
(character-offset nil :type (or null unsigned-byte))
;; File-write-date of the source file when compiled.
;; Null if not compiled from a file.
(file-write-date nil :type (or null unsigned-byte))
;; plist from WITH-COMPILATION-UNIT
(plist nil)
(defmacro defstruct* (name-and-options &rest slot-descriptions)
"Like DEFSTRUCT, but support :DOCUMENTATION among slot options.
The documentation is attached to the slot's STRUCTURE-ACCESSOR.
Example:
(defstruct* my-struct
(my-slot nil :documentation \"docstring\"))
In addition to the normal DEFSTRUCT processing, the above also does
the moral equivalent of
(setf (documentation 'my-struct-my-slot 'function) \"docstring\")"
(destructuring-bind (name &rest options)
(sb-c::ensure-list name-and-options)
(let* ((conc-name-option (find :conc-name options :key (lambda (x)
(if (consp x)
(car x)
x))))
(conc-name (cond ((not conc-name-option)
(format nil "~A-" name))
((or (atom conc-name-option)
(null (cdr conc-name-option))
(null (second conc-name-option)))
"")
(t
(string (second conc-name-option)))))
(not-found (gensym))
(set-doc-forms ())
(new-sds
(loop
for sd in slot-descriptions
collect (let ((documentation
(and (listp sd)
(getf (cddr sd) :documentation not-found))))
(cond
((or (not (listp sd))
(eq documentation not-found))
sd)
(t
(let ((accessor-name (intern
(format nil "~A~A" conc-name
(first sd)))))
(push `(setf (documentation ',accessor-name
'function)
,documentation)
set-doc-forms))
(let ((sd (copy-seq sd)))
(remf (cddr sd) :documentation)
sd)))))))
`(progn
(defstruct ,name-and-options
,@new-sds)
,@set-doc-forms))))
;;; FIXME: Rename this
(defstruct* definition-source
"This structure identifies a sexp in a compiled file.
Despite the name, the source location may not correspond to a
definition but to e.g. a function call (see WHO-CALLS)."
(pathname
nil :type (or null pathname)
:documentation "Pathname of the source file.
This is NIL if the source location is not in a compiled file.")
(form-path
'() :type list
:documentation "List of indices that identify the sexp in the
file given by DEFINITION-SOURCE-PATHNAME. The first element in the
list is the index of the top-level form that contains the sexp. If the
file was compiled at a high enough debug level, then the rest of the
elements recursively index into the list structure of the top-level
form.
Thus, the form path is somewhat stable regarding edits in the file,
but it gets invalidated by, for example, inserting a new top-level
form before the sexp in question.")
(form-number
nil :type (or null unsigned-byte)
:documentation "Depth-first index of the sexp within the top-level
form identified by the first element of DEFINITION-SOURCE-FORM-PATH.
That is, this is the index of the sexp in the list of subexpressions
of the top-level form ordered according to depth-first traversal. 0
corresponds to the top-level form itself.
When combined with the index of the top-level form (given by the first
element of DEFINITION-SOURCE-FORM-PATH), the form number allows
reconstruction of the rest of the form path, which may be missing.
This requires parsing the source file. Currently, this job is
delegated to e.g. SLIME.")
(character-offset
nil :type (or null unsigned-byte)
:documentation "Character offset of the top-level form containing
the sexp.")
(file-write-date
nil :type (or null unsigned-byte)
:documentation "FILE-WRITE-DATE of DEFINITION-SOURCE-PATHNAME at
the time of compilation. NIL if not compiled from a file.")
(plist
nil
:documentation "The `SOURCE-PLIST` from WITH-COMPILATION-UNIT in effect
when the file was compiled.")
;; Any extra metadata that the caller might be interested in. For
;; example the specializers of the method whose definition-source this
;; is.
;; example, DEFINITION-SOURCE of a method contains the specializers
;; of the method to help disambiguate it.
;;
;; FIXME: This is currently unexported, but it is also necessary to
;; disambiguate methods. See e.g. WHO-SPECIALIZES-DIRECTLY.
(description nil :type list))
(defun vops-translating-fun (name)
@ -205,48 +285,63 @@ constant pool."
source))))
(defun find-definition-sources-by-name (name type)
"Returns a list of DEFINITION-SOURCEs for the objects of type TYPE
defined with name NAME. NAME may be a symbol or a extended function
name. Type can currently be one of the following:
"Returns a list of DEFINITION-SOURCEs for definitions of NAME with
the given definition TYPE. A DEFINITION-SOURCE object is always
returned for definitions that exist, but the source location (e.g.
DEFINITION-SOURCE-PATHNAME) may be missing. TYPE can currently be one
of the following.
(Public)
:CLASS
:COMPILER-MACRO
:CONDITION
:CONSTANT
:FUNCTION
:GENERIC-FUNCTION
:MACRO
:METHOD
:METHOD-COMBINATION
:PACKAGE
:SETF-EXPANDER
:STRUCTURE
:SYMBOL-MACRO
:TYPE
:ALIEN-TYPE
:VARIABLE
:DECLARATION
- Public definition types:
(Internal)
:OPTIMIZER
:SOURCE-TRANSFORM
:TRANSFORM
:VOP
:IR1-CONVERT
:CLASS
:COMPILER-MACRO
:CONDITION
:CONSTANT
:FUNCTION
:GENERIC-FUNCTION
:MACRO
:METHOD
:METHOD-COMBINATION
:PACKAGE
:SETF-EXPANDER
:STRUCTURE
:SYMBOL-MACRO
:TYPE
:ALIEN-TYPE
:ALIEN-CALLBACK
:VARIABLE
:DECLARATION
If an unsupported TYPE is requested, the function will return NIL.
"
- Internal definition types:
:OPTIMIZER
:SOURCE-TRANSFORM
:TRANSFORM
:VOP
:IR1-CONVERT
Definition types are disjoint. For example, :TYPE refers to DEFTYPEs
but not CLASSes or SB-ALIEN:DEFINE-ALIEN-TYPE, as those are of
definition type :CLASS and :ALIEN-TYPE, respectively. :FUNCTION does
not include :GENERIC-FUNCTION, :CLASS does not include :STRUCTURE,
etc. :VARIABLE refers to non-constant dynamic variables (e.g. those
defined with DEFVAR, DEFPARAMETER, SB-EXT:DEFGLOBAL or
SB-ALIEN:DEFINE-ALIEN-VARIABLE but not with DEFCONSTANT).
Valid NAMEs are generally SYMBOLs with the following exceptions:
- For :COMPILER-MACRO, :FUNCTION, :GENERIC-FUNCTION and :METHOD,
anything that's VALID-FUNCTION-NAME-P is valid.
- For :PACKAGE, string designators are valid.
If an unsupported TYPE is requested or NAME is invalid, this function
returns NIL."
(flet ((get-class (name)
(and (symbolp name)
(find-class name nil)))
(real-fdefinition (name)
;; for getting the real function object, even if the
;; function is being profiled
(let ((profile-info (gethash name sb-profile::*profiled-fun-name->info*)))
(if profile-info
(sb-profile::profile-info-encapsulated-fun profile-info)
(fdefinition name)))))
(sb-ext:unencapsulated-function name)))
(ensure-list
(case type
((:variable)
@ -267,25 +362,28 @@ If an unsupported TYPE is requested, the function will return NIL.
(macro-function name))
(find-definition-source (macro-function name))))
((:compiler-macro)
(when (compiler-macro-function name)
(when (and (valid-function-name-p name)
(compiler-macro-function name))
(find-definition-source (compiler-macro-function name))))
(:ir1-convert
(let ((converter (info :function :ir1-convert name)))
(and converter
(find-definition-source converter))))
(find-definition-source converter))))
((:function :generic-function)
(if (fboundp name)
(when (and (or (consp name)
(and
(not (macro-function name))
(not (special-operator-p name)))))
(let ((fun (real-fdefinition name)))
(when (eq (not (typep fun 'generic-function))
(not (eq type :generic-function)))
(find-definition-source fun))))
(let ((dd (info :function :source-transform name)))
(when (typep dd '(cons defstruct-description))
(find-definition-sources-by-name (dd-name (car dd)) :structure)))))
(when (valid-function-name-p name)
(if (fboundp name)
(when (and (or (consp name)
(and
(not (macro-function name))
(not (special-operator-p name)))))
(let ((fun (real-fdefinition name)))
(when (eq (not (typep fun 'generic-function))
(not (eq type :generic-function)))
(find-definition-source fun))))
(let ((dd (info :function :source-transform name)))
(when (typep dd '(cons defstruct-description))
(find-definition-sources-by-name (dd-name (car dd))
:structure))))))
((:type)
;; Source locations for types are saved separately when the expander
;; is a closure without a good source-location.
@ -296,7 +394,7 @@ If an unsupported TYPE is requested, the function will return NIL.
(when (functionp expander-fun)
(find-definition-source expander-fun))))))
((:method)
(when (fboundp name)
(when (and (valid-function-name-p name) (fboundp name))
(let ((fun (real-fdefinition name)))
(when (typep fun 'generic-function)
(loop for method in (sb-mop::generic-function-methods
@ -334,10 +432,9 @@ If an unsupported TYPE is requested, the function will return NIL.
(translate-source-location
(sb-pcl::method-combination-info-source-location info)))))
((:package)
(when (symbolp name)
(let ((package (find-package name)))
(when package
(find-definition-source package)))))
(let ((package (ignore-errors (find-package name))))
(when package
(find-definition-source package))))
;; TRANSFORM and OPTIMIZER handling from swank-sbcl
((:transform)
(let ((fun-info (info :function :info name)))
@ -379,23 +476,30 @@ If an unsupported TYPE is requested, the function will return NIL.
(sb-c::fun-info-flushable . sb-c::flushable))))
(loop for (reader . name) in otypes
for fn = (funcall reader fun-info)
when (functionp fn) collect
(let ((source (find-definition-source fn)))
(setf (definition-source-description source)
(list name))
source))))))
when (functionp fn)
collect (let ((source (find-definition-source fn)))
(setf (definition-source-description source)
(list name))
source))))))
(:vop
(find-vop-source name))
(:alien-type
(let ((loc (info :source-location type name)))
(and loc
(translate-source-location loc))))
(:alien-callback
(let ((cb (gethash name sb-alien::*alien-callables*)))
(when cb
(let ((index (sb-alien::alien-callback-index cb)))
(when (and index
(array-in-bounds-p sb-alien::*alien-callback-functions* index))
(find-definition-source (aref sb-alien::*alien-callback-functions* index)))))))
((:source-transform)
(let* ((transform-fun
(or (info :function :source-transform name)
(and (typep name '(cons (eql setf) (cons symbol null)))
(info :function :source-transform
(second name)))))
(or (info :function :source-transform name)
(and (typep name '(cons (eql setf) (cons symbol null)))
(info :function :source-transform
(second name)))))
;; A cons for the :source-transform is essentially the same
;; info that was formerly in :structure-accessor.
(accessor (and (consp transform-fun) (cdr transform-fun))))
@ -409,16 +513,28 @@ If an unsupported TYPE is requested, the function will return NIL.
(let ((locations (info :source-location :declaration name)))
(loop for (kind loc) on locations by #'cddr
when loc
collect (let ((loc (translate-source-location loc)))
(setf (definition-source-description loc)
;; Copy list to ensure that user code
;; cannot mutate the original.
(copy-list (ensure-list kind)))
loc))))
collect (let ((loc (translate-source-location loc)))
(setf (definition-source-description loc)
;; Copy list to ensure that user code
;; cannot mutate the original.
(copy-list (ensure-list kind)))
loc))))
(t
nil)))))
(defun find-definition-source (object)
"Return the DEFINITION-SOURCE corresponding to the definition of OBJECT
or NIL if there is no corresponding definition. OBJECT must be a
PACKAGE, FUNCTION, METHOD, METHOD-COMBINATION, SB-MOP:SLOT-DEFINITION,
STANDARD-OBJECT, STRUCTURE-OBJECT, CONDITION, CLASS, STRUCTURE-CLASS,
or a subclass of CONDITION. An error is signalled for other types.
A DEFINITION-SOURCE object is always returned for definitions that
exist, but the source location (e.g. DEFINITION-SOURCE-PATHNAME) may
be missing.
For definitions that do not define an object (e.g. DEFVAR), use
FIND-DEFINITION-SOURCES-BY-NAME."
(typecase object
((or sb-pcl::condition-class sb-pcl::structure-class)
(let ((classoid (sb-pcl::class-classoid object)))
@ -481,8 +597,9 @@ If an unsupported TYPE is requested, the function will return NIL.
(when (stringp (sb-c::debug-source-namestring debug-source))
(parse-namestring (sb-c::debug-source-namestring debug-source)))
:character-offset
(if tlf
(elt (sb-c::debug-source-start-positions debug-source) tlf))
(let ((start-positions (sb-c::debug-source-start-positions debug-source)))
(when (and tlf (< tlf (length start-positions)))
(elt start-positions tlf)))
:form-path (if tlf (list tlf))
:form-number (handler-case (sb-di::code-location-form-number
(sb-di::debug-fun-start-location debug-fun))
@ -514,13 +631,13 @@ If an unsupported TYPE is requested, the function will return NIL.
(function-lambda-list function))
(defun function-lambda-list (function)
"Return the lambda list for the extended function designator FUNCTION.
Works for special-operators, macros, simple functions, interpreted functions,
and generic functions. Signals an error if FUNCTION is not a valid extended
function designator.
"Return the lambda list of FUNCTION.
FUNCTION must be a function object or a function name in the sense of
VALID-FUNCTION-NAME-P. Works for special operators, macros, simple
functions, interpreted functions, and generic functions.
If the function does not have a lambda list (compiled with debug 0),
then two values are returned: (values nil t)"
The second return value indicates whether the lambda list could not be
determined (e.g. because the function was compiled with DEBUG 0)."
(cond ((and (symbolp function) (special-operator-p function))
(function-lambda-list (info :function :ir1-convert function)))
((valid-function-name-p function)
@ -530,26 +647,34 @@ then two values are returned: (values nil t)"
((typep function 'generic-function)
(sb-pcl::generic-function-pretty-arglist function))
(t
(let ((raw-result (%fun-lambda-list function)))
(let ((raw-result (%fun-lambda-list (sb-ext:unencapsulated-function function))))
(if (eq raw-result :unknown)
(values nil t)
(values raw-result nil))))))
(defun deftype-lambda-list (typespec-operator)
"Returns the lambda list of TYPESPEC-OPERATOR as first return
value, and a flag whether the arglist could be found as second
value."
(check-type typespec-operator symbol)
;; Don't return a lambda-list for combinators AND,OR,NOT.
(let* ((f (and (info :type :kind typespec-operator)
(info :type :expander typespec-operator)))
(defun deftype-lambda-list (type-specifier-name)
"Returns the lambda list of TYPE-SPECIFIER-NAME as the first return
value, and a flag whether the arglist could be found as the second
value.
TYPE-SPECIFIER-NAME must be a symbol. This function can find the
lambda list of derived type specifiers (e.g. those defined with
DEFTYPE) and classes with compound type specifier syntaxes (e.g. the
class FLOAT). It returns NIL, NIL for other type specifiers (e.g. AND,
OR, NOT) and types (e.g. LIST)."
(check-type type-specifier-name symbol)
(let* ((f (and (info :type :kind type-specifier-name)
(info :type :expander type-specifier-name)))
(f (if (listp f) (car f) f)))
(if (functionp f)
(values (%fun-lambda-list f) t)
(let ((lambda-list (%fun-lambda-list f)))
(if (eq lambda-list :unknown)
(values nil nil)
(values lambda-list t)))
(values nil nil))))
(defun method-combination-lambda-list (method-combination)
"Return the lambda-list of METHOD-COMBINATION designator.
"Return the lambda list of the METHOD-COMBINATION designator.
METHOD-COMBINATION can be a method combination object,
or a method combination name."
(let* ((name (etypecase method-combination
@ -561,7 +686,7 @@ or a method combination name."
(sb-pcl::method-combination-info-lambda-list info)))
(defun function-type (function-designator)
"Returns the ftype of FUNCTION-DESIGNATOR, or NIL."
"Returns the ftype of FUNCTION-DESIGNATOR or NIL."
(etypecase function-designator
((or symbol cons)
;; XXX: why require FBOUNDP? Would it be wrong to always report the proclaimed type?
@ -629,7 +754,13 @@ or a method combination name."
callees)))
(defun find-function-callers (function &optional (spaces '(:all)))
"Return functions which call FUNCTION, by searching SPACES for code objects"
;; FIXME: :IMMOBILE-SPACE is an internal feature
"List functions that call FUNCTION by searching SPACES for code objects.
This can make previously garbage objects live.
SPACES should be a list of the symbols :DYNAMIC, :STATIC, :READ-ONLY,
or :IMMOBILE on `#+IMMOBILE-SPACE`. The shorthand (:ALL) is also
accepted."
(let ((referrers '()))
(map-caller-code-components
function
@ -798,47 +929,45 @@ or a method combination name."
result)))))
(defun who-calls (function-name)
"Use the xref facility to search for source locations where the
global function named FUNCTION-NAME is called. Returns a list of
function name, definition-source pairs."
"Find the source locations where the global function FUNCTION-NAME is
called, and return them as an alist of function or macro name,
DEFINITION-SOURCE pairs."
(collect-xref :calls function-name))
(defun who-binds (symbol)
"Use the xref facility to search for source locations where the
special variable SYMBOL is rebound. Returns a list of function name,
definition-source pairs."
"Find the source locations where the special variable SYMBOL is bound,
and return them as an alist of function or macro name,
DEFINITION-SOURCE pairs."
(collect-xref :binds symbol))
(defun who-references (symbol)
"Use the xref facility to search for source locations where the
special variable or constant SYMBOL is read. Returns a list of function
name, definition-source pairs."
"Find the source locations where the special variable SYMBOL is read,
and return them as an alist of function or macro name,
DEFINITION-SOURCE pairs."
(collect-xref :references symbol))
(defun who-sets (symbol)
"Use the xref facility to search for source locations where the
special variable SYMBOL is written to. Returns a list of function name,
definition-source pairs."
"Find the source locations where the special variable SYMBOL is set,
and return them as an alist of function or macro name,
DEFINITION-SOURCE pairs."
(collect-xref :sets symbol))
(defun who-macroexpands (macro-name)
"Use the xref facility to search for source locations where the
macro MACRO-NAME is expanded. Returns a list of function name,
definition-source pairs."
"Find the source locations where the macro MACRO-NAME is expanded, and
return them as an alist of function or macro name, DEFINITION-SOURCE
pairs."
(collect-xref :macroexpands macro-name))
(defun who-specializes-directly (class-designator)
"Search for source locations of methods directly specializing on
CLASS-DESIGNATOR. Returns an alist of method name, definition-source
pairs.
"Find the source locations of methods directly specializing on
CLASS-DESIGNATOR, and return them as an alist of generic function
name, DEFINITION-SOURCE pairs.
A method matches the criterion either if it specializes on the same
class as CLASS-DESIGNATOR designates (this includes CLASS-EQ
specializers), or if it eql-specializes on an instance of the
designated class.
class as CLASS-DESIGNATOR designates, or if it eql-specializes on an
instance of the designated class.
Experimental.
"
Experimental."
(let ((class (canonicalize-class-designator class-designator)))
(unless class
(return-from who-specializes-directly nil))
@ -861,17 +990,17 @@ Experimental.
result))))
(defun who-specializes-generally (class-designator)
"Search for source locations of methods specializing on
CLASS-DESIGNATOR, or a subclass of it. Returns an alist of method
name, definition-source pairs.
"Find the source locations of methods specializing on
CLASS-DESIGNATOR or a subclass of it, and return them as an alist of
generic function name, DEFINITION-SOURCE pairs.
DEFINITION-SOURCE-DESCRIPTION identifies the method.
A method matches the criterion either if it specializes on the
designated class itself or a subclass of it (this includes CLASS-EQ
specializers), or if it eql-specializes on an instance of the
designated class or a subclass of it.
Experimental.
"
Experimental."
(let ((class (canonicalize-class-designator class-designator)))
(unless class
(return-from who-specializes-generally nil))
@ -923,12 +1052,12 @@ Experimental.
1)))
(defun allocation-information (object)
"Returns information about the allocation of OBJECT. Primary return value
indicates the general type of allocation: :IMMEDIATE, :HEAP, :STACK,
or :FOREIGN.
"Returns information about the allocation of OBJECT. The primary return
value indicates the general type of allocation: :IMMEDIATE, :HEAP,
:STACK, or :FOREIGN.
Possible secondary return value provides additional information about the
allocation.
Non-NIL secondary return values provide additional information about
the allocation.
For :HEAP objects the secondary value is a plist:
@ -936,7 +1065,7 @@ For :HEAP objects the secondary value is a plist:
Indicates the heap segment the object is allocated in.
:GENERATION
Is the current generation of the object: 0 for nursery, 6 for pseudo-static
The current generation of the object: 0 for nursery, 6 for pseudo-static
generation loaded from core. (GENCGC and :SPACE :DYNAMIC only.)
:LARGE
@ -945,13 +1074,13 @@ For :HEAP objects the secondary value is a plist:
:BOXED
Indicates that the object is allocated in a boxed region. Unboxed
allocation is used for eg. specialized arrays after they have survived one
allocation is used for e.g. specialized arrays after they have survived one
collection. (GENCGC and :SPACE :DYNAMIC only.)
:PINNED
Indicates that the page(s) on which the object resides are kept live due
to conservative references. Note that object may reside on a pinned page
even if :PINNED in NIL if the GC has not had the need to mark the the page
even if :PINNED is NIL if the GC has not had the need to mark the page
as pinned. (GENCGC and :SPACE :DYNAMIC only.)
:WRITE-PROTECTED
@ -960,11 +1089,11 @@ For :HEAP objects the secondary value is a plist:
the last GC of its generation. (GENCGC and :SPACE :DYNAMIC only.)
:PAGE
The index of the page the object resides on. (GENGC and :SPACE :DYNAMIC
The index of the page the object resides on. (GENCGC and :SPACE :DYNAMIC
only.)
For :STACK objects secondary value is the thread on whose stack the object is
allocated.
For :STACK objects, the secondary value is the thread on whose stack
the object is allocated.
Expected use-cases include introspection to gain insight into allocation and
GC behaviour and restricting memoization to heap-allocated arguments.
@ -1022,17 +1151,17 @@ Experimental: interface subject to change."
Returns OBJECT.
If SIMPLE is true (default is NIL), elides those pointers that are not
notionally part of certain built-in objects, but backpointers to a
conceptual parent: eg. elides the pointer from a SYMBOL to the
notionally part of certain built-in objects but backpointers to a
conceptual parent: e.g. elides the pointer from a SYMBOL to the
corresponding PACKAGE.
If EXT is true (default is T), includes some pointers that are not
actually contained in the object, but found in certain well-known
actually contained in the object but found in certain well-known
indirect containers: FDEFINITIONs, EQL specializers, classes, and
thread-local symbol values in other threads fall into this category.
NOTE: calling MAP-ROOT with a THREAD does not currently map over
conservative roots from the thread registers and interrupt contexts.
> _Note_: calling MAP-ROOT with a THREAD does not currently map over
> conservative roots from the thread registers and interrupt contexts.
Experimental: interface subject to change."
(when (typep object '(or bignum float sb-sys:system-area-pointer

View file

@ -0,0 +1,45 @@
(in-package :sb-manual)
(defsection @sb-introspect (:title "sb-introspect")
"The `SB-INTROSPECT` module is about finding definitions, as well
as querying their properties and relationships in the running image."
(@finding-definitions section)
(@sb-introspect-variables section)
(@sb-introspect-functions section)
(@sb-introspect-types section)
(@sb-introspect-allocation section))
(defsection @finding-definitions (:title "Finding Definitions")
(sb-introspect:definition-source structure)
(sb-introspect:definition-source-pathname function)
(sb-introspect:definition-source-form-path function)
(sb-introspect:definition-source-form-number function)
(sb-introspect:definition-source-character-offset function)
(sb-introspect:definition-source-file-write-date function)
(sb-introspect:definition-source-plist function)
(sb-introspect:find-definition-source function)
(sb-introspect:find-definition-sources-by-name function))
(defsection @sb-introspect-variables (:title "Special Variables")
(sb-introspect:who-binds function)
(sb-introspect:who-references function)
(sb-introspect:who-sets function))
(defsection @sb-introspect-functions (:title "Functions")
(sb-introspect:function-lambda-list function)
(sb-introspect:function-type function)
(sb-introspect:method-combination-lambda-list function)
(sb-introspect:valid-function-name-p function)
(sb-introspect:find-function-callers function)
(sb-introspect:find-function-callees function)
(sb-introspect:who-calls function)
(sb-introspect:who-macroexpands function))
(defsection @sb-introspect-types (:title "Types and Classes")
(sb-introspect:deftype-lambda-list function)
(sb-introspect:who-specializes-directly function)
(sb-introspect:who-specializes-generally function))
(defsection @sb-introspect-allocation (:title "Allocation")
(sb-introspect:allocation-information function)
(sb-introspect:map-root function))

View file

@ -0,0 +1,363 @@
@c Generated by the sb-manual contrib. Do not edit.
@node sb introspect
@section sb-introspect
@menu
* Finding Definitions: finding definitions.
* Special Variables: sb introspect variables.
* Functions: sb introspect functions.
* Types and Classes: sb introspect types.
* Allocation: sb introspect allocation.
@end menu
The @code{sb-introspect} module is about finding definitions, as well
as querying their properties and relationships in the running image.
@node finding definitions
@subsection Finding Definitions
@anchor{Structure sb-introspect definition-source}
@ttindex @sortas{definition-source sb-introspect} definition-source [sb-introspect]
@deffn{Structure} sb-introspect:definition-source
This structure identifies a sexp in a compiled file.
Despite the name, the source location may not correspond to a
definition but to e.g. a function call (see @code{who-calls}).
@end deffn
@anchor{Function sb-introspect definition-source-pathname}
@ffindex @sortas{definition-source-pathname sb-introspect} definition-source-pathname [sb-introspect]
@deffn{Function} sb-introspect:definition-source-pathname instance
Pathname of the source file.
This is @code{nil} if the source location is not in a compiled file.
@end deffn
@anchor{Function sb-introspect definition-source-form-path}
@ffindex @sortas{definition-source-form-path sb-introspect} definition-source-form-path [sb-introspect]
@deffn{Function} sb-introspect:definition-source-form-path instance
List of indices that identify the sexp in the
file given by @code{definition-source-pathname}. The first element in the
list is the index of the top-level form that contains the sexp. If the
file was compiled at a high enough debug level, then the rest of the
elements recursively index into the list structure of the top-level
form.
Thus, the form path is somewhat stable regarding edits in the file,
but it gets invalidated by, for example, inserting a new top-level
form before the sexp in question.
@end deffn
@anchor{Function sb-introspect definition-source-form-number}
@ffindex @sortas{definition-source-form-number sb-introspect} definition-source-form-number [sb-introspect]
@deffn{Function} sb-introspect:definition-source-form-number instance
Depth-first index of the sexp within the top-level
form identified by the first element of @code{definition-source-form-path}.
That is, this is the index of the sexp in the list of subexpressions
of the top-level form ordered according to depth-first traversal. 0
corresponds to the top-level form itself.
When combined with the index of the top-level form (given by the first
element of @code{definition-source-form-path}), the form number allows
reconstruction of the rest of the form path, which may be missing.
This requires parsing the source file. Currently, this job is
delegated to e.g. SLIME.
@end deffn
@anchor{Function sb-introspect definition-source-character-offset}
@ffindex @sortas{definition-source-character-offset sb-introspect} definition-source-character-offset [sb-introspect]
@deffn{Function} sb-introspect:definition-source-character-offset instance
Character offset of the top-level form containing
the sexp.
@end deffn
@anchor{Function sb-introspect definition-source-file-write-date}
@ffindex @sortas{definition-source-file-write-date sb-introspect} definition-source-file-write-date [sb-introspect]
@deffn{Function} sb-introspect:definition-source-file-write-date instance
@code{file-write-date} of @code{definition-source-pathname} at
the time of compilation. @code{nil} if not compiled from a file.
@end deffn
@anchor{Function sb-introspect definition-source-plist}
@ffindex @sortas{definition-source-plist sb-introspect} definition-source-plist [sb-introspect]
@deffn{Function} sb-introspect:definition-source-plist instance
The @code{source-plist} from @code{with-compilation-unit} in effect
when the file was compiled.
@end deffn
@anchor{Function sb-introspect find-definition-source}
@ffindex @sortas{find-definition-source sb-introspect} find-definition-source [sb-introspect]
@deffn{Function} sb-introspect:find-definition-source object
Return the @code{definition-source} corresponding to the definition of @code{object}
or @code{nil} if there is no corresponding definition. @code{object} must be a
@code{package}, @code{function}, @code{method}, @code{method-combination}, @code{sb-mop:slot-definition},
@code{standard-object}, @code{structure-object}, @code{condition}, @code{class}, @code{structure-class},
or a subclass of @code{condition}. An error is signalled for other types.
A @code{definition-source} object is always returned for definitions that
exist, but the source location (e.g. @code{definition-source-pathname}) may
be missing.
For definitions that do not define an object (e.g. @code{defvar}), use
@code{find-definition-sources-by-name}.
@end deffn
@anchor{Function sb-introspect find-definition-sources-by-name}
@ffindex @sortas{find-definition-sources-by-name sb-introspect} find-definition-sources-by-name [sb-introspect]
@deffn{Function} sb-introspect:find-definition-sources-by-name name type
Returns a list of @code{definition-source}s for definitions of @code{name} with
the given definition @code{type}. A @code{definition-source} object is always
returned for definitions that exist, but the source location (e.g.
@code{definition-source-pathname}) may be missing. @code{type} can currently be one
of the following.
@itemize
@item Public definition types:
@code{:class}
@code{:compiler-macro}
@code{:condition}
@code{:constant}
@code{:function}
@code{:generic-function}
@code{:macro}
@code{:method}
@code{:method-combination}
@code{:package}
@code{:setf-expander}
@code{:structure}
@code{:symbol-macro}
@code{:type}
@code{:alien-type}
@code{:alien-callback}
@code{:variable}
@code{:declaration}
@item Internal definition types:
@code{:optimizer}
@code{:source-transform}
@code{:transform}
@code{:vop}
@code{:ir1-convert}
@end itemize
Definition types are disjoint. For example, @code{:type} refers to @code{deftype}s
but not @code{class}es or @code{sb-alien:define-alien-type}, as those are of
definition type @code{:class} and @code{:alien-type}, respectively. @code{:function} does
not include @code{:generic-function}, @code{:class} does not include @code{:structure},
etc. @code{:variable} refers to non-constant dynamic variables (e.g. those
defined with @code{defvar}, @code{defparameter}, @code{sb-ext:defglobal} or
@code{sb-alien:define-alien-variable} but not with @code{defconstant}).
Valid @code{name}s are generally @code{symbol}s with the following exceptions:
@itemize
@item For @code{:compiler-macro}, @code{:function}, @code{:generic-function} and @code{:method},
anything that's @code{valid-function-name-p} is valid.
@item For @code{:package}, string designators are valid.
@end itemize
If an unsupported @code{type} is requested or @code{name} is invalid, this function
returns @code{nil}.
@end deffn
@node sb introspect variables
@subsection Special Variables
@anchor{Function sb-introspect who-binds}
@ffindex @sortas{who-binds sb-introspect} who-binds [sb-introspect]
@deffn{Function} sb-introspect:who-binds symbol
Find the source locations where the special variable @code{symbol} is bound,
and return them as an alist of function or macro name,
@code{definition-source} pairs.
@end deffn
@anchor{Function sb-introspect who-references}
@ffindex @sortas{who-references sb-introspect} who-references [sb-introspect]
@deffn{Function} sb-introspect:who-references symbol
Find the source locations where the special variable @code{symbol} is read,
and return them as an alist of function or macro name,
@code{definition-source} pairs.
@end deffn
@anchor{Function sb-introspect who-sets}
@ffindex @sortas{who-sets sb-introspect} who-sets [sb-introspect]
@deffn{Function} sb-introspect:who-sets symbol
Find the source locations where the special variable @code{symbol} is set,
and return them as an alist of function or macro name,
@code{definition-source} pairs.
@end deffn
@node sb introspect functions
@subsection Functions
@anchor{Function sb-introspect function-lambda-list}
@ffindex @sortas{function-lambda-list sb-introspect} function-lambda-list [sb-introspect]
@deffn{Function} sb-introspect:function-lambda-list function
Return the lambda list of @code{function}.
@code{function} must be a function object or a function name in the sense of
@code{valid-function-name-p}. Works for special operators, macros, simple
functions, interpreted functions, and generic functions.
The second return value indicates whether the lambda list could not be
determined (e.g. because the function was compiled with @code{debug} 0).
@end deffn
@anchor{Function sb-introspect function-type}
@ffindex @sortas{function-type sb-introspect} function-type [sb-introspect]
@deffn{Function} sb-introspect:function-type function-designator
Returns the ftype of @code{function-designator} or @code{nil}.
@end deffn
@anchor{Function sb-introspect method-combination-lambda-list}
@ffindex @sortas{method-combination-lambda-list sb-introspect} method-combination-lambda-list [sb-introspect]
@deffn{Function} sb-introspect:method-combination-lambda-list method-combination
Return the lambda list of the @code{method-combination} designator.
@code{method-combination} can be a method combination object,
or a method combination name.
@end deffn
@anchor{Function sb-introspect valid-function-name-p}
@ffindex @sortas{valid-function-name-p sb-introspect} valid-function-name-p [sb-introspect]
@deffn{Function} sb-introspect:valid-function-name-p name
See if @code{name} is a valid function name. In addition to the ANSI
definition of function name, which is symbols plus lists like (@code{setf}
@code{symbol}), SBCL allows (@code{sb-ext:cas} @code{symbol}) and various internal
constructs.
@end deffn
@anchor{Function sb-introspect find-function-callers}
@ffindex @sortas{find-function-callers sb-introspect} find-function-callers [sb-introspect]
@deffn{Function} sb-introspect:find-function-callers function &optional spaces
List functions that call @code{function} by searching @code{spaces} for code objects.
This can make previously garbage objects live.
@code{spaces} should be a list of the symbols @code{:dynamic}, @code{:static}, @code{:read-only},
or @code{:immobile} on @code{#+immobile-space}. The shorthand (@code{:all}) is also
accepted.
@end deffn
@anchor{Function sb-introspect find-function-callees}
@ffindex @sortas{find-function-callees sb-introspect} find-function-callees [sb-introspect]
@deffn{Function} sb-introspect:find-function-callees function
Return functions called by @code{function}.
@end deffn
@anchor{Function sb-introspect who-calls}
@ffindex @sortas{who-calls sb-introspect} who-calls [sb-introspect]
@deffn{Function} sb-introspect:who-calls function-name
Find the source locations where the global function @code{function-name} is
called, and return them as an alist of function or macro name,
@code{definition-source} pairs.
@end deffn
@anchor{Function sb-introspect who-macroexpands}
@ffindex @sortas{who-macroexpands sb-introspect} who-macroexpands [sb-introspect]
@deffn{Function} sb-introspect:who-macroexpands macro-name
Find the source locations where the macro @code{macro-name} is expanded, and
return them as an alist of function or macro name, @code{definition-source}
pairs.
@end deffn
@node sb introspect types
@subsection Types and Classes
@anchor{Function sb-introspect deftype-lambda-list}
@ffindex @sortas{deftype-lambda-list sb-introspect} deftype-lambda-list [sb-introspect]
@deffn{Function} sb-introspect:deftype-lambda-list type-specifier-name
Returns the lambda list of @code{type-specifier-name} as the first return
value, and a flag whether the arglist could be found as the second
value.
@code{type-specifier-name} must be a symbol. This function can find the
lambda list of derived type specifiers (e.g. those defined with
@code{deftype}) and classes with compound type specifier syntaxes (e.g. the
class @code{float}). It returns @code{nil}, @code{nil} for other type specifiers (e.g. @code{and},
@code{or}, @code{not}) and types (e.g. @code{list}).
@end deffn
@anchor{Function sb-introspect who-specializes-directly}
@ffindex @sortas{who-specializes-directly sb-introspect} who-specializes-directly [sb-introspect]
@deffn{Function} sb-introspect:who-specializes-directly class-designator
Find the source locations of methods directly specializing on
@code{class-designator}, and return them as an alist of generic function
name, @code{definition-source} pairs.
A method matches the criterion either if it specializes on the same
class as @code{class-designator} designates, or if it eql-specializes on an
instance of the designated class.
Experimental.
@end deffn
@anchor{Function sb-introspect who-specializes-generally}
@ffindex @sortas{who-specializes-generally sb-introspect} who-specializes-generally [sb-introspect]
@deffn{Function} sb-introspect:who-specializes-generally class-designator
Find the source locations of methods specializing on
@code{class-designator} or a subclass of it, and return them as an alist of
generic function name, @code{definition-source} pairs.
@code{definition-source-description} identifies the method.
A method matches the criterion either if it specializes on the
designated class itself or a subclass of it (this includes CLASS-EQ
specializers), or if it eql-specializes on an instance of the
designated class or a subclass of it.
Experimental.
@end deffn
@node sb introspect allocation
@subsection Allocation
@anchor{Function sb-introspect allocation-information}
@ffindex @sortas{allocation-information sb-introspect} allocation-information [sb-introspect]
@deffn{Function} sb-introspect:allocation-information object
Returns information about the allocation of @code{object}. The primary return
value indicates the general type of allocation: @code{:immediate}, @code{:heap},
@code{:stack}, or @code{:foreign}.
Non-NIL secondary return values provide additional information about
the allocation.
For @code{:heap} objects the secondary value is a plist:
@code{:space}
Indicates the heap segment the object is allocated in.
@code{:generation}
The current generation of the object: 0 for nursery, 6 for pseudo-static
generation loaded from core. (GENCGC and @code{:space} @code{:dynamic} only.)
@code{:large}
Indicates a "large" object subject to non-copying
promotion. (GENCGC and @code{:space} @code{:dynamic} only.)
@code{:boxed}
Indicates that the object is allocated in a boxed region. Unboxed
allocation is used for e.g. specialized arrays after they have survived one
collection. (GENCGC and @code{:space} @code{:dynamic} only.)
@code{:pinned}
Indicates that the page(s) on which the object resides are kept live due
to conservative references. Note that object may reside on a pinned page
even if @code{:pinned} is @code{nil} if the GC has not had the need to mark the page
as pinned. (GENCGC and @code{:space} @code{:dynamic} only.)
@code{:write-protected}
Indicates that the page on which the object starts is write-protected,
which indicates for @code{:boxed} objects that it hasn't been written to since
the last GC of its generation. (GENCGC and @code{:space} @code{:dynamic} only.)
@code{:page}
The index of the page the object resides on. (GENCGC and @code{:space} @code{:dynamic}
only.)
For @code{:stack} objects, the secondary value is the thread on whose stack
the object is allocated.
Expected use-cases include introspection to gain insight into allocation and
GC behaviour and restricting memoization to heap-allocated arguments.
Experimental: interface subject to change.
@end deffn
@anchor{Function sb-introspect map-root}
@ffindex @sortas{map-root sb-introspect} map-root [sb-introspect]
@deffn{Function} sb-introspect:map-root function object &key simple ext
Call @code{function} with all non-immediate objects pointed to by @code{object}.
Returns @code{object}.
If @code{simple} is true (default is @code{nil}), elides those pointers that are not
notionally part of certain built-in objects but backpointers to a
conceptual parent: e.g. elides the pointer from a @code{symbol} to the
corresponding @code{package}.
If @code{ext} is true (default is @code{t}), includes some pointers that are not
actually contained in the object but found in certain well-known
indirect containers: @code{fdefinition}s, @code{eql} specializers, classes, and
thread-local symbol values in other threads fall into this category.
@quotation
@emph{Note}: calling @code{map-root} with a THREAD does not currently map over
conservative roots from the thread registers and interrupt contexts.
@end quotation
Experimental: interface subject to change.
@end deffn

View file

@ -8,7 +8,7 @@
;;;; files for more information.
(defpackage :sb-introspect-test
(:import-from #:test-util #:deftest)
(:import-from #:test-util #:deftest #:with-test)
(:use "SB-INTROSPECT" "CL"))
(in-package :sb-introspect-test)
@ -47,6 +47,11 @@
'(x b))
t)
(deftest deftype-lambda-list.1
(deftype-lambda-list 'cl-user::0-debug-type)
nil
nil)
(defmacro interpret (form)
`(let ((sb-ext:*evaluator-mode* :interpret))
(eval ',form)))
@ -70,7 +75,7 @@
'(x &key (b "abc")))
t)
(test-util:with-test (:name definition-source.1 :skipped-on :no-source-locs)
(with-test (:name definition-source.1 :skipped-on :no-source-locs)
#+sb-devel
(assert (consp (find-definition-sources-by-name 'vectorp :vop)))
(assert (consp (find-definition-sources-by-name 'check-type :macro))))
@ -92,7 +97,7 @@
;;; The behavior of :SOURCE-PLIST on nested WITH-COMPILATION-UNIT
;;; is to append. This is documented in source/compiler/main
(test-util:with-test (:name :definition-source-plist.2)
(with-test (:name :definition-source-plist.2)
(let ((plist (definition-source-plist
(find-definition-source #'cl-user::four))))
(assert (equal (getf plist :test-outer) "OUT"))
@ -122,25 +127,25 @@
(matchp #'cl-user::one 2)
t)
(test-util:with-test (:name find-source-stuff.3 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.3 :skipped-on :no-source-locs)
(assert (matchp-name :generic-function 'cl-user::two 3)))
(test-util:with-test (:name find-source-stuff.4 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.4 :skipped-on :no-source-locs)
(assert (matchp (car (sb-mop:generic-function-methods #'cl-user::two)) 4)))
(test-util:with-test (:name find-source-stuff.5 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.5 :skipped-on :no-source-locs)
(assert (matchp-name :variable 'cl-user::*a* 8)))
(test-util:with-test (:name find-source-stuff.6 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.6 :skipped-on :no-source-locs)
(assert (matchp-name :variable 'cl-user::*b* 9)))
(test-util:with-test (:name find-source-stuff.7 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.7 :skipped-on :no-source-locs)
(assert (matchp-name :class 'cl-user::a 10)))
(test-util:with-test (:name find-source-stuff.8 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.8 :skipped-on :no-source-locs)
(assert (matchp-name :condition 'cl-user::b 11)))
(test-util:with-test (:name find-source-stuff.9 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.9 :skipped-on :no-source-locs)
(assert (matchp-name :structure 'cl-user::c 12)))
(deftest find-source-stuff.10
@ -151,7 +156,7 @@
(matchp-name :function 'cl-user::c-e 12)
t)
(test-util:with-test (:name find-source-stuff.12 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.12 :skipped-on :no-source-locs)
(assert (matchp-name :structure 'cl-user::d 13)))
(deftest find-source-stuff.13
@ -162,16 +167,16 @@
(matchp-name :function 'cl-user::d-e 13)
t)
(test-util:with-test (:name find-source-stuff.15 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.15 :skipped-on :no-source-locs)
(assert (matchp-name :package 'cl-user::e 14)))
(test-util:with-test (:name find-source-stuff.16 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.16 :skipped-on :no-source-locs)
(assert (matchp-name :symbol-macro 'cl-user::f 15)))
(test-util:with-test (:name find-source-stuff.17 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.17 :skipped-on :no-source-locs)
(assert (matchp-name :type 'cl-user::g 16)))
(test-util:with-test (:name find-source-stuff.18 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.18 :skipped-on :no-source-locs)
(assert (matchp-name :constant 'cl-user::+h+ 17)))
(deftest find-source-stuff.19
@ -194,7 +199,7 @@
(matchp-name :function '(setf cl-user::o) 23)
t)
(test-util:with-test (:name find-source-stuff.24 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.24 :skipped-on :no-source-locs)
(assert (matchp-name :method '(setf cl-user::p) 24)))
(deftest find-source-stuff.25
@ -202,7 +207,7 @@
t)
(test-util:with-test (:name find-source-stuff.26 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.26 :skipped-on :no-source-locs)
(assert (matchp-name :method-combination 'cl-user::r 26)))
@ -238,7 +243,7 @@
(matchp-name :function 'cl-user::loaded-as-source-fun 3)
t)
(test-util:with-test (:name find-source-stuff.33 :skipped-on :no-source-locs)
(with-test (:name find-source-stuff.33 :skipped-on :no-source-locs)
(assert (matchp-name :variable 'cl-user::**global** 29)))
;;; Check wrt. interplay of generic functions and their methods.
@ -366,7 +371,7 @@
(tai 42s0 :immediate nil)
t)
(test-util:with-test (:name :allocation-information.4
(with-test (:name :allocation-information.4
;; Ignored as per the comment above, even though it seems
;; unlikely that this is the right condition.
:fails-on (or :ppc64 (and :sparc :gencgc)))
@ -383,7 +388,7 @@
(setq *large-obj* (make-array (* sb-vm:gencgc-page-bytes 4)
:element-type '(unsigned-byte 8)))
(sb-ext:gc :gen 1) ; Array won't move to a large unboxed page until GC'd
(test-util:with-test (:name allocation-information.5
(with-test (:name allocation-information.5
:skipped-on :mark-region-gc) ; doesn't move to an unboxed page
(tai *large-obj* :heap
`(:space :dynamic :generation 1 :boxed nil :pinned nil :large t)
@ -731,20 +736,23 @@
t
t)
(test-util:with-test (:name alien-type.1 :skipped-on :no-source-locs)
(with-test (:name alien-type.1 :skipped-on :no-source-locs)
(assert (matchp-name :alien-type 'cl-user::test-alien-type 30)))
(test-util:with-test (:name alien-type.2 :skipped-on :no-source-locs)
(with-test (:name alien-type.2 :skipped-on :no-source-locs)
(assert (matchp-name :alien-type 'cl-user::test-alien-struct 31)))
(test-util:with-test (:name alien-variable :skipped-on :no-source-locs)
(with-test (:name alien-variable :skipped-on :no-source-locs)
(assert (matchp-name :variable 'cl-user::test-alien-var 32)))
(test-util:with-test (:name condition-slot-reader :skipped-on :no-source-locs)
(matchp-name :method 'cl-user::condition-slot-reader 33))
(with-test (:name alien-callable :skipped-on :no-source-locs)
(assert (matchp-name :alien-callback 'cl-user::alien-comparator 33)))
(test-util:with-test (:name condition-slot-writer :skipped-on :no-source-locs)
(matchp-name :method 'cl-user::condition-slot-writer 33))
(with-test (:name condition-slot-reader :skipped-on :no-source-locs)
(matchp-name :method 'cl-user::condition-slot-reader 34))
(with-test (:name condition-slot-writer :skipped-on :no-source-locs)
(matchp-name :method 'cl-user::condition-slot-writer 34))
(deftest function-with-a-local-function
(sb-introspect:definition-source-form-number
@ -796,10 +804,50 @@
(defun sets-equalp (a b) (and (subsetp a b) (subsetp b a)))
(deftest find-callees
(sets-equalp (sb-introspect:find-function-callees #'sb-c::find-dominators)
(list #'sb-c::dfo-as-needed))
(list #'sb-c::dfo-as-needed #'sb-c::lowest-common-dominator))
t)
(deftest find-callers
(let ((callers (sb-introspect:find-function-callers #'sb-c::dfo-as-needed)))
(and (>= (length callers) 5)
(not (null (member #'sb-c::find-dominators callers)))))
t)
(defparameter *definition-types*
'(:class
:compiler-macro
:condition
:constant
:function
:generic-function
:macro
:method
:method-combination
:package
:setf-expander
:structure
:symbol-macro
:type
:alien-type
:alien-callback
:variable
:declaration
:optimizer
:source-transform
:transform
:vop
:ir1-convert))
(with-test (:name :find-definition-sources-by-name-error-handling)
(dolist (definition-type *definition-types*)
(assert (null (sb-introspect:find-definition-sources-by-name
7 definition-type)))
(assert (null (sb-introspect:find-definition-sources-by-name
"xxx" definition-type)))
(assert (null (sb-introspect:find-definition-sources-by-name
'(setf (setf xxx)) definition-type))))
(assert (null (sb-introspect:find-definition-sources-by-name 'print :junk))))
(with-test (:name (:find-definition-sources-by-name :package))
(assert (sb-introspect:find-definition-sources-by-name "CL" :package))
(assert (sb-introspect:find-definition-sources-by-name :cl :package))
(assert (null (sb-introspect:find-definition-sources-by-name #\a :package))))

View file

@ -85,6 +85,11 @@
(sb-alien:define-alien-variable ("errno" test-alien-var) sb-alien:int)
(sb-alien:define-alien-callable alien-comparator sb-alien:int
((p1 (* t)) (p2 (* t)))
(- (sb-alien:deref (sb-alien:cast p1 (* sb-alien:int)))
(sb-alien:deref (sb-alien:cast p2 (* sb-alien:int)))))
(define-condition test-condition (error)
((a :reader condition-slot-reader
:writer condition-slot-writer)))
@ -95,3 +100,11 @@
(x)))
(defun 0-debug (a b c) (declare (optimize (debug 0))) (+ a b c))
(defvar *x* 1)
(eval-when (:compile-toplevel)
(declaim (optimize (debug 0))))
(deftype 0-debug-type ()
`(member ,*x*))

1
contrib/sb-manual/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
output/

View file

@ -0,0 +1,2 @@
SYSTEM=sb-manual
include ../asdf-module.mk

264
contrib/sb-manual/README.md Normal file
View file

@ -0,0 +1,264 @@
Docstring Style Guide
---------------------
The Markdown-to-Texinfo converter is documented in `markdown.lisp`.
Here, we provide a quick howto and style guide. If something is
unclear (there should be lots), then you can test things with e.g.
(sb-manual::markdown-to-texinfo "PRINT")
## Writing Names Inline
- Upcase symbols naming definitions (or arguments of the function
being documented):
SB-EXT:EXIT
PRINT
X
Unqualified symbols must be accessible in the package where the
docstring is parsed. A good practice is to rely on Slime's TAB
completion on the name; then it's clear that the symbol exists.
- Upcase and mark strings naming definitions as code:
`SB-EXT`
This is necessary because we don't want the creation of package
`ANSI` to automatically codify all occurrences of `ANSI` in the
documentation.
- Upcase and mark non-existent symbols as code:
`WIN64::WHATEVER`
For when the code that defines the package or the symbol cannot be
loaded.
- Mark C symbols as code:
`send`
`send(2)`
The latter is preferable to `send`(2), as it can be parsed by
`manual-entry` in Emacs.
If there is a Lisp symbol `SEND` accessible in the current package
and it names a definition, then you need to prevent it from being
autolinked (only with PAX, currently):
`\send(2)`
> _Note_: Here and in general, the backslashes need to be doubled
> when writing docstrings.
- Mark C constants as code and escape downcasing:
`\\AF_LOCAL`
All capital code is downcased, which is great in the common case
but not here.
## Writing Sexps Inline
- One option is to mark the whole expression as code:
`(PRINT 'HELLO)`
Here, everything is rendered in monospace, downcased, no autolinks.
- Alternatively, one could simply write
(PRINT '`HELLO`)
and rely on automatic codification for `PRINT`, codify `HELLO`
manually, and accept the fact that the parens will be in the
proportional font. In return, `PRINT` is autolinked.
- Even more alternatively:
`(`PRINT` 'HELLO)`
Here, everything is monospace (except maybe the space), and
`PRINT` is autolinked.
## Writing Signatures Inline
Follow the somewhat usual `<TERMINAL-NAME>` convention:
One option is `(:USE <PACKAGE-NAME>*)`, where `<PACKAGE-NAME>`
is a package designator.
If you wrote the mixed-case `(:USE <package-name>*)`, then the
expression would be downcased, which is bad here.
## Code Blocks
In code blocks, always write as you would write in a source file,
which means downcase the symbols. Prefer indented code blocks
```
this is indented
```
to fenced code blocks:
```
this is fenced
```
Use fenced code blocks only if there multiple successive code blocks
that you definitely want to render as distinct "boxes".
One gotcha to look out for is indenting code blocks is in list items:
```
- this is a list
A separate child paragraph indented to be "within" the list item.
(some code)
```
Note how the code block is indented 8 spaces from the `-` character.
The required indentation remains the same if the child paragraph above
is not present.
## Links
### Plain Links
For short links:
<http://x.y>
### Explicit Links
For overly long links:
[label](http://x.y/a?b=c)
When generating Texinfo, this is translated to `@url`, which is
rendered like a HTML link in HTML and PDF, but with `label (see
<uri>)` in Info.
PAX will generate a normal link except in plain text, where it simply
drops the URI.
### Reflinks
In PAX-generated output only, `FUNCTION` is autolinked to its
definitions. If there is more than one, you can dismambiguate:
[FUNCTION][type]
PAX will produce a single link in this case. If `(FUNCTION CLASS)` is
documented in some section, then the link will point to that
documentation. Else, the link will go to the CLHS. The latter can be
forced:
[FUNCTION][(clhs type)]
Since we don't link to definitions in Texinfo (except to sections),
the above examples are translated to `FUNCTION` there.
## Notes
- In many cases, just write a sentence:
Note that this may not be always so.
- To add a note, use blockquotes:
> _Note_: This is not terribly important,
> but it can span multiple lines.
Blockquotes render indented in most formats, sometimes with a
vertical line to their left (e.g. Markdown on GitHub).
- To add a warning, use blockquotes:
> __Warning__: Beware of the dog!
Blockquotes without `_Note_` and `__Warning__` are fine for their
other purposes: citing stuff, add copyright notices, etc. Markdown is
not semantic. Use it freely and visually.
Footnotes are not supported.
## Typographic Miscellanea
The Markdown-to-Texinfo converter does not convert e.g. `--` to
en-dash. This is to prevent messing up the output when something like
`git <option>* -- <path>` is written without proper markup. The issue
is similar but maybe more pronounced with literal strings and curly
quotes: you don't want to copy the rendered version of
(print "Hello, world")
to the REPL, only to find the double quotes have been replaced by some
fancy characters.
## Inline Quotes and Emphasis
Use strong emphasis (e.g. `__not__`) very sparingly. It usually gets
rendered bold, which draws too much attention. However, emphasis
(usually italic) is fine.
You may use emphasis instead of single or double quotes:
CLHS `14.1` says that _depending on context, a group of
connected conses can be viewed in a variety of different
ways_, but that's trivial.
You may also use double quotes, but the straight double quotes are
kind of ugly in proportional fonts.
## Sections
### Titles
Use title case:
Big and Bigger Words
### Names
Name the section `@BIG-AND-BIGGER-WORDS` or something shorter like
`@BIG-WORDS`. In a docstring, you may read `"@BIG-WORDS are
necessary"`, and `"Big and Bigger Words are necessary"` when it's
rendered, so make sure that they are similar enough.
Note that section names live in a flat namespace: they are all
exported from SB-MANUAL, and they also show up the Texinf indices
without the context of their parents. So, their names should be
globally meaningful. Thus, it is better to name the section describing
`SB-ACLREPL`'s usage `@SB-ACLREPL-USAGE` than `@USAGE`.
## Docstring Formatting
The Emacs style:
(defun foo (x)
"Return X.
It signals no errors."
x)
You may also indent all but the first line as long as you do it
consistently within the docstring. Maybe one day we could even agree
upon a universally accepted style ... just joking.
## Locale Stuff
Currently the manual is a mix of American and British English.
In the vast majority of the cases, the existing docstrings use `e.g.
X` and `i.e. X` (the British version). For consistency, do not use
other forms such as `eg. X` or `i.e., X`.
## Paragraph Formatting
Note that docstrings are also inconsistent about whether one or two
spaces follow a full stop (controlled by `sentence-end-double-space`
in Emacs) and their `fill-column`. It would be nice to have them all
`fill-paragraph`ed with the same settings ...

26
contrib/sb-manual/TODO.md Normal file
View file

@ -0,0 +1,26 @@
- How/when to load/include docs of contribs?
Currently, `sb-manual` loads *all* contribs to be able to query
the definition docstrings. Each contrib directory has a
`manual.lisp` file, which is part of the `sb-manual` contrib.
On the positive side, this does not load extra stuff until the
user `require`s `sb-manual`. However, then it loads all contribs.
It shouldn't be difficult to show documtation only for actually
loaded contribs.
- How to deal with repetitive package names?
For example, `sb-alien` is `:use`d by `sb-manual` so that the
section docstrings need not fully qualify with `sb-alien:` a
thousand times. In the generated Texinfo, this can be a tad
confusing. In output formats with links (e.g. HTML from PAX), this
is clearly preferable.
Nicknames, maybe?
- Improve section names
They are a soft interface: exported from `sb-manual` and visible
to the user via HTML anchors.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,903 @@
(in-package :sb-manual)
(defsection @compiler (:title "Compiler")
"This chapter will discuss most compiler issues other than efficiency,
including compiler error messages, the SBCL compiler's unusual
approach to type safety in the presence of type declarations, the
effects of various compiler optimization policies, and the way that
inlining and open coding may cause optimized code to differ from a
naive translation. Efficiency issues are sufficiently varied and
separate that they have their own chapter, @EFFICIENCY."
(@diagnostic-messages section)
(@handling-of-types section)
(@compiler-policy section)
(@compiler-errors section)
(@open-coding-and-inline-expansion section)
(@interpreter section)
(@advanced-compiler-use-and-efficiency-hints section))
(defsection @diagnostic-messages (:title "Diagnostic Messages"
:concepts (("compiler" "messsage")
("messsage," "compiler")))
(@controlling-verbosity section)
(@diagnostic-severity section)
(@understanding-compiler-diagnostics section))
(defsection @controlling-verbosity
(:title "Controlling Verbosity"
:concepts (("compiler" "messsage" "verbosity")
("verbosity" "of compiler messsages")))
"The compiler can be quite verbose in its diagnostic reporting, rather
more then some users would prefer -- the amount of noise emitted can
be controlled, however.
To control emission of compiler diagnostics (of any severity other
than ERROR: @DIAGNOSTIC-SEVERITY) use the SB-EXT:MUFFLE-CONDITIONS
and SB-EXT:UNMUFFLE-CONDITIONS declarations, specifying the type of
condition that is to be muffled (the muffling is done using an
associated MUFFLE-WARNING restart).
Global control:
;;; Muffle compiler-notes globally
(declaim (sb-ext:muffle-conditions sb-ext:compiler-note))
Local control:
;;; Muffle compiler-notes based on lexical scope
(defun foo (x)
(declare (optimize speed) (fixnum x)
(sb-ext:muffle-conditions sb-ext:compiler-note))
(values (* x 5) ; no compiler note from this
(locally
(declare (sb-ext:unmuffle-conditions sb-ext:compiler-note))
;; this one gives a compiler note
(* x -5))))"
(sb-ext:muffle-conditions declaration)
(sb-ext:unmuffle-conditions declaration)
"Various details of _how_ the compiler messages are printed can be
controlled via the alist SB-EXT:*COMPILER-PRINT-VARIABLE-ALIST*."
(sb-ext:*compiler-print-variable-alist* variable)
"For information about muffling warnings signaled outside of the
compiler, see @CUSTOMIZATION-HOOKS-FOR-USERS.")
;; FIXME: How much control over error messages is in SBCL? How much
;; should be? How much of this documentation should we save or adapt?
;;
;; %%\node Error Message Parameterization, , Read Errors, Interpreting Error Messages
;; \subsection{Error Message Parameterization}
;; \cpsubindex{error messages}{verbosity}
;; \cpsubindex{verbosity}{of error messages}
;;
;; There is some control over the verbosity of error messages. See also
;; \varref{undefined-warning-limit}, \code{*efficiency-note-limit*} and
;; \varref{efficiency-note-cost-threshold}.
;;
;; \begin{defvar}{}{enclosing-source-cutoff}
;;
;; This variable specifies the number of enclosing actual source forms
;; that are printed in full, rather than in the abbreviated processing
;; path format. Increasing the value from its default of \code{1}
;; allows you to see more of the guts of the macroexpanded source,
;; which is useful when debugging macros.
;; \end{defvar}
;;
;; \begin{defmac}{extensions:}{define-source-context}{%
;; \args{\var{name} \var{lambda-list} \mstar{form}}}
;;
;; This macro defines how to extract an abbreviated source context from
;; the \var{name}d form when it appears in the compiler input.
;; \var{lambda-list} is a \code{defmacro} style lambda-list used to
;; parse the arguments. The \var{body} should return a list of
;; subforms that can be printed on about one line. There are
;; predefined methods for \code{defstruct}, \code{defmethod}, etc. If
;; no method is defined, then the first two subforms are returned.
;; Note that this facility implicitly determines the string name
;; associated with anonymous functions.
;; \end{defmac}
(defsection @diagnostic-severity
(:title "Diagnostic Severity"
:concepts (("compiler" "message" "severity")
("severity" "of compiler message")))
"There are four levels of compiler diagnostic severity:
- error
- warning
- style warning
- note
The first three levels correspond to condition classes which are
defined in the ANSI standard for Common Lisp and which have special
significance to the COMPILE and COMPILE-FILE functions. These levels
of compiler error severity occur when the compiler handles
conditions of these classes.
The fourth level of compiler error severity, _note_, corresponds to
the SB-EXT:COMPILER-NOTE, and is used for problems which are too
mild for the standard condition classes, typically hints about how
efficiency might be improved. The SB-EXT:CODE-DELETION-NOTE, a
subtype of SB-EXT:COMPILER-NOTE, is signalled when the compiler
deletes user-supplied code after proving that the code in question
is unreachable.
Future work for SBCL includes expanding this hierarchy of types to
allow more fine-grained control over emission of diagnostic
messages."
(sb-ext:compiler-note condition)
(sb-ext:code-deletion-note condition))
(defsection @understanding-compiler-diagnostics
(:title "Understanding Compiler Diagnostics")
"The messages emitted by the compiler contain a lot of detail in a
terse format, so they may be confusing at first. The messages will be
illustrated using this example program:
(defmacro zoq (x)
`(roq (ploq (+ ,x 3))))
(defun foo (y)
(declare (symbol y))
(zoq y))
The main problem with this program is that it is trying to add `3`
to a symbol. Note also that the functions `ROQ` and `PLOQ` aren't
defined anywhere."
(@parts-of-a-compiler-diagnostic section)
(@original-and-actual-source section)
(@processing-paths section))
(defsection @parts-of-a-compiler-diagnostic
(:title "Parts of a Compiler Diagnostic")
"When processing this program, the compiler will produce this warning:
; file: /tmp/foo.lisp
; in: DEFUN FOO
; (ZOQ Y)
; --> ROQ PLOQ
; ==>
; (+ Y 3)
;
; caught WARNING:
; Asserted type NUMBER conflicts with derived type (VALUES SYMBOL &OPTIONAL).
In this example we see each of the six possible parts of a compiler
diagnostic:
- `file: /tmp/foo.lisp` is the name of the file that the compiler
read the relevant code from. The file name is displayed because it
may not be immediately obvious when there is an error during
compilation of a large system, especially when
WITH-COMPILATION-UNIT is used to delay undefined warnings.
- `in: DEFUN FOO` is the definition top level form responsible for
the diagnostic. It is obtained by taking the first two elements of
the enclosing form whose first element is a symbol beginning with
`DEF`. If there is no such enclosing `DEF` form, then the
outermost form is used. If there are multiple `DEF` forms, then
they are all printed from the outside in, separated by `=>`s. In
this example, the problem was in the DEFUN for `FOO`.
- `(ZOQ Y)` is the _@ORIGINAL-SOURCE_ form responsible for the
diagnostic. Original source means that the form directly appeared
in the original input to the compiler, i.e. in the lambda passed
to COMPILE or in the top level form read from the source file. In
this example, the expansion of the `ZOQ` macro was responsible for
the message.
- `--> ROQ PLOQ` This is the _@PROCESSING-PATH_ that the compiler
used to produce the code that caused the message to be emitted.
The processing path is a representation of the evaluated forms
enclosing the @ACTUAL-SOURCE that the compiler encountered when
processing the original source. The path is the first element of
each form, or the form itself if the form is not a list. These
forms result from the expansion of macros or source-to-source
transformation done by the compiler. In this example, the
enclosing evaluated forms are the calls to `ROQ` and `PLOQ`. These
calls resulted from the expansion of the `ZOQ` macro.
- `==> (+ Y 3)` is the _actual source_ responsible for the
diagnostic. If the actual source appears in the explanation, then
we print the next enclosing evaluated form, instead of printing
the actual source twice. (This is the form that would otherwise
have been the last form of the processing path.) In this example,
the problem is with the evaluation of the reference to the
variable `Y`.
- `caught WARNING: Asserted type NUMBER conflicts with derived type
(VALUES SYMBOL &OPTIONAL).` is the _explanation_ of the problem.
In this example, the problem is that, while the call to `+`
requires that its arguments are all of type NUMBER, the compiler
has derived that Y will evaluate to a SYMBOL. Note that
`(VALUES SYMBOL &OPTIONAL)` expresses that `Y` evaluates to
precisely one value.
Note that each part of the message is distinctively marked:
- `file:` and `in:` mark the file and definition, respectively.
- The original source is an indented form with no prefix.
- Each line of the processing path is prefixed with `-->`.
- The actual source form is indented like the original source, but
is marked by a preceding `==>` line. (FIXME: no it isn't.)
- The explanation is prefixed with the diagnostic severity, which
can be `caught ERROR:`, `caught WARNING:`, `caught
STYLE-WARNING:`, or `note:`.
Each part of the message is more specific than the preceding one. If
consecutive messages are for nearby locations, then the front part
of the messages would be the same. In this case, the compiler omits
as much of the second message as in common with the first. For
example:
; file: /tmp/foo.lisp
; in: DEFUN FOO
; (ZOQ Y)
; --> ROQ
; ==>
; (PLOQ (+ Y 3))
;
; caught STYLE-WARNING:
; undefined function: PLOQ
; ==>
; (ROQ (PLOQ (+ Y 3)))
;
; caught STYLE-WARNING:
; undefined function: ROQ
In this example, the file, definition and original source are
identical for the two messages, so the compiler omits them in the
second message. If consecutive messages are entirely identical, then
the compiler prints only the first message, followed by: `[Last
message occurs <repeats> times]` where `<repeats>` is the number of
times the message was given.
If the source was not from a file, then no file line is printed. If
the actual source is the same as the original source, then the
processing path and actual source will be omitted. If no forms
intervene between the original source and the actual source, then
the processing path will also be omitted.")
(defsection @original-and-actual-source (:title "Original and Actual Source"
:concepts (@original-source
@actual-source))
"The _original source_ displayed will almost always be a list. If
the actual source for an message is a symbol, the original source will
be the immediately enclosing evaluated list form. So even if the
offending symbol does appear in the original source, the compiler will
print the enclosing list and then print the symbol as the actual
source (as though the symbol were introduced by a macro.)
When the _actual source_ is displayed (and is not a symbol), it will
always be code that resulted from the expansion of a macro or a
source-to-source compiler optimization. This is code that did not
appear in the original source program; it was introduced by the
compiler.
Keep in mind that when the compiler displays a source form in an
diagnostic message, it always displays the most specific (innermost)
responsible form. For example, compiling this function
(defun bar (x)
(let (a)
(declare (fixnum a))
(setq a (foo x))
a))
gives this error message
; file: /tmp/foo.lisp
; in: DEFUN BAR
; (LET (A)
; (DECLARE (FIXNUM A))
; (SETQ A (FOO X))
; A)
;
; caught WARNING:
; Asserted type FIXNUM conflicts with derived type (VALUES NULL &OPTIONAL).
This message is not saying that there is a problem somewhere in this
LET -- it is saying that there is a problem with the LET itself. In
this example, the problem is that `A`'s NIL initial value is not a
FIXNUM.")
(defsection @processing-paths (:title "Processing Paths"
:concepts (@processing-path))
"The processing path is mainly useful for debugging macros, so if you
don't write macros, you can probably ignore it. Consider this example:
(defun foo (n)
(dotimes (i n *undefined*)))
Compiling results in this error message:
; in: DEFUN FOO
; (DOTIMES (I N *UNDEFINED*))
; --> DO BLOCK LET TAGBODY RETURN-FROM
; ==>
; (PROGN *UNDEFINED*)
;
; caught WARNING:
; undefined variable: *UNDEFINED*
Note that DO appears in the processing path. This is because
DOTIMES expands into:
(do ((i 0 (1+ i)) (#:g1 n))
((>= i #:g1) *undefined*)
(declare (type unsigned-byte i)))
The rest of the processing path results from the @MACROEXPANSION of
DO: ~SOURCE-TRANSFORM
(block nil
(let ((i 0) (#:g1 n))
(declare (type unsigned-byte i))
(tagbody (go #:g3)
#:g2 (psetq i (1+ i))
#:g3 (unless (>= i #:g1) (go #:g2))
(return-from nil (progn *undefined*)))))
In this example, the compiler descended into the BLOCK, LET, TAGBODY
and RETURN-FROM to reach the PROGN printed as the actual source.
This is a place where the \"actual source appears in explanation\"
rule was applied. The innermost actual source form was the symbol
_undefined_ itself, but that also appeared in the explanation, so
the compiler backed out one level.")
(defsection @handling-of-types (:title "Handling of Types")
"One of the most important features of the SBCL compiler (similar to
the original CMUCL compiler, also known as _Python_) is its fairly
sophisticated understanding of the Common Lisp type system and its
conservative approach to the implementation of type declarations.
These two features reward the use of type declarations throughout
development, even when high performance is not a concern. Also, as
discussed in the chapter on performance (see @EFFICIENCY), the use
of appropriate type declarations can be very important for
performance as well.
The SBCL compiler also has a greater knowledge of the Common Lisp
type system than other compilers. Support is incomplete only for
types involving the SATISFIES type specifier."
(@declarations-as-assertions section)
(@precise-type-checking section)
(@getting-existing-programs-to-run section)
(@implementation-limitations section))
;; FIXME: See also sections \ref{advanced-type-stuff} and
;; \ref{type-inference}, once we snarf them from the CMU CL manual.
;;
;; Also see my paper on improving Baker, when I get round to it.
;;
;; Whose paper?
(defsection @declarations-as-assertions (:title "Declarations as Assertions")
"The SBCL compiler treats type declarations differently from most other
Lisp compilers. Under default compilation policy the compiler doesn't
blindly believe type declarations, but considers them assertions about
the program that should be checked: all type declarations that have
not been proven to always hold are asserted at runtime.
_Remaining bugs in the compiler's handling of types unfortunately
provide some exceptions to this rule, see
@IMPLEMENTATION-LIMITATIONS._
CLOS slot types form a notable exception. Types declared using the
:TYPE slot option in DEFCLASS are asserted if and only if the class
was defined in _safe code_ ~SAFETY and the slot access location is
in _safe code_ as well. This laxness does not pose any internal
consistency issues, as the CLOS slot types are not available for the
type inferencer, nor do CLOS slot types provide any efficiency
benefits.
There are three type checking policies available in SBCL, selectable
via OPTIMIZE declarations."
;; FIXME: This should be properly integrated with general policy
;; stuff, once that gets cleaned up.
"- __Full Type Checks__
All declarations are considered assertions to be checked at
runtime, and all type checks are precise. The default
compilation policy provides full type checks.
Used when `(OR (>= SAFETY 2) (>= SAFETY SPEED 1))`.
- __Weak Type Checks__
Declared types may be simplified into faster to check
supertypes: for example, `(OR (INTEGER -17 -7) (INTEGER 7 17))`
is simplified into `(INTEGER -17 17)`.
> __Warning__: It is relatively easy to corrupt the heap when
> weak type checks are used if the program contains type-errors.
Used when `(AND (< SAFETY 2) (< SAFETY SPEED))`.
- __No Type Checks__
All declarations are believed without assertions. Also disables
argument count and array bounds checking.
> __Warning__: Any type errors in code where type checks are not
> performed are liable to corrupt the heap.
Used when `(= SAFETY 0)`.")
(defsection @precise-type-checking (:title "Precise Type Checking"
:concepts (("type checking," "precise")
("precise" "type checking")))
"Precise checking means that the check is done as though TYPEP
had been called with the exact type specifier that appeared in the
declaration.
If a variable is declared to be `(INTEGER 3 17)`, then its value
must always be an integer between `3` and `17`. If multiple type
declarations apply to a single variable, then all the declarations
must be correct; it is as though all the types were intersected
producing a single AND type specifier.
To gain maximum benefit from the compiler's type checking, you
should always declare the types of function arguments and structure
slots as precisely as possible. This often involves the use of OR,
MEMBER, and other list-style type specifiers.")
(defsection @getting-existing-programs-to-run
(:title "Getting Existing Programs to Run"
:concepts (("existing programs," "getting them to run")
("types," "portability")
("compatibility" "with other Lisps")))
"Since SBCL's compiler does much more comprehensive type checking than
most Lisp compilers, SBCL may detect type errors in programs that have
been debugged using other compilers. These errors are mostly incorrect
declarations, although compile-time type errors can find actual bugs
if parts of the program have never been tested.
Some incorrect declarations can only be detected by run-time type
checking. It is very important to initially compile a program with
full type checks (high @SAFETY optimization) and then test this safe
version. After the checking version has been tested, then you can
consider weakening or eliminating type checks. _This applies even to
previously debugged programs_ because the SBCL compiler does much
more type inference than other Common Lisp compilers, so an
incorrect declaration can do more damage.
The most common problem is with variables whose constant initial
value doesn't match the type declaration. Incorrect constant initial
values will always be flagged by a compile-time type error, and they
are simple to fix once located. Consider this code fragment:
(prog (foo)
(declare (fixnum foo))
(setq foo ...)
...)
Here `FOO` is given an initial value of NIL but is declared to be a
FIXNUM. Even if it is never read, the initial value of a variable
must match the declared type. There are two ways to fix this
problem. Change the declaration
(prog (foo)
(declare (type (or fixnum null) foo))
(setq foo ...)
...)
or change the initial value
(prog ((foo 0))
(declare (fixnum foo))
(setq foo ...)
...)
It is generally preferable to change to a legal initial value rather
than to weaken the declaration, but sometimes it is simpler to
weaken the declaration than to try to make an initial value of the
appropriate type.
Another declaration problem occasionally encountered is incorrect
declarations on DEFMACRO arguments. This can happen when a function
is converted into a macro. Consider this macro:
(defmacro my-1+ (x)
(declare (fixnum x))
`(the fixnum (1+ ,x)))
Although legal and well-defined Common Lisp code, this meaning of
this definition is almost certainly not what the writer intended.
For example, this call is illegal:
(my-1+ (+ 4 5))
This call is illegal because the argument to the macro is `(+ 4 5)`,
which is a LIST, not a FIXNUM. Because of macro semantics, it is
hardly ever useful to declare the types of macro arguments. If you
really want to assert something about the type of the result of
evaluating a macro argument, then put a THE in the expansion:
(defmacro my-1+ (x)
`(the fixnum (1+ (the fixnum ,x))))
In this case, it would be stylistically preferable to change this
macro back to a function and declare it inline."
;; FIXME: <xref>inline-expansion, once we crib the relevant text
;; from the CMU CL manual.
"Some more subtle problems are caused by incorrect declarations that
can't be detected at compile time. Consider this code:
(do ((pos 0 (position #\a string :start (1+ pos))))
((null pos))
(declare (fixnum pos))
...)
Although `POS` is almost always a FIXNUM, it is NIL at the end of
the loop. If this example is compiled with full type checks (the
default), then running it will signal a type error at the end of the
loop. If compiled without type checks, the program will go into an
infinite loop (or perhaps POSITION will complain because `(1+ NIL)`
isn't a sensible start.) Why? Because if you compile without type
checks, the compiler just quietly believes the type declaration.
Since the compiler believes that `POS` is always a FIXNUM, it
believes that `POS` is never NIL, so `(NULL POS)` is never true, and
the loop exit test is optimized away. Such errors are sometimes
flagged by unreachable code notes, but it is still important to
initially compile and test any system with full type checks, even if
the system works fine when compiled using other compilers.
In this case, the fix is to weaken the type declaration to `(OR
FIXNUM NULL)`. (Actually, this declaration is unnecessary in SBCL,
since it already knows that POSITION returns a non-negative FIXNUM
or NIL.)
Note that there is usually little performance penalty for weakening
a declaration in this way. Any numeric operations in the body can
still assume that the variable is a FIXNUM, since NIL is not a legal
numeric argument. Another possible fix would be to say:
(do ((pos 0 (position #\a string :start (1+ pos))))
((null pos))
(let ((pos pos))
(declare (fixnum pos))
...))
This would be preferable in some circumstances, since it would allow
a non-standard representation to be used for the local `POS`
variable in the loop body."
;; FIXME: <xref>ND-variables, once we crib the text from the CMU CL
;; manual.
)
(defsection @implementation-limitations (:title "Implementation Limitations")
"If an FTYPE is placed after the function definition the function won't
perform any type checks, and the calls to the function will blindly
trust the declared types.
(OPTIMIZE (DEBUG 3)) will not trust any FTYPE declarations.")
(defsection @compiler-policy (:title "Compiler Policy")
"Compiler policy is controlled by the OPTIMIZE declaration,
supporting all ANSI optimization qualities (DEBUG, safety, space,
and speed). (A deprecated extension SB-EXT:INHIBIT-WARNINGS is still
supported but liable to go away at any time.)
For effects of various optimization qualities on type-safety and
debuggability see @DECLARATIONS-AS-ASSERTIONS and
@DEBUGGER-POLICY-CONTROL.
Ordinarily, when the speed quality is high, the compiler emits notes
to notify the programmer about its inability to apply various
optimizations. For selective muffling of these notes, see
@CONTROLLING-VERBOSITY.
The value of space mostly influences the compiler's decision whether
to inline operations, which tend to increase the size of programs.
Use the value `0` with caution, since it can cause the compiler to
inline operations so indiscriminately that the net effect is to slow
the program by causing cache misses or even swapping."
(sb-ext:describe-compiler-policy function)
(sb-ext:restrict-compiler-policy function)
(with-compilation-unit macro))
;; FIXME: old CMU CL compiler policy, should perhaps be adapted for
;; SBCL. (Unfortunately, the CMU CL docs are out of sync with the CMU
;; CL code, so adapting this requires not only reformatting the
;; documentation, but rooting out code rot.)
;;
;; <sect2 id=\")compiler-policy\"><title>Compiler Policy</1000
;; INDEX {policy}{compiler}
;; INDEX compiler policy
;;
;; <para>The policy is what tells the compiler <emphasis>how</emphasis> to
;; compile a program. This is logically (and often textually) distinct
;; from the program itself. Broad control of policy is provided by the
;; <parameter>optimize</parameter> declaration; other declarations and variables
;; control more specific aspects of compilation.
;;
;; \begin{comment}
;; * The Optimize Declaration::
;; * The Optimize-Interface Declaration::
;; \end{comment}
;;
;; %%\node The Optimize Declaration, The Optimize-Interface Declaration, Compiler Policy, Compiler Policy
;; \subsection{The Optimize Declaration}
;; \label{optimize-declaration}
;; \cindex{optimize declaration}
;; \cpsubindex{declarations}{\code{optimize}}
;;
;; The \code{optimize} declaration recognizes six different
;; \var{qualities}. The qualities are conceptually independent aspects
;; of program performance. In reality, increasing one quality tends to
;; have adverse effects on other qualities. The compiler compares the
;; relative values of qualities when it needs to make a trade-off; i.e.,
;; if \code{speed} is greater than \code{safety}, then improve speed at
;; the cost of safety.
;;
;; The default for all qualities (except \code{debug}) is \code{1}.
;; Whenever qualities are equal, ties are broken according to a broad
;; idea of what a good default environment is supposed to be. Generally
;; this downplays \code{speed}, \code{compile-speed} and \code{space} in
;; favor of \code{safety} and \code{debug}. Novice and casual users
;; should stick to the default policy. Advanced users often want to
;; improve speed and memory usage at the cost of safety and
;; debuggability.
;;
;; If the value for a quality is \code{0} or \code{3}, then it may have a
;; special interpretation. A value of \code{0} means ``totally
;; unimportant'', and a \code{3} means ``ultimately important.'' These
;; extreme optimization values enable ``heroic'' compilation strategies
;; that are not always desirable and sometimes self-defeating.
;; Specifying more than one quality as \code{3} is not desirable, since
;; it doesn't tell the compiler which quality is most important.
;;
;;
;; These are the optimization qualities:
;; \begin{Lentry}
;;
;; \item[\code{speed}] \cindex{speed optimization quality}How fast the
;; program should is run. \code{speed 3} enables some optimizations
;; that hurt debuggability.
;;
;; \item[\code{compilation-speed}] \cindex{compilation-speed optimization
;; quality}How fast the compiler should run. Note that increasing
;; this above \code{safety} weakens type checking.
;;
;; \item[\code{space}] \cindex{space optimization quality}How much space
;; the compiled code should take up. Inline expansion is mostly
;; inhibited when \code{space} is greater than \code{speed}. A value
;; of \code{0} enables indiscriminate inline expansion. Wide use of a
;; \code{0} value is not recommended, as it may waste so much space
;; that run time is slowed. \xlref{inline-expansion} for a discussion
;; of inline expansion.
;;
;; \item[\code{debug}] \cindex{debug optimization quality}How debuggable
;; the program should be. The quality is treated differently from the
;; other qualities: each value indicates a particular level of debugger
;; information; it is not compared with the other qualities.
;; \xlref{debugger-policy} for more details.
;;
;; \item[\code{safety}] \cindex{safety optimization quality}How much
;; error checking should be done. If \code{speed}, \code{space} or
;; \code{compilation-speed} is more important than \code{safety}, then
;; type checking is weakened (\pxlref{weakened-type-checks}). If
;; \code{safety} if \code{0}, then no run time error checking is done.
;; In addition to suppressing type checks, \code{0} also suppresses
;; argument count checking, unbound-symbol checking and array bounds
;; checks.
;; ... and checking of tag existence in RETURN-FROM and GO.
;;
;; \item[\code{extensions:inhibit-warnings}] \cindex{inhibit-warnings
;; optimization quality}This is a CMU extension that determines how
;; little (or how much) diagnostic output should be printed during
;; compilation. This quality is compared to other qualities to
;; determine whether to print style notes and warnings concerning those
;; qualities. If \code{speed} is greater than \code{inhibit-warnings},
;; then notes about how to improve speed will be printed, etc. The
;; default value is \code{1}, so raising the value for any standard
;; quality above its default enables notes for that quality. If
;; \code{inhibit-warnings} is \code{3}, then all notes and most
;; non-serious warnings are inhibited. This is useful with
;; \code{declare} to suppress warnings about unavoidable problems.
;; \end{Lentry}
;;
;; %%\node The Optimize-Interface Declaration, , The Optimize Declaration, Compiler Policy
;; \subsection{The Optimize-Interface Declaration}
;; \label{optimize-interface-declaration}
;; \cindex{optimize-interface declaration}
;; \cpsubindex{declarations}{\code{optimize-interface}}
;;
;; The \code{extensions:optimize-interface} declaration is identical in
;; syntax to the \code{optimize} declaration, but it specifies the policy
;; used during compilation of code the compiler automatically generates
;; to check the number and type of arguments supplied to a function. It
;; is useful to specify this policy separately, since even thoroughly
;; debugged functions are vulnerable to being passed the wrong arguments.
;; The \code{optimize-interface} declaration can specify that arguments
;; should be checked even when the general \code{optimize} policy is
;; unsafe.
;;
;; Note that this argument checking is the checking of user-supplied
;; arguments to any functions defined within the scope of the
;; declaration, \code{not} the checking of arguments to \llisp{}
;; primitives that appear in those definitions.
;;
;; The idea behind this declaration is that it allows the definition of
;; functions that appear fully safe to other callers, but that do no
;; internal error checking. Of course, it is possible that arguments may
;; be invalid in ways other than having incorrect type. Functions
;; compiled unsafely must still protect themselves against things like
;; user-supplied array indices that are out of bounds and improper lists.
;; See also the \kwd{context-declarations} option to
;; \macref{with-compilation-unit}.
;;
;; (end of section on compiler policy)
(defsection @compiler-errors (:title "Compiler Errors")
(@type-errors-at-compile-time section)
(@errors-during-macroexpansion section)
(@read-errors section))
(defsection @type-errors-at-compile-time
(:title "Type Errors at Compile Time"
:concepts (("compile-time" "type error")
("type error," "compile-time")))
"If the compiler can prove at compile time that some portion of the
program cannot be executed without a type error, then it will give a
warning at compile time.
It is possible that the offending code would never actually be
executed at run-time due to some higher level consistency constraint
unknown to the compiler, so a type warning doesn't always indicate an
incorrect program.
For example, consider this code fragment:
(defun raz (foo)
(let ((x (case foo
(:this 13)
(:that 9)
(:the-other 42))))
(declare (fixnum x))
(foo x)))
Compilation produces this warning:
; in: DEFUN RAZ
; (CASE FOO (:THIS 13) (:THAT 9) (:THE-OTHER 42))
; --> LET COND IF COND IF COND IF
; ==>
; (COND)
;
; caught WARNING:
; This is not a FIXNUM:
; NIL
In this case, the warning means that if `FOO` isn't any of `:THIS`,
`:THAT` or `:THE-OTHER`, then `x` will be initialized to NIL, which
the FIXNUM declaration makes illegal. The warning will go away if
ECASE is used instead of CASE, or if `:THE-OTHER` is changed to T.
This sort of spurious type warning happens moderately often in the
expansion of complex macros and in inline functions. In such cases,
there may be dead code that is impossible to correctly execute. The
compiler can't always prove this code is dead (could never be
executed), so it compiles the erroneous code (which will always signal
an error if it is executed) and gives a warning.")
(defsection @errors-during-macroexpansion
(:title "Errors During Macroexpansion"
:concepts (("macroexpansion," "errors during")))
"The compiler handles errors that happen during macroexpansion, turning
them into compiler errors. If you want to debug the error (to debug
a macro), you can set *BREAK-ON-SIGNALS* to ERROR. For example, this
definition:
(defun foo (e l)
(do ((current l (cdr current))
((atom current) nil))
(when (eq (car current) e) (return current))))
gives this error:
; in: DEFUN FOO
; (DO ((CURRENT L (CDR CURRENT))
; ((ATOM CURRENT) NIL))
; (WHEN (EQ (CAR CURRENT) E) (RETURN CURRENT)))
;
; caught ERROR:
; (in macroexpansion of (DO # #))
; (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
; DO step variable is not a symbol: (ATOM CURRENT)")
(defsection @read-errors (:title "Read Errors"
:concepts (("compiler" "read error")
("read error," "compiler")))
"SBCL's compiler does not attempt to recover from read errors when
reading a source file, but instead just reports the offending
character position and gives up on the entire source file.")
(defsection @open-coding-and-inline-expansion
(:title "Open Coding and Inline Expansion"
:concepts ("open-coding"
("inline" "expansion")
("static" "functions")))
"Since Common Lisp forbids the redefinition of standard functions, the
compiler can have special knowledge of these standard functions
embedded in it. This special knowledge is used in various ways (open
coding, inline expansion, source transformation), but the implications
to the user are basically the same:
- Attempts to redefine standard functions may be frustrated, since
the function may never be called. Although it is technically
illegal to redefine standard functions, users sometimes want to
implicitly redefine these functions when they are debugging using
the TRACE macro. Special-casing of standard functions can be
inhibited using the NOTINLINE declaration, but even then some
phases of analysis such as type inferencing are applied by the
compiler.
- The compiler can have multiple alternate implementations of
standard functions that implement different trade-offs of speed,
space and safety. This selection is based on the @COMPILER-POLICY.
When a function call is _open coded_, inline code whose effect is
equivalent to the function call is substituted for that function
call. When a function call is _closed coded_, it is usually left as
is, although it might be turned into a call to a different function
with different arguments. As an example, if NTHCDR were to be open
coded, then
(nthcdr 4 foobar)
might turn into
(cdr (cdr (cdr (cdr foobar))))
or even
(do ((i 0 (1+ i))
(list foobar (cdr foobar)))
((= i 4) list))
If NTH is closed coded, then
(nth x l)
might stay the same, or turn into something like
(car (nthcdr x l))
In general, open coding sacrifices space for speed, but some functions
(such as CAR) are so simple that they are always open-coded. Even
when not open-coded, a call to a standard function may be
transformed into a different function call (as in the last example)
or compiled as _static call_. Static function call uses a more
efficient calling convention that forbids redefinition.")
(defsection @interpreter (:title "Interpreter"
:concepts ("interpreter"))
"By default SBCL implements EVAL by calling the native code
compiler.
SBCL also includes an interpreter for use in special cases where
using the compiler is undesirable, for example due to compilation
overhead. Unlike in some other Lisp implementations, in SBCL
interpreted code is not safer or more debuggable than compiled code."
(sb-ext:*evaluator-mode* variable))
(defsection @advanced-compiler-use-and-efficiency-hints
(:title "Advanced Compiler Use and Efficiency Hints")
"For more advanced usages of the compiler, please see the chapter of the
same name in the CMUCL manual. Many aspects of the compiler have stayed
exactly the same, and there is a much more detailed explanation of the
compiler's behavior and how to maximally optimize code in their
manual. In particular, while SBCL no longer supports byte-code
compilation, it does support CMUCL's block compilation facility allowing
whole program optimization and increased use of the local call
convention.
Unlike CMUCL, SBCL is able to open-code forward-referenced type
tests while block compiling. This helps for mutually referential
DEFSTRUCTs in particular.")

View file

@ -0,0 +1,108 @@
(in-package :sb-manual)
(define-concept @interning-symbols (:title "interning symbols"
:keys (("interning" "symbols")
("symbols," "interning"))))
(define-concept @package-lock (:title "package lock"
:keys (("package" "lock")
("lock," "package"))))
(define-concept @unicode (:title "Unicode" :keys ("Unicode")))
(define-concept @nfkc (:title "NFKC"
:keys ("NFKC"
"normalization form compatibility composition")))
(define-concept ~unbound-slot (:keys (("unbound" "slot")
("slot," "unbound"))))
(define-concept ~character-name (:keys (("character" "name")
("name" "of character"))))
(define-concept @hash-table (:title "hash table"
:keys (("hash" "table"))))
(define-concept @actual-source (:title "actual source"
:keys (("actual" "source")
("source," "actual"))))
(define-concept @original-source (:title "original source"
:keys (("original" "source")
("source," "original"))))
(define-concept @processing-path (:title "processing path"
:keys (("processing" "path"))))
(define-concept @macroexpansion (:title "macroexpansion"
:keys ("macroexpansion")))
(define-concept ~source-transform (:keys (("source" "transform"))))
(define-concept ~safety (:keys (("safety," "optimization quality")
("optimization quality" "safety"))))
(define-concept @safety (:title "safety" :keys (~safety)))
(define-concept ~debug (:keys (("debug," "optimization quality")
("optimization quality" "debug"))))
(define-concept @debug (:title "debug" :keys (~debug)))
(define-concept @tail-recursion (:title "tail recursion"
:keys (("tail" "recursion")
("recursion," "tail"))))
(define-concept @tail-recursive (:title "tail recursive"
:keys (@tail-recursion)))
(define-concept @interrupt (:title "interrupt"
:keys ("interrupt")))
(define-concept ~run-time-error (:keys (("run-time" "error")
("error," "run-time"))))
(define-concept @basic-block (:title "basic block"
:keys ("basic block"
("block," "basic"))))
(define-concept @block-start (:title "block start"
:keys (("block," "start location"))))
(define-concept @semi-inline (:title "semi inline"
:keys (("inline," "semi")
("semi-inline"))))
(define-concept @external-format (:title "external format"
:keys (("external" "format")
("format," "external"))))
(define-concept @generational-gc
(:title "generational GC"
:keys (("garbage collector," "generational")
("generational" "garbage collector"))))
(define-concept @conservative-gc
(:title "conservative GC"
:keys (("garbage collector," "conservative")
("conservative" "garbage collector"))))
(define-concept @declaration (:title "declaration"
:keys ("declaration")))
(define-concept @logical-pathname (:title "logical pathname"
:keys (("logical" "pathname")
("pathname," "logical"))))
(define-concept @ldb (:title "LDB" :keys ("LDB")))
(define-concept ~disabling-ldb (:title "disabling LDB"
:keys (("disabling" "LDB")
("LDB," "disabling"))))
(define-concept ~enabling-ldb (:title "enabling LDB"
:keys (("enabling" "LDB")
("LDB," "enabling"))))
(define-concept ~repl (:keys ("Read-Eval-Print Loop" "REPL")))
(define-concept @repl (:title "REPL" :keys (~repl)))

View file

@ -0,0 +1,29 @@
(in-package :sb-manual)
(defsection @contributed-modules (:title "Contributed Modules")
"SBCL comes with a number of modules that are not part of the core
system. These are loaded via `(REQUIRE :<MODULENAME>)`
(see @CUSTOMIZATION-HOOKS-FOR-USERS). This section contains
documentation (or pointers to documentation) for some of the
contributed modules."
#+#.(sb-manual::package-exists-p/reader '#:sb-aclrepl)
(@sb-aclrepl section)
#+#.(sb-manual::package-exists-p/reader '#:sb-concurrency)
(@sb-concurrency section)
#+#.(sb-manual::package-exists-p/reader '#:sb-cover)
(@sb-cover section)
#+#.(sb-manual::package-exists-p/reader '#:sb-grovel)
(@sb-grovel section)
#+#.(sb-manual::package-exists-p/reader '#:sb-introspect)
(@sb-introspect section)
(@sb-manual section)
#+#.(sb-manual::package-exists-p/reader '#:sb-md5)
(@sb-md5 section)
#+#.(sb-manual::package-exists-p/reader '#:sb-posix)
(@sb-posix section)
#+#.(sb-manual::package-exists-p/reader '#:sb-queue)
(@sb-queue section)
#+#.(sb-manual::package-exists-p/reader '#:sb-rotate-byte)
(@sb-rotate-byte section)
#+#.(sb-manual::package-exists-p/reader '#:sb-simd)
(@sb-simd section))

View file

@ -0,0 +1,896 @@
(in-package :sb-manual)
(defsection @debugger (:title "Debugger"
:concepts ("debugger"))
"This chapter documents the debugging facilities of SBCL, including
the debugger, single-stepper and TRACE, and the effect of `(OPTIMIZE
DEBUG)` declarations."
(@debugger-entry section)
(@debugger-command-loop section)
(@stack-frames section)
(@variable-access section)
(@source-location-printing section)
(@debugger-policy-control section)
(@exiting-commands section)
(@information-commands section)
(@breakpoint-commands section)
(@function-tracing section)
(@single-stepping section)
(@enabling-and-disabling-the-debugger section))
(defsection @debugger-entry (:title "Debugger Entry")
(@debugger-banner section)
(@debugger-invocation section))
(defsection @debugger-banner (:title "Debugger Banner")
"When you enter the debugger, it looks something like this:
debugger invoked on a TYPE-ERROR in thread 11184:
The value 3 is not of type LIST.
You can type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT ] Reduce debugger level (leaving debugger, returning to toplevel).
1: [TOPLEVEL] Restart at toplevel READ/EVAL/PRINT loop.
(CAR 1 3)
0]
The first group of lines describe what the error was that put us in
the debugger. In this case CAR was called on `3`, causing a
TYPE-ERROR.
This is followed by the \"beginner help line\", which appears only
if SB-DEBUG:*DEBUG-BEGINNER-HELP-P* is true (default).
Next comes a listing of the active restart names, along with their
descriptions -- the ways we can restart execution after this error.
In this case, both options return to top-level. Restarts can be
selected by entering the corresponding number or name.
The current frame appears right underneath the restarts, immediately
followed by the debugger prompt.")
(defsection @debugger-invocation (:title "Debugger Invocation")
"The debugger is invoked when:
- ERROR is called, and the condition it signals is not handled.
- BREAK is called, or SIGNAL is called with a condition that matches
the current *BREAK-ON-SIGNALS*.
- The debugger is explicitly entered with the INVOKE-DEBUGGER
function.
When the debugger is invoked by a condition, ANSI mandates that the
value of *DEBUGGER-HOOK*, if any, be called with two arguments: the
condition that caused the debugger to be invoked and the previous
value of *DEBUGGER-HOOK*. When this happens, *DEBUGGER-HOOK* is
bound to NIL to prevent recursive errors. However, ANSI also
mandates that *DEBUGGER-HOOK* not be invoked when the debugger is to
be entered by the BREAK function. For users who wish to provide an
alternate debugger interface (and thus catch BREAK entries into the
debugger), SBCL provides SB-EXT:*INVOKE-DEBUGGER-HOOK*, which is
invoked during any entry into the debugger."
;; When Swank is loaded, it sets this variable.
(sb-ext:*invoke-debugger-hook* (variable nil)))
(defsection @debugger-command-loop (:title "Debugger Command Loop")
"The debugger is an interactive read-eval-print loop much like the
normal top level, but some symbols are interpreted as debugger
commands instead of being evaluated. A debugger command starts with
the symbol name of the command, possibly followed by some arguments
on the same line. Some commands prompt for additional input.
Debugger commands can be abbreviated by any unambiguous prefix:
`help` can be typed as `h`, `he`, etc.
The package is not significant in debugger commands; any symbol with
the name of a debugger command will work. If you want to show the
value of a variable that happens also to be the name of a debugger
command you can wrap the variable in a PROGN to hide it from
the command loop.
The debugger prompt is `<frame>]`, where `<frame>` is the number of
the current frame. Frames are numbered starting from zero at the
top (most recent call), increasing down to the bottom. The current
frame is the frame that commands refer to.
It is possible to override the normal printing behaviour in the
debugger by using the SB-EXT:*DEBUG-PRINT-VARIABLE-ALIST*."
(sb-ext:*debug-print-variable-alist* variable))
(defsection @stack-frames (:title "Stack Frames"
:concepts ("stack frame"))
"A _stack frame_ is the run-time representation of a call to a
function; the frame stores the state that a function needs to
remember what it is doing. Frames have:
- _Variables_ (see @VARIABLE-ACCESS), which are the values being
operated on.
- _Arguments_ to the call (which are really just particularly
interesting variables).
- A current source location (@SOURCE-LOCATION-PRINTING), which is
the place in the program where the function was running when it
stopped to call another function, or because of an interrupt or
error."
(@stack-motion section)
(@how-arguments-are-printed section)
(@function-names section)
(@debug-tail-recursion section)
(@unknown-locations-and-interrupts section))
(defsection @stack-motion (:title "Stack Motion")
"These commands move to a new stack frame and print the name of the
function and the values of its arguments in the style of a Lisp
function call:
- `up`: Move up to the next higher frame. More recent function calls
are considered to be higher on the stack.
- `down`: Move down to the next lower frame.
- `top`: Move to the highest frame, that is, the frame where the
debugger was entered.
- `bottom`: Move to the lowest frame.
- `frame [<n>]`: Move to the frame with the specified number.
Prompts for the number if not supplied. The frame with number 0 is
the frame where the debugger was entered.")
(defsection @how-arguments-are-printed (:title "How Arguments are Printed")
"A frame is printed to look like a function call, but with the actual
argument values in the argument positions. So the frame for this call
in the source:
(myfun (+ 3 4) 'a)
would look like this:
(MYFUN 7 A)
All keyword and optional arguments are displayed with their actual
values; if the corresponding argument was not supplied, the value will
be the default. So this call:
(subseq \"foo\" 1)
would look like this:
(SUBSEQ \"foo\" 1 3)
And this call:
(string-upcase \"test case\")
would look like this:
(STRING-UPCASE \"test case\" :START 0 :END NIL)
The arguments to a function call are displayed by accessing the
argument variables. Although those variables are initialized to the
actual argument values, they can be set inside the function; in this
case the new value will be displayed.
&REST arguments are handled somewhat differently. The value of the
rest argument variable is displayed as the spread-out arguments to
the call, so:
(format t \"~A is a ~A.\" \"This\" 'test)
would look like this:
(FORMAT T \"~A is a ~A.\" \"This\" 'TEST)
Rest arguments cause an exception to the normal display of keyword
arguments in functions that have both &REST and &KEY arguments. In
this case, the keyword argument variables are not displayed at all;
the rest arg is displayed instead. So for these functions, only the
keywords actually supplied will be shown, and the values displayed
will be the argument values, not values of the
(possibly modified) variables.
If the variable for an argument is never referenced by the function,
it will be deleted. The variable value is then unavailable, so the
debugger prints `#<unused-arg>` instead of the value. Similarly, if
for any of a number of reasons the value of the variable is
unavailable or not known to be available (@VARIABLE-ACCESS), then
`#<unavailable-arg>` will be printed instead of the argument value.
Note that inline expansion and open-coding affect what frames are
present in the debugger, see @DEBUGGER-POLICY-CONTROL."
;; FIXME: Link here to section about open coding once it exists.
)
(defsection @function-names (:title "Function Names")
"If a function is defined by DEFUN it will appear in backtrace
by that name. Functions defined by LABELS and FLET will appear as
`(FLET <NAME>)` and `(LABELS <NAME>)` respectively. Anonymous
lambdas will appear as `(LAMBDA <LAMBDA-LIST>)`."
(@entry-point-details section))
(defsection @entry-point-details
(:title "Entry Point Details"
:concepts (("external" "entry point")
("entry point," "external")
("block compilation," "debugger implications")
("external," "stack frame kind")
("optional," "stack frame kind")
("cleanup," "stack frame kind")))
"Sometimes the compiler introduces new functions that are used to
implement a user function, but are not directly specified in the
source. This is mostly done for argument type and count checking.
With recursive or block compiled functions, an additional `external`
frame may appear before the frame representing the first call to the
recursive function or entry to the compiled block. This is a
consequence of the way the compiler works: there is nothing odd with
your program. You may also see `cleanup` frames during the execution
of UNWIND-PROTECT cleanup code, and `optional` for variable argument
entry points.")
(defsection @debug-tail-recursion (:title "Debug Tail Recursion")
"The compiler is _properly tail recursive_. If a function call is
in a @TAIL-RECURSIVE position, the stack frame will be deallocated
_at the time of the call_, rather than after the call returns.
Consider this backtrace:
(BAR ...)
(FOO ...)
Because of tail recursion, it is not necessarily the case that `FOO`
directly called `BAR`. It may be that `FOO` called some other
function `FOO2`, which then called `BAR` tail-recursively, as in
this example:
(defun foo ()
...
(foo2 ...)
...)
(defun foo2 (...)
...
(bar ...))
(defun bar (...)
...)
Usually the elimination of tail-recursive frames makes debugging
more pleasant, since these frames are mostly uninformative. If there
is any doubt about how one function called another, it can usually
be eliminated by finding the source location in the calling frame.
See @SOURCE-LOCATION-PRINTING.
The elimination of tail-recursive frames can be prevented by
disabling tail-recursion optimization, which happens when the DEBUG
optimization quality is greater than 2. See
@DEBUGGER-POLICY-CONTROL."
;; FIXME: reinstate this link once the chapter is in the manual. For
;; a more thorough discussion of tail recursion, see @TAIL-RECURSION.
)
(defsection @unknown-locations-and-interrupts
(:title "Unknown Locations and Interrupts"
:concepts (("unknown code location")
("code location" "unknown")))
"The debugger operates using special debugging information attached to
the compiled code. This debug information tells the debugger what it
needs to know about the locations in the code where the debugger can
be invoked. If the debugger somehow encounters a location not
described in the debug information, then it is said to be _unknown_.
If the code location for a frame is unknown, then some variables may
be inaccessible, and the source location cannot be precisely
displayed.
There are three reasons why a code location could be unknown:
- There is inadequate debug information due to the value of the
DEBUG optimization quality. See @DEBUGGER-POLICY-CONTROL.
- The debugger was entered because of an @INTERRUPT such as `C-c`.
- A hardware error ~RUN-TIME-ERROR such as a bus error occurred in
code that was compiled unsafely due to the value of the SAFETY
optimization quality."
;; FIXME: reinstate link when section on optimize qualities exists.
;; @OPTIMIZE-DECLARATION.
"In the last two cases, the values of argument variables are
accessible, but may be incorrect. For more details on when variable
values are accessible, see @VARIABLE-VALUE-AVAILABILITY.
It is possible for an interrupt to happen when a function call or
return is in progress. The debugger may then flame out with some
obscure error or insist that the bottom of the stack has been
reached, when the real problem is that the current stack frame can't
be located. If this happens, return from the interrupt and try
again.")
(defsection @variable-access (:title "Variable Access"
:concepts (("debug" "variables")
("variable," "debugger access")))
"There are two ways to access the current frame's local variables in
the debugger: `list-locals` and SB-DEBUG:VAR.
The debugger doesn't really understand lexical scoping; it has just
one namespace for all the variables in the current stack frame. If a
symbol is the name of multiple variables in the same function, then
the reference appears ambiguous, even though lexical scoping
specifies which value is visible at any given source location. If
the scopes of the two variables are not nested, then the debugger
can resolve the ambiguity by observing that only one variable is
accessible.
When there are ambiguous variables, the evaluator assigns each one a
small integer identifier. The SB-DEBUG:VAR function uses this
identifier to distinguish between ambiguous variables. The
`list-locals` command prints the identifier. In the following
example, there are two variables named `X`. The first one has
identifier 0 (which is not printed), the second one has identifier
1.
X = 1
X#1 = 2
- `list-locals [<prefix>]`: This command prints the name and value
of all variables in the current frame whose name has the specified
`<prefix>`, which may be a string or a symbol. If no `<prefix>` is
given, then all available variables are printed. If a variable has
a potentially ambiguous name, then the name is printed with a
`#<identifier>` suffix, where `<identifier>` is the small integer
used to make the name unique."
(sb-debug:var function)
(@variable-value-availability section)
(@note-on-lexical-variable-access section))
(defsection @variable-value-availability
(:title "Variable Value Availability"
:concepts (("variable," "value availabilty in debugger")
("debug variable," "value availabilty")))
"The value of a variable may be unavailable to the debugger in portions
of the program where Lisp says that the variable is defined. If a
variable value is not available, the debugger will not let you read
or write that variable. With one exception, the debugger will never
display an incorrect value for a variable. Rather than displaying
incorrect values, the debugger tells you the value is unavailable.
The one exception is this: if you interrupt (e.g. with `C-c`) or if
there is an unexpected hardware error such as a bus error (which
should only happen in unsafe code), then the values displayed for
arguments to the interrupted frame might be incorrect. This
exception applies only to the interrupted frame: any frame farther
down the stack will be fine.
> _Note_: Since the location of an interrupt or hardware error will
> always be an unknown location, non-argument variable values will
> never be available in the interrupted frame. See
> @UNKNOWN-LOCATIONS-AND-INTERRUPTS.)
The value of a variable may be unavailable for these reasons:
- The value of the @DEBUG optimization quality may have omitted
debug information needed to determine whether the variable is
available. Unless a variable is an argument, its value will only
be available when DEBUG is at least 2.
- The compiler did lifetime analysis and determined that the value
was no longer needed, even though its scope had not been exited.
Lifetime analysis is inhibited when the DEBUG optimization
quality is 3.
- The variable's name is an uninterned symbol (gensym). To save
space, the compiler only dumps debug information about uninterned
variables when the DEBUG optimization quality is 3.
- The frame's location is unknown (see
@UNKNOWN-LOCATIONS-AND-INTERRUPTS) because the debugger was
entered due to an interrupt or unexpected hardware error. Under
these conditions the values of arguments will be available, but
might be incorrect. This is the exception mentioned above.
- The variable (or the code referencing it) was optimized out of
existence. Variables with no reads are always optimized away. The
degree to which the compiler deletes variables will depend on the
value of the COMPILATION-SPEED optimization quality, but most
source-level optimizations are done under all compilation
policies.
- The variable is never set and its definition looks like
(LET ((var1 var2))
...)
In this case, `VAR1` is substituted with `VAR2`.
- The variable is never set and is referenced exactly once. In this
case, the reference is substituted with the variable initial
value.
Since it is especially useful to be able to get the arguments to a
function, argument variables are treated specially when the SPEED
optimization quality is less than 3 and the DEBUG quality is at
least 1. With this compilation policy, the values of argument
variables are almost always available everywhere in the function,
even at unknown locations. For non-argument variables, DEBUG must be
at least 2 for values to be available, and even then, values are
only available at known locations.")
(defsection @note-on-lexical-variable-access
(:title "Note On Lexical Variable Access")
"When the debugger command loop establishes variable bindings for
available variables, these variable bindings have lexical scope and
dynamic extent. You can close over them, but such closures can't be
used as upward function arguments.
> _Note_: The variable bindings are actually created using the Lisp
> SYMBOL-MACROLET special form.
You can also set local variables using SETQ, but if the variable was
closed over in the original source and never set, then setting the
variable in the debugger may not change the value in all the
functions the variable is defined in. Another risk of setting
variables is that you may assign a value of a type that the compiler
proved the variable could never take on. This may result in bad
things happening.")
(defsection @source-location-printing
(:title "Source Location Printing"
:concepts (("source location" "in debugger")))
"One of the debugger's capabilities is source level debugging of
compiled code. These commands display the source location for the
current frame:
- `source [<context>]`: This command displays the file that the
current frame's function was defined from (if it was defined from
a file), and then the source form responsible for generating the
code that the current frame was executing. If `<context>` is
specified, then it is an integer specifying the number of
enclosing levels of list structure to print.
The source form for a location in the code is the innermost list
present in the original source that encloses the form responsible
for generating that code. If the actual source form is not a list,
then some enclosing list will be printed. For example, if the source
form was a reference to the variable `*SOME-RANDOM-SPECIAL*`, then
the innermost enclosing evaluated form will be printed. Here are
some possible enclosing forms:
(let ((a *some-random-special*))
...)
(+ *some-random-special* ...)
If the code at a location was generated from the expansion of a
macro or a source-level compiler optimization, then the form in the
original source that expanded into that code will be printed.
Suppose the file `/usr/me/mystuff.lisp` looked like this:
(defmacro mymac ()
'(myfun))
(defun foo ()
(mymac)
...)
If `FOO` has called `MYFUN`, and is waiting for it to return, then
the `source` command would print:
; File: /usr/me/mystuff.lisp
(MYMAC)
Note that the macro use was printed, not the actual function call form,
`(MYFUN)`.
If enclosing source is printed by giving an argument to `source` or
`vsource`, then the actual source form is marked by wrapping it in a
list whose first element is `#:***HERE***`. In the previous example,
`source 1` would print:
; File: /usr/me/mystuff.lisp
(DEFUN FOO ()
(#:***HERE***
(MYMAC))
...)"
(@how-the-source-is-found section)
(@source-location-availability section))
(defsection @how-the-source-is-found (:title "How the Source is Found")
"If the code was defined from Lisp by COMPILE or EVAL, then the source
can always be reliably located. If the code was defined from a FASL
file created by COMPILE-FILE, then the debugger gets the source
forms it prints by reading them from the original source file. This
is a potential problem, since the source file might have moved or
changed since the time it was compiled.
The source file is opened using the TRUENAME of the source file
pathname originally given to the compiler. This is an absolute
pathname with all logical names and symbolic links expanded. If the
file can't be located using this name, then the debugger gives up
and signals an error.
If the source file can be found, but has been modified since the time it was
compiled, the debugger prints this warning:
; File has been modified since compilation:
; <filename>
; Using form offset instead of character position.
where `<filename>` is the name of the source file. It then proceeds
using a robust but not foolproof heuristic for locating the source.
This heuristic works if:
- No top-level forms before the top-level form containing the source
have been added or deleted, and
- the top-level form containing the source has not been modified
much. (More precisely, none of the list forms beginning before the
source form have been added or deleted.)
If the heuristic doesn't work, the displayed source will be wrong,
but will probably be near the actual source. If the \"shape\" of the
top-level form in the source file is too different from the original
form, then an error will be signaled. When the heuristic is used,
the source location commands are noticeably slowed.
Source location printing can also be confused if (after the source
was compiled) a read-macro you used in the code was redefined to
expand into something different, or if a read-macro ever returns the
same EQ list twice. If you don't define read macros and don't use
`##` in perverted ways, you don't need to worry about this.")
(defsection @source-location-availability
(:title "Source Location Availability")
"Source location information is only available when the @DEBUG
optimization quality is at least 2. If source location information
is unavailable, the source commands will give an error message.
If source location information is available, but the source location
is unknown because of an interrupt or unexpected hardware error
(see @UNKNOWN-LOCATIONS-AND-INTERRUPTS), then the command will
print
Unknown location: using block start.
and then proceed to print the source location for the start of the
_@BASIC-BLOCK_ enclosing the code location. It's a bit complicated to
explain exactly what a basic block is, but here are some properties
of the block start location:
- The @BLOCK-START location may be the same as the true location.
- The block start location will never be later in the program's flow
of control than the true location.
- No conditional control structures (such as IF, COND, OR) will
intervene between the block start and the true location (but note
that some conditionals present in the original source could be
optimized away.) Function calls _do not_ end basic blocks.
- The head of a loop will be the start of a block.
- The programming language concept of block structure and the Lisp
BLOCK special form are totally unrelated to the compiler's basic
block.
In other words, the true location lies between the printed location
and the next conditional (but watch out because the compiler may
have changed the program on you.)")
(defsection @debugger-policy-control (:title "Debugger Policy Control"
:concepts (("debugger" "policy")
("policy," "debugger")))
"The compilation policy specified by OPTIMIZE declarations
affects the behavior seen in the debugger. The @DEBUG quality
directly affects the debugger by controlling the amount of debugger
information dumped. Other optimization qualities have indirect but
observable effects due to changes in the way compilation is done.
Unlike the other optimization qualities (which are compared in
relative value to evaluate tradeoffs), the DEBUG optimization
quality is directly translated to a level of debug information. This
absolute interpretation allows the user to count on a particular
amount of debug information being available even when the values of
the other qualities are changed during compilation. These are the
levels of debug information that correspond to the values of the
DEBUG quality:
- `0`: Only the function name and enough information to allow the
stack to be parsed.
- `> 0`: Any level greater than 0 gives level 0 plus all argument
variables. Values will only be accessible if the argument variable
is never set and SPEED is not 3. SBCL allows any real value for
optimization qualities. It may be useful to specify 0.5 to get
backtrace argument display without argument documentation.
- `1`: Level 1 provides argument documentation (printed argument
lists) and derived argument/result type information. This makes
DESCRIBE more informative, and allows the compiler to do
compile-time argument count and type checking for any calls
compiled at run-time. This is the default.
- `2`: Level 1 plus all interned local variables, source location
information, and lifetime information that tells the debugger when
arguments are available (even when SPEED is 3 or the argument is
set).
- `> 2`: Any level greater than 2 gives level 2 and in addition
disables tail-call optimization, so that the backtrace will
contain frames for all invoked functions, even those in tail
positions.
- `3`: Level 2 plus all uninterned variables. In addition, lifetime
analysis is disabled (even when SPEED is 3), ensuring that all
variable values are available at any known location within the
scope of the binding. This has a speed penalty in addition to the
obvious space penalty.
Inlining of local functions is inhibited so that they may be TRACEd.
- `> (MAX SPEED SPACE)`: If DEBUG is greater than both SPEED and
SPACE, the command `return` can be used to continue execution by
returning a value from the current stack frame.
- `> (MAX SPEED SPACE COMPILATION-SPEED)`: If DEBUG is greater than
all of SPEED, SPACE and COMPILATION-SPEED the code will be
steppable (see @SINGLE-STEPPING).
As you can see, if the SPEED quality is 3, debugger performance is
degraded. This effect comes from the elimination of argument
variable special-casing (see @VARIABLE-VALUE-AVAILABILITY). Some
degree of speed/debuggability tradeoff is unavoidable, but the
effect is not too drastic when DEBUG is at least 2.
In addition to INLINE and NOTINLINE declarations, the relative
values of the SPEED and SPACE qualities also change whether
functions are inline expanded. If a function is inline expanded,
then there will be no frame to represent the call, and the arguments
will be treated like any other local variable. Functions may also be
_@SEMI-INLINE_, in which case there is a frame to represent the
call, but the call is to an optimized local version of the function,
not to the original function."
;; FIXME: link to section about inline expansion when it exists
;; (@INLINE-EXPANSION).
)
(defsection @exiting-commands (:title "Exiting Commands")
"These commands get you out of the debugger.
- `toplevel`: Throw to top level.
- `restart [<n>]`: Invoke the `<n>`th restart case as displayed by
the `error` command. If `<n>` is not specified, the available
restart cases are reported.
- `\\continue`: Call CONTINUE on the condition given to DEBUG. If
there is no restart case named CONTINUE, then an error is
signaled.
- `\\abort`: Call ABORT on the condition given to DEBUG. This is
useful for popping debug command loop levels or aborting to top
level, as the case may be.
- `return <value>`: Return `VALUE` from the current stack frame.
This command is available when the DEBUG optimization quality is
greater than both SPEED and SPACE. Care must be taken that the
value is of the same type as SBCL expects the stack frame to
return.
- `restart-frame`: Restart execution of the current stack frame.
This command is available when the DEBUG optimization quality is
greater than both SPEED and SPACE and when the frame is for a
global function. If the function is redefined in the debugger
before the frame is restarted, the new function will be used.")
(defsection @information-commands (:title "Information Commands")
"Most of these commands print information about the current frame or
function, but a few show general information.
- `help` or `?`: Display a synopsis of debugger commands.
- `\\describe`: Call DESCRIBE on the current function and displays the
number of local variables.
- `\\print`: Display the current function call as it would be
displayed by moving to this frame.
- `\\error`: Print the condition given to INVOKE-DEBUGGER and the
active proceed cases.
- `backtrace [<n>]`: Display all the frames from the current to the
bottom. Only shows `<n>` frames if specified. The printing is
controlled by SB-DEBUG:*DEBUG-PRINT-VARIABLE-ALIST*.")
(defsection @breakpoint-commands (:title "Breakpoint Commands"
:concepts ("breakpoint"))
"SBCL supports setting of breakpoints inside compiled functions and
stepping of compiled code. Breakpoints can only be set at known
locations (see @UNKNOWN-LOCATIONS-AND-INTERRUPTS), so these commands
are largely useless unless the DEBUG optimize quality is at least
2 (see @DEBUGGER-POLICY-CONTROL). These commands manipulate
breakpoints:
- `breakpoint <location> [<option> <value>]*`: Set a breakpoint in
some function. `<location>` may be an integer code location
number (as displayed by `list-locations`) or a keyword. The
keyword can be used to indicate setting a breakpoint at the
function start (:START, `:S`) or function end (:END, `:E`). The
`breakpoint` command has :CONDITION, :BREAK, :PRINT and :FUNCTION
options which work similarly to the TRACE options.
- `list-locations [<function>]` or `ll [<function>]`: List all the
code locations in the current frame's function, or in `<function>`
if it is supplied. The display format is the code location number,
a colon and then the source form for that location:
3: (1- N)
If consecutive locations have the same source, then a numeric
range like `3-5:` will be printed. For example, a default
function call has a known location both immediately before and
after the call, which would result in two code locations with
the same source. The listed function becomes the new default
function for breakpoint setting (via the `breakpoint`) command.
- `list-breakpoints` or `lb`: List all currently active breakpoints
with their breakpoint number.
- `delete-breakpoint [<number>]` or `db [<number>]`: Delete a
breakpoint specified by its breakpoint number. If no number is
specified, delete all breakpoints.
- `step*`: Step to the next possible breakpoint location in the
current function. This always steps over function calls, instead
of stepping into them."
(@breakpoint-example section))
(defsection @breakpoint-example (:title "Breakpoint Example")
"Consider this definition of the factorial function:
(defun ! (n)
(if (zerop n)
1
(* n (! (1- n)))))
This debugger session demonstrates the use of breakpoints:
* (break) ; invoke debugger
debugger invoked on a SIMPLE-CONDITION in thread 11184: break
restarts (invokable by number or by possibly-abbreviated name):
0: [CONTINUE] Return from BREAK.
1: [ABORT ] Reduce debugger level (leaving debugger, returning to toplevel).
2: [TOPLEVEL] Restart at toplevel READ/EVAL/PRINT loop.
(\"varargs entry for top level local call BREAK\" \"break\")
0] ll #'!
0-1: (SB-INT:NAMED-LAMBDA ! (N) (BLOCK ! (IF (ZEROP N) 1 (* N (! #)))))
2: (BLOCK ! (IF (ZEROP N) 1 (* N (! (1- N)))))
3: (ZEROP N)
4: (* N (! (1- N)))
5: (1- N)
6: (! (1- N))
7-8: (* N (! (1- N)))
9-10: (IF (ZEROP N) 1 (* N (! (1- N))))
0] br 4
(* N (! (1- N)))
1: 4 in !
added
0] toplevel
> (! 10) ; Call the function
*Breakpoint hit*
Restarts:
0: [CONTINUE] Return from BREAK.
1: [ABORT ] Return to Top-Level.
Debug (type H for help)
(! 10) ; We are now in first call (arg 10) before the multiply
Source: (* N (! (1- N)))
3] step*
*Step*
(! 10) ; We have finished evaluation of (1- n)
Source: (1- N)
3] step*
*Breakpoint hit*
Restarts:
0: [CONTINUE] Return from BREAK.
1: [ABORT ] Return to Top-Level.
Debug (type H for help)
(! 9) ; We hit the breakpoint in the recursive call
Source: (* N (! (1- N)))
3]
> _Note_: The `step*` command differs from the single stepping
> commands in that it also functions in compiled code which has not
> been compiled with stepping instrumentation. It simply steps to
> the next compiled code location. In the future, this form of
> stepping may be improved enough to subsume the instrumentation
> based stepping commands, which have much higher overhead.")
(defsection @function-tracing (:title "Function Tracing"
:concepts ("tracing"
("function," "tracing")))
"The tracer causes selected functions to print their arguments and
their results whenever they are called. Options allow conditional
printing of the trace information and conditional breakpoints on
function entry or exit.
In SBCL, tracing can be done either by temporarily redefining the
function name (encapsulation), or using breakpoints. When
breakpoints are used, the function object itself is destructively
modified to cause the tracing action. The advantage of using
breakpoints is that tracing works even when the function is
anonymously called via FUNCALL, that function object identity is
preserved, and that anonymous and local functions can also be
traced."
(trace macro)
"In the case of functions where the known return convention is used
to optimize, encapsulation may be necessary in order to make tracing
work at all. The symptom of this occurring is an error stating
Error in function FOO: :FUNCTION-END breakpoints are
currently unsupported for the known return convention.
in such cases we recommend using `(TRACE FOO :ENCAPSULATE t)`."
(untrace macro)
(sb-debug:*trace-indentation-step* variable)
(sb-debug:*max-trace-indentation* variable)
(sb-debug:*trace-encapsulate-default* variable)
(sb-debug:*trace-report-default* variable))
(defsection @single-stepping (:title "Single Stepping"
:concepts ("stepper"
"single-stepping"))
"SBCL includes an instrumentation based single-stepper for compiled
code, that can be invoked via the STEP macro, or from within the
debugger. See @DEBUGGER-POLICY-CONTROL, for details on enabling
stepping for compiled code.
The following debugger commands are used for controlling single stepping.
- `start`: Select the CONTINUE restart if one exists and starts
single stepping. None of the other single stepping commands can be
used before stepping has been started either by using `start` or
by using the standard STEP macro.
- `step`: Step into the current form. Stepping will be resumed when
the next form that has been compiled with stepper instrumentation
is evaluated.
- `next`: Step over the current form. Stepping will be disabled
until evaluation of the form is complete.
- `out`: Step out of the current frame. Stepping will be disabled
until the topmost stack frame that had been stepped into returns.
- `stop`: Stop the single stepper and resumes normal execution."
(step macro))
(defsection @enabling-and-disabling-the-debugger
(:title "Enabling and Disabling the Debugger"
:concepts (("debugger," "enabling")
("debugger," "disabling")
("enabling" "debugger")
("disabling" "debugger")
~enabling-ldb
~disabling-ldb))
"In certain contexts (e.g. non-interactive applications), it may be
desirable to turn off the SBCL debugger (and possibly re-enable it).
The functions here control the debugger."
(sb-ext:disable-debugger function)
(sb-ext:enable-debugger function))

View file

@ -0,0 +1,396 @@
(in-package :sb-manual)
(defsection @deprecation (:title "Deprecation"
:concepts ("deprecation"))
"In order to support evolution of interfaces in SBCL as well as in user
code, SBCL allows declaring functions, variables and types as
deprecated. Users of deprecated things are notified by means of
warnings while the deprecated thing in question is still available.
This chapter documents the interfaces for being notified when using
deprecated thing and declaring things as deprecated, the deprecation
process used for SBCL interfaces, and lists legacy interfaces in
various stages of deprecation.
_Deprecation_ in this context should not be confused with those
things the ANSI Common Lisp standard calls _deprecated_: the
entirety of ANSI CL is supported by SBCL, and none of those
interfaces are subject to censure."
(@why-deprecate? section)
(@the-deprecation-pipeline section)
(@deprecation-conditions section)
(@introspecting-deprecation-information section)
(@deprecation-declaration section)
(@deprecation-examples section)
(@deprecated-interfaces-in-sbcl section))
(defsection @why-deprecate? (:title "Why Deprecate?")
"While generally speaking we try to keep SBCL changes as backwards
compatible as feasible, there are situations when existing interfaces
are deprecated:
- __Broken Interfaces__
Sometimes it turns out that an interface is sufficiently
misdesigned that fixing it would be worse than deprecating it
and replacing it with another.
This is typically the case when fixing the interface would
change its semantics in ways that could break user code subtly:
in such cases we may end up considering the obvious breakage
caused by deprecation to be preferable.
Another example are functions or macros whose current signature
makes them hard or impossible to extend in the future: backwards
compatible extensions would either make the interface
intolerably hairy, or are sometimes outright impossible.
- __Internal Interfaces__
SBCL has several internal interfaces that were never meant to be
used in user code -- or at least never meant to be used in user
code unwilling to track changes to SBCL internals.
Ideally, we'd like to be free to refactor our own internals as
we please, without even going through the hassle of deprecating
things. Sometimes, however, it turns out that our internal
interfaces have several external users who aren't using them
advisedly, but due to misunderstandings regarding their status
or stability.
Consider a deprecated internal interface a reminder for SBCL
maintainers not to delete the thing just yet, even though it is
seems unused -- because it has external users.
When internal interfaces are deprecated we try our best to
provide supported alternatives.
- __Aesthetics & Ease of Maintenance__
Sometimes an interface isn't broken or internal but just
inconsistent somehow.
This mostly happens only with historical interfaces inherited
from CMUCL which often haven't been officially supported in SBCL
before, or with new extensions to SBCL that haven't been around
for very long in the first place.
The alternative would be to keep the suboptimal version around
forever, possibly alongside an improved version. Sometimes we
may do just that, but because every line of code comes with a
maintenance cost, sometimes we opt to deprecate the suboptimal
version instead: SBCL doesn't have infinite developer resources.
We also believe that sometimes cleaning out legacy interfaces
helps keep the whole system more comprehensible to users, and
makes introspective tools such as APROPOS more useful.")
(defsection @the-deprecation-pipeline (:title "The Deprecation Pipeline")
"SBCL uses a _deprecation pipeline_ with multiplestages: as
time time goes by, deprecated things move from earlier stages of
deprecation to later stages before finally being removed. The
intention is making users aware of necessary changes early but
allowing a migration to new interfaces at a reasonable pace.
Deprecation proceeds in three stages, each lasting approximately a
year. In some cases it might move slower or faster, but one year per
stage is what we aim at in general. During each stage warnings (and
errors) of increasing severity are signaled, which note that the
interface is deprecated, and point users towards any replacements
when applicable.
- __Early Deprecation__
During early deprecation the interface is kept in working
condition. However, when a thing in this deprecation stage is
used, an SB-EXT:EARLY-DEPRECATION-WARNING, which is a
STYLE-WARNING, is signaled at compile-time.
The internals may change at this stage: typically because the
interface is re-implemented on top of its successor. While we
try to keep things as backwards-compatible as feasible (taking
maintenance costs into account), sometimes semantics change
slightly.
For example, when the spinlock API was deprecated, spinlock
objects ceased to exist, and the whole spinlock API became a
synonym for the mutex API -- so code using the spinlock API
continued working but silently switched to mutexes instead.
However, if someone relied on
(typep lock 'spinlock)
returning NIL for a mutexes, trouble could ensue.
- __Late Deprecation__
During late deprecation the interface remains as it was during
early deprecation, but the compile-time warning is upgraded:
when a thing in this deprecation stage is used, a
SB-EXT:LATE-DEPRECATION-WARNING, which is a full WARNING, is
signaled at compile-time.
- __Final Deprecation__
During final deprecation the symbols still exist. However, when
a thing in this deprecation stage is used, a
SB-EXT:FINAL-DEPRECATION-WARNING, which is a full WARNING, is
signaled at compile-time and an ERROR is signaled at run-time.
- __After Final Deprecation__
The interface is deleted entirely.")
(defsection @deprecation-conditions (:title "Deprecation Conditions")
"SB-EXT:DEPRECATION-CONDITION is the superclass of all
deprecation-related warning and error conditions. All common slots and
readers are defined in this condition class."
(sb-ext:deprecation-condition condition)
(sb-ext:early-deprecation-warning condition)
(sb-ext:late-deprecation-warning condition)
(sb-ext:final-deprecation-warning condition)
(sb-ext:deprecation-error condition))
(defsection @introspecting-deprecation-information
(:title "Introspecting Deprecation Information")
"The deprecation status of functions and variables can be inspected
using the SB-CLTL2:FUNCTION-INFORMATION and
SB-CLTL2:VARIABLE-INFORMATION functions provided by the `SB-CLTL2`
contributed module.")
(defsection @deprecation-declaration (:title "Deprecation Declaration")
"The SB-EXT:DEPRECATED declaration can be used to declare objects
in various namespaces as deprecated.
> _Note_: See the `namespace` CLHS glossary entry in the glossary of
> the Common Lisp HyperSpec.)"
(sb-ext:deprecated declaration))
(defsection @deprecation-examples (:title "Deprecation Examples")
"Marking functions as deprecated:
(defun foo ())
(defun bar ())
(declaim (deprecated :early (\"my-system\" \"1.2.3\")
(function foo :replacement bar)))
;; Remember: do not define the actual function or variable in case of
;; :final deprecation:
(declaim (deprecated :final (\"my-system\" \"1.2.3\")
(function fez :replacement whoop)))
Attempting to use the deprecated functions:
(defun baz ()
(foo))
| STYLE-WARNING: The function CL-USER::FOO has been deprecated...
=> BAZ
(baz)
=> NIL ; no error
(defun danger ()
(fez))
| WARNING: The function CL-USER::FEZ has been deprecated...
=> DANGER
(danger)
|- ERROR: The function CL-USER::FEZ has been deprecated...")
(defsection @deprecated-interfaces-in-sbcl
(:title "Deprecated Interfaces in SBCL")
"This sections lists legacy interfaces in various stages of deprecation."
(@list-of-deprecated-interfaces section)
(@historical-interfaces section))
(defsection @list-of-deprecated-interfaces
(:title "List of Deprecated Interfaces")
(@early-deprecation section)
(@late-deprecation section)
(@final-deprecation section))
(defsection @early-deprecation (:title "Early Deprecation")
"- `SOCKINT::WIN32-*`
Deprecated in favor of the corresponding prefix-less functions
(e.g. `SOCKINT::BIND` replaces `SOCKINT::WIN32-BIND`) as of
1.2.10 in March 2015. Expected to move into late deprecation in
August 2015.
- SB-UNIX:UNIX-EXIT
Deprecated as of 1.0.56.55 in May 2012. Expected to move into
late deprecation in May 2013.
When the SBCL process termination was refactored,
SB-UNIX:UNIX-EXIT ceased to be used internally. Since `SB-UNIX`
is an internal package not intended for user code to use, and
since we're slowly in the process of refactoring things to be
less Unix-oriented, SB-UNIX:UNIX-EXIT was initially deleted as
it was no longer used. Unfortunately it became apparent that it
was used by several external users, so it was re-instated in
deprecated form.
While the cost of keeping SB-UNIX:UNIX-EXIT indefinitely is
trivial, the ability to refactor our internals is important, so
its deprecation was taken as an opportunity to highlight that
`SB-UNIX` is an internal package and `SB-POSIX` should be used
by user-programs instead -- or alternatively calling the foreign
function directly if the desired interface doesn't for some
reason exist in `SB-POSIX`.
__Remedy__
For code needing to work with legacy SBCLs, use e.g.
`SYSTEM-EXIT`. In modern SBCLs, simply call either SB-POSIX:EXIT
or SB-EXT:EXIT with appropriate arguments.
- `SB-C::MERGE-TAIL-CALLS` compiler policy
Deprecated as of 1.0.53.74 in November 2011. Expected to move
into late deprecation in November 2012.
This compiler policy was never functional: SBCL has always
merged tail calls when it could, regardless of this policy
setting. (It was also never officially supported, but several
code-bases have historically used it.)
__Remedy__
Simply remove the policy declarations. They were never necessary: SBCL
always merged tail-calls when possible. To disable tail merging,
structure the code to avoid the tail position instead.
- The Spinlock API
Deprecated as of 1.0.53.11 in August 2011. Expected to move into
late deprecation in August 2012.
Spinlocks were an internal interface but had a number of
external users and were hence deprecated instead of being simply
deleted.
Affected symbols: SB-THREAD::SPINLOCK, SB-THREAD::MAKE-SPINLOCK,
SB-THREAD::WITH-SPINLOCK, SB-THREAD::WITH-RECURSIVE-SPINLOCK,
SB-THREAD::GET-SPINLOCK, SB-THREAD::RELEASE-SPINLOCK,
SB-THREAD::SPINLOCK-VALUE, and SB-THREAD::SPINLOCK-NAME.
__Remedy__
Use the mutex API instead, or implement spinlocks suiting your
needs on top of SB-EXT:COMPARE-AND-SWAP, SB-EXT:SPIN-LOOP-HINT,
etc.
- `SOCKINT::HANDLE->FD`, `SOCKINT::FD->HANDLE`
Internally deprecated in 2012. Declared deprecated as of 1.2.10
in March 2015. Expected to move into final deprecation in August
2015.")
(defsection @late-deprecation (:title "Late Deprecation")
"- SB-THREAD:JOIN-THREAD-ERROR-THREAD and
SB-THREAD:INTERRUPT-THREAD-ERROR-THREAD
Deprecated in favor of SB-THREAD:THREAD-ERROR-THREAD as of
1.0.29.17 in June 2009. Expected to move into final deprecation
in June 2012.
__Remedy__
For code that needs to support legacy SBCLs, use e.g.:
(defun get-thread-error-thread (condition)
#+#.(cl:if (cl:find-symbol \"THREAD-ERROR-THREAD\" :sb-thread)
'(and) '(or))
(sb-thread:thread-error-thread condition)
#-#.(cl:if (cl:find-symbol \"THREAD-ERROR-THREAD\" :sb-thread)
'(and) '(or))
(etypecase condition
(sb-thread:join-thread-error
(sb-thread:join-thread-error-thread condition))
(sb-thread:interrupt-thread-error
(sb-thread:interrupt-thread-error-thread condition))))
- SB-INTROSPECT:FUNCTION-ARGLIST
Deprecated in favor of SB-INTROSPECT:FUNCTION-LAMBDA-LIST as of
1.0.24.5 in January 2009. Expected to move into final
deprecation in January 2012.
Renamed for consistency and aesthetics. Functions have
lambda-lists, not arglists.
__Remedy__
For code that needs to support legacy SBCLs, use e.g.:
(defun get-function-lambda-list (function)
#+#.(cl:if (cl:find-symbol \"FUNCTION-LAMBDA-LIST\" :sb-introspect)
'(and) '(or))
(sb-introspect:function-lambda-list function)
#-#.(cl:if (cl:find-symbol \"FUNCTION-LAMBDA-LIST\" :sb-introspect)
'(and) '(or))
(sb-introspect:function-arglist function))
- Stack Allocation Policies
Deprecated in favor of SB-EXT:*STACK-ALLOCATE-DYNAMIC-EXTENT* as
of 1.0.19.7 in August 2008, and are expected to be removed in
August 2012.
Affected symbols: `SB-C::STACK-ALLOCATE-DYNAMIC-EXTENT`,
`SB-C::STACK-ALLOCATE-VECTOR`, and
`SB-C::STACK-ALLOCATE-VALUE-CELLS`.
These compiler policies were never officially supported, and
turned out the be a flawed design.
__Remedy__
For code that needs stack-allocation in legacy SBCLs,
conditionalize using:
#-#.(cl:if (cl:find-symbol \"*STACK-ALLOCATE-DYNAMIC-EXTENT*\" :sb-ext)
'(and) '(or))
(declare (optimize sb-c::stack-allocate-dynamic-extent))
However, unless stack allocation is essential, we recommend
simply removing these declarations. Refer to documentation on
`SB-EXT:*STACK-ALLOCATE-DYNAMIC*` for details on stack
allocation control in modern SBCLs.
- `SB-SYS:OUTPUT-RAW-BYTES`
Deprecated as of 1.0.8.16 in June 2007. Expected to move into final
deprecation in June 2012.
Internal interface with some external users. Never officially
supported, deemed unnecessary in presence of WRITE-SEQUENCE and
bivalent streams.
__Remedy__
Use streams with element-type (UNSIGNED-BYTE 8) or
:DEFAULT -- the latter allowing both binary and character IO --
in conjunction with WRITE-SEQUENCE.")
(defsection @final-deprecation (:title "Final Deprecation")
"No interfaces are currently in final deprecation.")
(defsection @historical-interfaces (:title "Historical Interfaces")
"The following is a partial list of interfaces present in historical
versions of SBCL, which have since then been deleted.
- `SB-KERNEL:INSTANCE-LAMBDA`
Historically needed for CLOS code. Deprecated as of 0.9.3.32 in
August 2005. Deleted as of 1.0.47.8 in April 2011. Plain LAMBDA
can be used where `SB-KERNEL:INSTANCE-LAMBDA` used to be needed.
- `SB-ALIEN:DEF-ALIEN-ROUTINE`, `SB-ALIEN:DEF-ALIEN-VARIABLE`,
`SB-ALIEN:DEF-ALIEN-TYPE`
Inherited from CMUCL, naming convention not consistent with
preferred SBCL style. Deprecated as of 0.pre7.90 in December
2001. Deleted as of 1.0.9.17 in September 2007. Replaced by
SB-ALIEN:DEFINE-ALIEN-ROUTINE, SB-ALIEN:DEFINE-ALIEN-VARIABLE,
and SB-ALIEN:DEFINE-ALIEN-TYPE.")

View file

@ -0,0 +1,387 @@
(in-package :sb-manual)
(defsection @efficiency (:title "Efficiency"
:concepts ("efficicency"))
(@slot-access section)
(@stack-allocation section)
(@modular-arithmetic section)
(@recognized-idioms section)
(@global-and-always-bound-variables section)
(@miscellaneous-efficiency-issues section))
(defsection @slot-access (:title "Slot Access"
:concepts (("slot" "access")))
(@structure-object-slot-access section)
(@standard-object-slot-access section))
(defsection @structure-object-slot-access
(:title "Structure Object Slot Access")
"Structure slot accessors are efficient only if the compiler is
able to open code them: compiling a call to a structure slot
accessor before the structure is defined, declaring one NOTINLINE,
or passing it as a functional argument to another function causes
severe performance degradation.")
(defsection @standard-object-slot-access
(:title "Standard Object Slot Access")
"The most efficient way to access a slot of a STANDARD-OBJECT is
by using SLOT-VALUE with a constant slot name argument inside a
DEFMETHOD body, where the variable holding the instance is a
specializer parameter of the method and is never assigned to. The
cost is roughly 1.6 times that of an open coded structure slot
accessor.
Second most efficient way is to use a CLOS slot accessor, or
SLOT-VALUE with a constant slot name argument, but in circumstances
other than specified above. This may be up to 3 times as slow as the
method described above.
Example:
(defclass foo () ((bar)))
;; Fast: specializer and never assigned to
(defmethod quux ((foo foo) new)
(let ((old (slot-value foo 'bar)))
(setf (slot-value foo 'bar) new)
old))
;; Slow: not a specializer
(defmethod quux ((foo foo) new)
(let* ((temp foo)
(old (slot-value temp 'bar)))
(setf (slot-value temp 'bar) new)
old))
;; Slow: assignment to FOO
(defmethod quux ((foo foo) new)
(let ((old (slot-value foo 'bar)))
(setf (slot-value foo 'bar) new)
(setf foo new)
old))
Note that when profiling code such as this, the first few calls to the
generic function are not representative, as the dispatch mechanism is
lazily set up during those calls.")
(defsection @stack-allocation (:title "Stack Allocation")
"SBCL has fairly extensive support for performing allocations on the
stack when a variable or function is declared DYNAMIC-EXTENT. The
DYNAMIC-EXTENT declarations are not verified but are simply trusted
as long as SB-EXT:*STACK-ALLOCATE-DYNAMIC-EXTENT* is true."
(sb-ext:*stack-allocate-dynamic-extent* variable)
"SBCL recognizes any value which a variable declared DYNAMIC-EXTENT
can take on as having dynamic extent. This means that, in addition
to the value a variable is bound to initially, a value assigned to a
variable by SETQ is also recognized as having dynamic extent when
the variable is declared DYNAMIC-EXTENT. Users can thus build
complex structures on the stack using iteration and SETQ.
At present, SBCL implements stack allocation for the following kinds
of values when they are recognized as having dynamic extent:
- &REST lists;
- the results of CONS, LIST, LIST*, and VECTOR;
- the result of simple forms of MAKE-ARRAY: stack allocation is
possible only if the resulting array is known to be both simple
and one-dimensional, and has a constant :ELEMENT-TYPE;
> __Warning__: Stack space is limited, so allocation of a large
> vector may cause stack overflow. Stack overflow checks are
> done except in 0 @SAFETY policies.
- closures defined with FLET or LABELS with a bound DYNAMIC-EXTENT
declaration;
- anonymous closures defined with LAMBDA;
- user-defined structures when the structure constructor defined using
DEFSTRUCT has been declared INLINE;
> _Note_: Structures with _raw_ slots can currently be
> stack-allocated only on x86 and x86-64. A raw slot is one
> whose declared type is a subtype of exactly one of:
> DOUBLE-FLOAT, SINGLE-FLOAT, `(COMPLEX
> DOUBLE-FLOAT)`, `(COMPLEX SINGLE-FLOAT)`, or SB-EXT:WORD; but
> as an exception to the preceding, any subtype of FIXNUM is not
> stored as raw despite also being a subtype of SB-EXT:WORD.
- otherwise-inaccessible parts of objects recognized to be dynamic
extent. The support for detecting when this applies is very
sophisticated. The compiler can do this detection when any value
form for a variable contains conditional allocations, function
calls, inlined functions, anonymous closures, or even other
variables. This allows stack allocation of complex structures.
Examples:
;;; Declaiming a structure constructor inline before definition makes
;;; stack allocation possible.
(declaim (inline make-thing))
(defstruct thing obj next)
;;; Stack allocation of various objects bound to DYNAMIC-EXTENT
;;; variables.
(let* ((list (list 1 2 3))
(nested (cons (list 1 2) (list* 3 4 (list 5))))
(vector (make-array 3 :element-type 'single-float))
(thing (make-thing :obj list
:next (make-thing :obj (make-array 3))))
(closure (let ((y ...)) (lambda () y))))
(declare (dynamic-extent list nested vector thing closure))
...)
;;; Stack allocation of objects assigned to DYNAMIC-EXTENT variables.
(let ((x nil))
(declare (dynamic-extent x))
(setq x (list 1 2 3))
(dotimes (i 10)
(setq x (cons i x)))
...)
;;; Stack allocation of arguments to a local function is equivalent
;;; to stack allocation of local variable values.
(flet ((f (x)
(declare (dynamic-extent x))
...))
...
(f (list 1 2 3))
(f (cons (cons 1 2) (cons 3 4)))
...)
;;; Stack allocation of &REST lists
(defun foo (&rest args)
(declare (dynamic-extent args))
...)
As a notable exception to recognizing otherwise inaccessible parts
of other recognized dynamic extent values, SBCL does not as of
1.0.48.21 propagate dynamic-extentness through &REST arguments --
but another conforming implementation might, so portable code should
not rely on this.
(declaim (inline foo))
(defun foo (fun &rest arguments)
(declare (dynamic-extent arguments))
(apply fun arguments))
(defun bar (a)
;; SBCL will heap allocate the result of (LIST A), and stack
;; allocate only the spine of the &rest list -- so this is
;; safe but unportable.
;;
;; Another implementation, including earlier versions of SBCL
;; might consider (LIST A) to be otherwise inaccessible and
;; stack-allocate it as well!
(foo #'car (list a)))
If dynamic extent constraints specified in the Common Lisp standard
are violated, the best that can happen is for the program to have
garbage in variables and return values; more commonly, the system
will crash.
In particular, it is important to realize that this can interact in
suprising ways with the otherwise inaccessible parts criterion:
(let* ((a (list 1 2 3))
(b (cons a a)))
(declare (dynamic-extent b))
;; Unless A is accessed elsewhere as well, SBCL will consider
;; it to be otherwise inaccessible -- it can only be accessed
;; through B, after all -- and stack allocate it as well.
;;
;; Hence returning (CAR B) here is unsafe.
...)
SBCL also performs sophisticated escape analysis to enable automatic
stack allocation of local functions without any bound dynamic extent
declarations in many situations where the compiler can prove that no
uses escape (traditional Lisp terminology names this situation \"all
uses are downward funargs\"). For example, in the following
function, the local function `#'PREDICATEP` is stack allocated,
because the compiler understands that the built-in function
POSITION-IF only uses its first argument as a downward funarg:
(let ((acc 0))
(flet ((predicatep (num) (plusp (+ num off))))
(dotimes (i 10)
(incf acc (position-if #'predicatep array)))
(if (plusp off)
(incf acc (if (positivep acc) 10 3))
(incf acc (position-if #'predicatep array))))
acc)
Users can also declare that their own functions take downward
funargs by adding bound dynamic extent declarations on the function
arguments.
(defun trivial-hof (fun arg)
(declare (dynamic-extent fun))
(funcall fun 3 arg))
Currently, such dynamic extent declarations only cause stack
allocation of downward funargs at call sites on sufficiently unsafe
policy. This is partly because the compiler is currently not able to
detect incorrect usage of dynamic extent declarations.
(defun autodxclosure1 (&optional (x 4))
;; Calling a higher-order function will only implicitly
;; stack-allocate a funarg if the callee is trusted (a CL:
;; function) or the caller is unsafe.
(declare (optimize speed (safety 0) (debug 0)))
(trivial-hof (lambda (a b) (+ a b x)) 92))")
(defsection @modular-arithmetic (:title "Modular Arithmetic"
:concepts ("modular arithmetic"
("arithmetic," "modular")
("arithmetic," "hardware")))
"Some numeric functions have a property: n lower bits of the
result depend only on n lower bits of (all or some) arguments. If
the compiler sees an expression of form `(LOGAND <EXPR> <MASK>)`,
where `<EXPR>` is a tree of such _good_ functions and `<MASK>` is
known to be of type `(UNSIGNED-BYTE <W>)`, where `<W>` is a _good_
width, all intermediate results will be cut to `<W>` bits (but it is
not done for variables and constants!). This often results in an
ability to use simple machine instructions for the functions.
Consider this example:
(defun i (x y)
(declare (type (unsigned-byte 32) x y))
(ldb (byte 32 0) (logxor x (lognot y))))
The result of `(LOGNOT Y)` will be negative and of type
`(SIGNED-BYTE 33)`, so a naive implementation on a 32-bit platform
is unable to use 32-bit arithmetic here. But modular arithmetic
optimizer is able to do it: because the result is cut down to 32
bits, the compiler will replace LOGXOR and LOGNOT with versions
cutting results to 32 bits, and because terminals (here, expressions
`X` and `Y`) are also of type `(UNSIGNED-BYTE 32)`, 32-bit machine
arithmetic can be used.
As of SBCL 0.8.5 good functions are `+`, `-`, LOGAND, LOGIOR,
LOGXOR, LOGNOT and their combinations; and ASH with the positive
second argument. Good widths are 32 on 32-bit CPUs and 64 on 64-bit
CPUs. While it is possible to support smaller widths as well,
currently this is not implemented."
(@signed-modular-arithmetic section))
(defsection @signed-modular-arithmetic (:title "Signed Modular Arithmetic")
"Sign-extending the result in the following way will be
translated into signed modular arithmetic:
(defun add (a b)
(declare (type (signed-byte 64) a b))
(let ((u (ldb (byte 64 0) (+ a b))))
(logior u (- (mask-field (byte 1 63) u)))))")
(defsection @recognized-idioms (:title "Recognized Idioms"
:concepts ("modular arithmetic"
("arithmetic," "modular")
("arithmetic," "hardware")))
"Common Lisp doesn't directly expose all features present in
modern hardware. Some code patterns are recognized and turned into
more efficient hardware instructions without requiring the use of
internal features."
(@count-trailing-zeros section))
(defsection @count-trailing-zeros (:title "Count Trailing Zeros")
" (defun ctz (n)
(declare (type (unsigned-byte 64) n))
(integer-length (ldb (byte 64 0) (lognor n (- n)))))
is turned into hardware instructions on arm64 and x86-64. It returns
64 when `N` is 0. `N` can also be `(SIGNED-BYTE 64)` or FIXNUM.")
(defsection @global-and-always-bound-variables
(:title "Global and Always-bound Variables")
(sb-ext:defglobal macro)
(sb-ext:global declaration)
(sb-ext:always-bound declaration))
(defsection @miscellaneous-efficiency-issues
(:title "Miscellaneous Efficiency Issues")
"FIXME: The material in the CMUCL manual about getting good
performance from the compiler should be reviewed, reformatted in
Texinfo, lightly edited for SBCL, and substituted into this
manual. In the meantime, the original CMUCL manual is still 95+%
correct for the SBCL version of the Python compiler. See the
sections
- Advanced Compiler Use and Efficiency Hints
- Advanced Compiler Introduction
- More About Types in Python
- Type Inference
- Source Optimization
- Tail Recursion
- Local Call
- Block Compilation
- Inline Expansion
- Object Representation
- Numbers
- General Efficiency Hints
- Efficiency Notes
Besides this information from the CMUCL manual, there are a few other
points to keep in mind.
- The CMUCL manual doesn't seem to state it explicitly, but Python
has a mental block about type inference when assignment is
involved. Python is very aggressive and clever about inferring the
types of values bound with LET, LET*, inline function call, and so
forth. However, it's much more passive and dumb about inferring
the types of values assigned with SETQ, SETF, and friends. It
would be nice to fix this, but in the meantime don't expect that
just because it's very smart about types in most respects it will
be smart about types involved in assignments. (This doesn't affect
its ability to benefit from explicit type declarations involving
the assigned variables, only its ability to get by without
explicit type declarations.)"
;; FIXME: Python dislikes assignments but not in type inference. The
;; real problems are loop induction, closed over variables and
;; aliases.
"- Since the time the CMUCL manual was written, CMUCL (and thus SBCL)
has gotten a @GENERATIONAL-GC. This means that there are some
efficiency implications of various patterns of memory usage which
aren't discussed in the CMUCL manual. (Some new material should be
written about this.)
- SBCL has some important known efficiency problems. Perhaps the
most important are
- The garbage collector is not particularly efficient, at least
on platforms without the generational collector (as of SBCL
0.8.9, all except x86).
- Various aspects of the PCL implementation of CLOS are more
inefficient than necessary.
Finally, note that Common Lisp defines many constructs which, in the
infamous phrase, \"could be compiled efficiently by a sufficiently
smart compiler\". The phrase is infamous because making a compiler
which actually is sufficiently smart to find all these optimizations
systematically is well beyond the state of the art of current
compiler technology. Instead, they're optimized on a case-by-case
basis by hand-written code, or not optimized at all if the
appropriate case hasn't been hand-coded. Some cases where no such
hand-coding has been done as of SBCL version 0.6.3 include
- `(REDUCE #'F X)` where the type of `X` is known at compile time,
- various bit vector operations, e.g. `(POSITION 0 SOME-BIT-VECTOR)`,
- specialized sequence idioms, e.g. `(REMOVE ITEM LIST :COUNT 1)`,
- cases where local compilation policy does not require excessive
type checking, e.g. `(LOCALLY (DECLARE (SAFETY 1)) (ASSOC ITEM LIST))`
(which currently performs safe ENDP checking internal to ASSOC).
If your system's performance is suffering because of some construct
which could in principle be compiled efficiently, but which the SBCL
compiler can't in practice compile efficiently, consider writing a
patch to the compiler and submitting it for inclusion in the main
sources. Such code is often reasonably straightforward to write;
search the sources for the string `deftransform` to find many
examples (some straightforward, some less so).")

View file

@ -0,0 +1,137 @@
(in-package :sb-manual)
(defsection @external-formats (:title "External Formats"
:concepts (@external-format))
"External formats determine the coding of characters from/to sequences
of octets when exchanging data with the outside world. Examples of
such exchanges are:
- Character streams associated with files, sockets and process
input/output (see @STREAM-EXTERNAL-FORMATS and
@RUNNING-EXTERNAL-PROGRAMS)
- Names of files
- Foreign strings (see @FOREIGN-TYPES-AND-LISP-TYPES)
- Posix interface (see @SB-POSIX)
- Hostname- and protocol-related functions of the BSD-socket interface
(see @NETWORKING)
Technically, external formats in SBCL are named objects describing
coding of characters as well as policies in case de- or encoding is
not possible. Each external format has a canonical name and zero or
more aliases. User code mostly interacts with external formats by
supplying external format designators to functions that use external
formats internally."
(@default-external-format section)
(@external-format-designators section)
(@character-coding-conditions section)
(@converting-between-strings-and-octet-vectors section)
(@supported-external-formats section))
(defsection @default-external-format (:title "The Default External Format")
(sb-ext:*default-external-format* variable)
(sb-ext:*default-source-external-format* variable)
;; FIXME: Move this to @FFI?
(sb-ext:*default-c-string-external-format* variable))
(defsection @external-format-designators (:title "External Format Designators")
"In situations where an external format designator is required, such as
the :EXTERNAL-FORMAT argument in calls to OPEN or WITH-OPEN-FILE,
users may supply the name of an encoding to denote the external
format which is applying that encoding to Lisp characters.
In addition to the basic encoding for an external format, options
controlling various special cases may be passed, by using a list
(whose first element must be an encoding name and whose rest is a
plist) as an external file format designator.
More specifically, external format designators can take the
following forms:
- :DEFAULT: Designates the current default external format (see
@DEFAULT-EXTERNAL-FORMAT).
- `<keyword>`: Designates the supported external format that has
`<keyword>` as one of its names (see @SUPPORTED-EXTERNAL-FORMATS).
- `(<keyword> . <options-plist>)`: Designates an external format
that is like the one designated by `<keyword>` with options as
specified in `<options-plist>`.
Valid options for `<options-plist>` are:
- `:NEWLINE <newline>`
An external format with an explicit :NEWLINE option is like its
`<keyword>` parent but recognizes certain characters or
character sequences as newlines. For :LF (the default), the
`#\\Linefeed` character is treated as `#\\Newline` for both
input and output. For :CR, `#\\Return` is treated as
`#\\Newline`, while for :CRLF the two-character sequence
`#\\Return #\\Linefeed` is translated to and from
`#\\Newline`.
- `:REPLACEMENT <replacement>`
An external format with an explicit :REPLACEMENT option is like
its `<keyword>` parent but does not signal an error in case a
character or octet sequence cannot be en- or decoded. Instead,
it inserts `<replacement>` at the position in question.
`<replacement>` must be a string designator; that is, a
character or a string.
For example:
(with-open-file (stream pathname :external-format '(:utf-8 :replacement #\\?))
(read-line stream))
will read the first line of `\\PATHNAME`, replacing any octet
sequence that is not valid in the UTF-8 external format with a
question mark character.")
(defsection @character-coding-conditions (:title "Character Coding Conditions")
"De- or encoding characters using a given external format is not always
possible:
- Decoding an octet vector using a given external format can fail if
it contains an octet or sequence of octets that does not have an
interpretation as a character according to the external format.
- Conversely, a string may contain characters that a given external
format cannot encode. For example, the ASCII external format
cannot encode the character `#\\ö`.
Unless the external format governing the coding uses the
:REPLACEMENT option, SBCL will signal (continuable) errors under the
above circumstances. The types of the condition signaled are not
currently exported or documented but will be in future SBCL
versions.")
(defsection @converting-between-strings-and-octet-vectors
(:title "Converting between Strings and Octet Vectors")
"To encode Lisp strings as octet vectors and decode octet vectors as
Lisp strings, the following SBCL-specific functions can be used:"
(sb-ext:string-to-octets function)
(sb-ext:octets-to-string function))
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun list-external-formats-in-markdown ()
(flet ((table (items)
(with-output-to-string (s)
(loop for (canonical-name . names) in items
do (format s "- `~S`~%~% ~{`~S`~^, ~}~%~%"
canonical-name names)))))
(let (result)
(loop for ef across sb-impl::*external-formats*
when (sb-impl::external-format-p ef)
do
(pushnew (sb-impl::ef-names ef) result :test #'equal))
(table (sort result #'string< :key #'car))))))
(defsection @supported-external-formats (:title "Supported External Formats")
"The following lists the external formats supported by SBCL in
the form of the respective canonical name followed by the list of aliases:"
#.(list-external-formats-in-markdown))

View file

@ -0,0 +1,780 @@
(in-package :sb-manual)
(defsection @foreign-function-interface
(:title "Foreign Function Interface")
"This chapter describes SBCL's interface to C programs and
libraries (and, since C interfaces are a sort of _lingua franca_
of the Unix world, to other programs and libraries in general).
> _Note_: In the modern Lisp world, the usual term for this
> functionality is Foreign Function Interface, or FFI, where despite
> the mention of _function_ in this term, FFI also refers to direct
> manipulation of C data structures as well as functions. The
> traditional CMUCL terminology is Alien Interface, and while that
> older terminology is no longer used much in the system
> documentation, it still reflected in names in the implementation,
> notably in the name of the `SB-ALIEN` package."
(@introduction-to-the-foreign-function-interface section)
(@foreign-types section)
(@operations-on-foreign-values section)
(@foreign-variables section)
(@foreign-data-structure-examples section)
(@loading-shared-object-files section)
(@foreign-function-calls section)
(@calling-lisp-from-c section)
(@step-by-step-example-of-the-foreign-function-interface section))
(defsection @introduction-to-the-foreign-function-interface
(:title "Introduction to the Foreign Function Interface")
;; AKA Introduction to Aliens in the CMU CL manual
"Because of Lisp's emphasis on dynamic memory allocation and garbage
collection, Lisp implementations use non-C-like memory
representations for objects. This representation mismatch creates
friction when a Lisp program must share objects with programs which
expect C data. There are three common approaches to establishing
communication:
- The burden can be placed on the foreign program (and programmer)
by requiring the knowledge and use of the representations used
internally by the Lisp implementation. This can require a
considerable amount of \"glue\" code on the C side, and that code
tends to be sensitively dependent on the internal implementation
details of the Lisp system.
- The Lisp system can automatically convert objects back and forth
between the Lisp and foreign representations. This is convenient,
but translation becomes prohibitively slow when large or complex
data structures must be shared. This approach is supported by the
SBCL FFI, and used automatically when passing integers and
strings.
- The Lisp program can directly manipulate foreign objects through
the use of extensions to the Lisp language.
SBCL, like CMUCL before it, relies primarily on the automatic
conversion and direct manipulation approaches. The `SB-ALIEN`
package provides a facility wherein foreign values of simple scalar
types are automatically converted and complex types are directly
manipulated in their foreign representation. Additionally the
lower-level System Area Pointers (or SAPs) can be used where
necessary to provide untyped access to foreign memory.
Any foreign objects that can't automatically be converted into Lisp
values are represented by objects of type
SB-ALIEN-INTERNALS:ALIEN-VALUE Since Lisp is a dynamically typed
language, even foreign objects must have a run-time type; this type
information is provided by encapsulating the raw pointer to the
foreign data within an SB-ALIEN-INTERNALS:ALIEN-VALUE object.
The type language and operations on foreign types are intentionally
similar to those of the C language.")
(defsection @foreign-types (:title "Foreign Types")
"Alien types have a description language based on nested list
structure. For example the C type
struct foo {
int a;
struct foo *b[100];
};
has the corresponding SBCL FFI type
(struct foo
(a int)
(b (array (* (struct foo)) 100)))"
(@defining-foreign-types section)
(@foreign-types-and-lisp-types section)
(@foreign-type-specifiers section))
(defsection @defining-foreign-types (:title "Defining Foreign Types")
"Types may be either named or anonymous. With structure and union
types, the name is part of the type specifier, allowing recursively
defined types such as:
(struct foo (a (* (struct foo))))
An anonymous structure or union type is specified by using the name
NIL. The WITH-ALIEN macro defines a local scope which _captures_ any
named type definitions. Other types are not inherently named, but
can be given named abbreviations using the DEFINE-ALIEN-TYPE macro.")
(defsection @foreign-types-and-lisp-types
(:title "Foreign Types and Lisp Types")
"The foreign types form a subsystem of the SBCL type system. An
ALIEN type specifier provides a way to use any foreign type as a
Lisp type specifier. For example,
(typep foo '(alien (* int)))
can be used to determine whether `FOO` is a pointer to a foreign
`int`. ALIEN type specifiers can be used in the same ways as
ordinary Lisp type specifiers (like STRING.) Alien type declarations
are subject to the same precise type checking as any other
declaration. See @PRECISE-TYPE-CHECKING.
Note that the type identifiers used in the foreign type system
overlap with native Lisp type specifiers in some cases. For example,
the type specifier `(ALIEN SINGLE-FLOAT)` is identical to
SINGLE-FLOAT, since foreign floats are automatically converted to
Lisp floats. When TYPE-OF is called on an alien value that is not
automatically converted to a Lisp value, then it will return an
ALIEN type specifier.")
(defsection @foreign-type-specifiers (:title "Foreign Type Specifiers")
"> _Note_: All foreign type names are exported from the `SB-ALIEN`
> package. Some foreign type names are also symbols in the
> `COMMON-LISP` package, in which case they are reexported from the
> `SB-ALIEN` package, so that e.g. it is legal to refer to
> SINGLE-FLOAT.
These are the basic foreign type specifiers:
- The foreign type specifier `(* <FOO>)` describes a pointer to an
object of type `<FOO>`. A pointed-to type `<FOO>` of T indicates a
pointer to anything, similar to `void *` in ANSI C. A null alien
pointer can be detected with the NULL-ALIEN function.
- The foreign type specifier `(ARRAY <FOO> &REST <DIMENSIONS>)`
describes array of the specified `<DIMENSIONS>`, holding elements
of type `<FOO>`. Note that (unlike in C) `(* <FOO>)` and
`(ARRAY <FOO>)` are considered to be different types when
type checking is done. If equivalence of pointer and array types
is desired, it may be explicitly coerced using CAST.
Arrays are accessed using DEREF, passing the indices
as additional arguments. Elements are stored in row-major order
(as in C), so the first dimension determines only the size of the
memory block, and not the layout of the higher dimensions. An array
whose first dimension is variable may be specified by using NIL as
the first dimension. Fixed-size arrays can be allocated as array
elements, structure slots or WITH-ALIEN variables. Dynamic arrays
can only be allocated using MAKE-ALIEN.
- The foreign type specifier `(STRUCT <NAME> &REST <FIELDS>)`
describes a structure type with the specified `<NAME>` and
`<FIELDS>`. Fields are allocated at the same offsets used by the
implementation's C compiler, as guessed by the SBCL internals.
An optional :ALIGNMENT keyword argument can be specified for each
field to explicitly control the alignment of a field. If `<NAME>`
is NIL then the structure is anonymous.
If a named foreign STRUCT specifier is passed to
DEFINE-ALIEN-TYPE or WITH-ALIEN, then this defines,
respectively, a new global or local foreign structure type. If
no `<FIELDS>` are specified, then the fields are taken from the
current (local or global) alien structure type definition of
`<NAME>`.
- The foreign type specifier `(UNION <NAME> &REST <FIELDS>)` is
similar to STRUCT but describes a union type. All fields are
allocated at the same offset, and the size of the union is the
size of the largest field. The programmer must determine which
field is active from context.
- The foreign type specifier `(ENUM <NAME> &REST <SPECS>)` describes
an enumeration type that maps between integer values and symbols.
If `<NAME>` is NIL, then the type is anonymous. Each element of
the `<SPECS>` list is either a Lisp symbol, or a list
`(<symbol> <value>)`. `<value>` is an integer. If `<value>` is not
supplied, then it defaults to one greater than the value for the
preceding spec (or to zero if it is the first spec).
- The foreign type specifier `(SIGNED &OPTIONAL <BITS>)` specifies a
signed integer with the specified number of `<BITS>` precision.
The upper limit on integer precision is determined by the
machine's word size. If `<BITS>` is not specified, the maximum
size will be used.
- The foreign type specifier `(INTEGER &OPTIONAL <BITS>)` is
equivalent to the corresponding type specifier using SIGNED
instead of INTEGER.
- The foreign type specifier `(UNSIGNED &OPTIONAL <BITS>)` is like
corresponding type specifier using SIGNED except that the variable
is treated as an unsigned integer.
- The foreign type specifier `(BOOLEAN &OPTIONAL <BITS>)` is similar
to an enumeration type but maps from Lisp NIL and T to C 0 and 1
respectively. `<BITS>` determines the amount of storage allocated
to hold the truth value.
- The foreign type specifier `\\SINGLE-FLOAT` describes a
floating-point number in IEEE single-precision format.
- The foreign type specifier `\\DOUBLE-FLOAT` describes a
floating-point number in IEEE double-precision format.
- The foreign type specifier `(FUNCTION <RESULT-TYPE> &REST
<ARG-TYPES>)` describes a foreign function that takes arguments of
the specified `<ARG-TYPES>` and returns a result of type
`<RESULT-TYPE>`. Note that the only context where a foreign
`\\FUNCTION` type is directly specified is in the argument to
ALIEN-FUNCALL. In all other contexts, foreign functions are
represented by foreign function pointer types: `(* (FUNCTION
...))`.
- The foreign type specifier `\\SYSTEM-AREA-POINTER` describes a
pointer which is represented in Lisp as a SYSTEM-AREA-POINTER
object. SBCL exports this type from `SB-ALIEN` because CMUCL did,
but tentatively (as of the first draft of this section of the
manual, SBCL 0.7.6) it is deprecated, since it doesn't seem to be
required by user code.
- The foreign type specifier VOID is used in function types to
declare that no useful value is returned. Using ALIEN-FUNCALL to
call a VOID foreign function will return zero values.
- The foreign type specifier `(C-STRING &KEY <EXTERNAL-FORMAT>
<ELEMENT-TYPE> <NOT-NULL>)` is similar to `(* CHAR)` but is
interpreted as a null-terminated string, and is automatically
converted into a Lisp string when accessed; or if the pointer is C
`\\NULL` or 0, then accessing it gives Lisp NIL unless
`<NOT-NULL>` is true, in which case a TYPE-ERROR is signalled.
@EXTERNAL-FORMAT conversion is automatically done when Lisp
strings are passed to foreign code, or when foreign strings are
passed to Lisp code. If the type specifier has an explicit
`<EXTERNAL-FORMAT>`, that external format will be used.
Otherwise SB-EXT:*DEFAULT-C-STRING-EXTERNAL-FORMAT* will be
used. For example, when the following alien routine is called,
the Lisp string given as argument is converted to an \\EBCDIC
octet representation.
(define-alien-routine test int (str (c-string :external-format :ebcdic-us)))
Lisp strings of type BASE-STRING are stored with a trailing
`\\\\NUL` termination, so no copying (either by the user or the
implementation) is necessary when passing them to foreign code,
assuming that the `<EXTERNAL-FORMAT>` and `<ELEMENT-TYPE>` of
the C-STRING type are compatible with the internal
representation of the string. For an SBCL built with Unicode
support that means an `<EXTERNAL-FORMAT>` of :ASCII and an
`<ELEMENT-TYPE>` of BASE-CHAR. Without Unicode support the
`<EXTERNAL-FORMAT>` can also be :ISO-8859-1, and the
`<ELEMENT-TYPE>` can also be [CHARACTER][type]. If
`<EXTERNAL-FORMAT>` and `<ELEMENT-TYPE>` are not compatible, or
the string is a `(SIMPLE-ARRAY CHARACTER (*))`, this data is
copied by the implementation as required.
Assigning a Lisp string to a C-STRING structure field or
variable stores the contents of the string to the memory already
pointed to by that variable. When a foreign object of type
`(* CHAR)` is assigned to a C-STRING, then the C-STRING pointer
is assigned to. This allows C-STRING pointers to be initialized.
For example:
(cl:in-package \"CL-USER\") ; which USEs package \"SB-ALIEN\"
(define-alien-type nil (struct foo (str c-string)))
(defun make-foo (str)
(let ((my-foo (make-alien (struct foo))))
(setf (slot my-foo 'str) (make-alien char (length str))
(slot my-foo 'str) str)
my-foo))
Storing Lisp NIL in a C-STRING writes C `\\\\NULL` to the
variable."
"- `SB-ALIEN` also exports translations of these C type
specifiers as foreign type specifiers:
CHAR, SHORT, INT, LONG, UNSIGNED-CHAR, UNSIGNED-SHORT,
UNSIGNED-INT, UNSIGNED-LONG, FLOAT, DOUBLE, SIZE-T, OFF-T")
(defsection @operations-on-foreign-values
(:title "Operations On Foreign Values")
"This section describes how to read foreign values as Lisp values,
how to coerce foreign values to different kinds of foreign values,
and how to dynamically allocate and free foreign variables."
(@accessing-foreign-values section)
(@coercing-foreign-values section)
(@foreign-dynamic-allocation section))
(defsection @accessing-foreign-values (:title "Accessing Foreign Values")
(sb-alien:deref function)
(sb-alien:slot function)
(@untyped-memory section))
(defsection @untyped-memory (:title "Untyped memory")
"As noted at the beginning of the chapter, the System Area Pointer
facilities allow untyped access to foreign memory. SAPs can be
converted to and from the usual typed foreign values using SAP-ALIEN
and ALIEN-SAP, and also to and from integers (raw machine
addresses). They should thus be used with caution; corrupting the
Lisp heap or other memory with SAPs is trivial."
(sb-sys:int-sap function)
(sb-sys:sap-ref-32 function)
(sb-sys:sap= function)
"Similarly named functions exist for accessing other sizes of word,
other comparisons, and other conversions. The reader is invited to
use APROPOS and DESCRIBE for more details:
(apropos \"sap\" :sb-sys)")
(defsection @coercing-foreign-values (:title "Coercing Foreign Values")
(addr macro)
(cast macro)
(sap-alien macro)
(alien-sap function))
(defsection @foreign-dynamic-allocation (:title "Foreign Dynamic Allocation")
"Lisp code can call the C standard library functions `malloc`
and `free` to dynamically allocate and deallocate foreign variables.
The Lisp code uses the same allocator as foreign C code, so it's
OK for foreign code to call `free` on the result of Lisp MAKE-ALIEN,
or for Lisp code to call FREE-ALIEN on foreign objects allocated by
C code."
(make-alien macro)
(make-alien-string function)
(free-alien function))
(defsection @foreign-variables (:title "Foreign Variables")
"Both local (stack allocated) and external (C global) foreign
variables are supported."
(@local-foreign-variables section)
(@external-foreign-variables section))
(defsection @local-foreign-variables (:title "Local Foreign Variables")
(with-alien macro))
(defsection @external-foreign-variables (:title "External Foreign Variables")
"External foreign names are strings, and Lisp names are symbols. When
an external foreign value is represented using a Lisp variable, there
must be a way to convert from one name syntax into the other. The
macros EXTERN-ALIEN, DEFINE-ALIEN-VARIABLE and
DEFINE-ALIEN-ROUTINE use this conversion heuristic:
- Alien names are converted to Lisp names by uppercasing and
replacing underscores with hyphens.
- Conversely, Lisp names are converted to alien names by lowercasing
and replacing hyphens with underscores.
- Both the Lisp symbol and alien string names may be separately
specified by using a list of the form
(<alien-string> <lisp-symbol>)"
(define-alien-variable macro)
(get-errno function)
(extern-alien macro))
(defsection @foreign-data-structure-examples
(:title "Foreign Data Structure Examples")
"Now that we have alien types, operations and variables, we can
manipulate foreign data structures. This C declaration
struct foo {
int a;
struct foo *b[100];
};
can be translated into the following alien type:
(define-alien-type nil
(struct foo
(a int)
(b (array (* (struct foo)) 100))))
Once the `FOO` alien type has been defined as above, the C
expression
struct foo f;
f.b[7].a;
can be translated in this way:
(with-alien ((f (struct foo)))
(slot (deref (slot f 'b) 7) 'a)
;;
;; Do something with f...
)
Or consider this example of an external C variable and some accesses:
struct c_struct {
short x, y;
char a, b;
int z;
c_struct *n;
};
extern struct c_struct *my_struct;
my_struct->x++;
my_struct->a = 5;
my_struct = my_struct->n;
which can be manipulated in Lisp like this:
(define-alien-type nil
(struct c-struct
(x short)
(y short)
(a char)
(b char)
(z int)
(n (* c-struct))))
(define-alien-variable \"my_struct\" (* c-struct))
(incf (slot my-struct 'x))
(setf (slot my-struct 'a) 5)
(setq my-struct (slot my-struct 'n))")
(defsection @loading-shared-object-files (:title "Loading Shared Object Files")
"Foreign object files can be loaded into the running Lisp process by
calling LOAD-SHARED-OBJECT."
(load-shared-object function)
(unload-shared-object function))
(defsection @foreign-function-calls (:title "Foreign Function Calls")
"The foreign function call interface allows a Lisp program to call
many functions written in languages that use the C calling convention.
Lisp sets up various signal handling routines and other environment
information when it first starts up, and expects these to be in
place at all times. The C functions called by Lisp should not change
the environment, especially the signal handlers: the signal handlers
installed by Lisp typically have interesting flags set (e.g to
request machine context information, or for signal delivery on an
alternate stack) which the Lisp runtime relies on for correct
operation. Precise details of how this works may change without
notice between versions; the source, or the brain of a friendly SBCL
developer, is the only documentation. Users of a Lisp built with the
:SB-THREAD feature should also read the section about threads,
@THREADING."
(alien-funcall function)
(alien-funcall-into function)
(define-alien-routine macro))
;; <!-- FIXME: This is a \"changebar\" section from the CMU CL manual.
;; I (WHN 2002-07-14) am not very familiar with this content, so
;; I'm not immediately prepared to try to update it for SBCL, and
;; I'm not feeling masochistic enough to work to encourage this
;; kind of low-level hack anyway. However, I acknowledge that callbacks
;; are sometimes really really necessary, so I include the original
;; text in case someone is hard-core enough to benefit from it. If
;; anyone brings the information up to date for SBCL, it belong
;; either in the main manual or on a CLiki SBCL Internals page.
;; LaTeX \subsection{Accessing Lisp Arrays}
;; LaTeX
;; LaTeX Due to the way \cmucl{} manages memory, the amount of memory that can
;; LaTeX be dynamically allocated by \code{malloc} or \funref{make-alien} is
;; LaTeX limited\footnote{\cmucl{} mmaps a large piece of memory for it's own
;; LaTeX use and this memory is typically about 8 MB above the start of the C
;; LaTeX heap. Thus, only about 8 MB of memory can be dynamically
;; LaTeX allocated.}.
;;
;; Empirically determined to be considerably >8Mb on this x86 linux
;; machine, but I don't know what the actual values are - dan 2003.09.01
;;
;; Note that this technique is used in SB-GROVEL in the SBCL contrib
;;
;; LaTeX
;; LaTeX To overcome this limitation, it is possible to access the content of
;; LaTeX Lisp arrays which are limited only by the amount of physical memory
;; LaTeX and swap space available. However, this technique is only useful if
;; LaTeX the foreign function takes pointers to memory instead of allocating
;; LaTeX memory for itself. In latter case, you will have to modify the
;; LaTeX foreign functions.
;; LaTeX
;; LaTeX This technique takes advantage of the fact that \cmucl{} has
;; LaTeX specialized array types (\pxlref{specialized-array-types}) that match
;; LaTeX a typical C array. For example, a \code{(simple-array double-float
;; LaTeX (100))} is stored in memory in essentially the same way as the C
;; LaTeX array \code{double x[100]} would be. The following function allows us
;; LaTeX to get the physical address of such a Lisp array:
;; LaTeX \begin{example}
;; LaTeX (defun array-data-address (array)
;; LaTeX \"Return the physical address of where the actual data of an array is
;; LaTeX stored.
;; LaTeX
;; LaTeX ARRAY must be a specialized array type in CMU Lisp. This means ARRAY
;; LaTeX must be an array of one of the following types:
;; LaTeX
;; LaTeX double-float
;; LaTeX single-float
;; LaTeX (unsigned-byte 32)
;; LaTeX (unsigned-byte 16)
;; LaTeX (unsigned-byte 8)
;; LaTeX (signed-byte 32)
;; LaTeX (signed-byte 16)
;; LaTeX (signed-byte 8)
;; LaTeX \"
;; LaTeX (declare (type (or #+signed-array (array (signed-byte 8))
;; LaTeX #+signed-array (array (signed-byte 16))
;; LaTeX #+signed-array (array (signed-byte 32))
;; LaTeX (array (unsigned-byte 8))
;; LaTeX (array (unsigned-byte 16))
;; LaTeX (array (unsigned-byte 32))
;; LaTeX (array single-float)
;; LaTeX (array double-float))
;; LaTeX array)
;; LaTeX (optimize (speed 3) (safety 0))
;; LaTeX (ext:optimize-interface (safety 3)))
;; LaTeX ;; with-array-data will get us to the actual data. However, because
;; LaTeX ;; the array could have been displaced, we need to know where the
;; LaTeX ;; data starts.
;; LaTeX (lisp::with-array-data ((data array)
;; LaTeX (start)
;; LaTeX (end))
;; LaTeX (declare (ignore end))
;; LaTeX ;; DATA is a specialized simple-array. Memory is laid out like this:
;; LaTeX ;;
;; LaTeX ;; byte offset Value
;; LaTeX ;; 0 type code (should be 70 for double-float vector)
;; LaTeX ;; 4 4 * number of elements in vector
;; LaTeX ;; 8 1st element of vector
;; LaTeX ;; ... ...
;; LaTeX ;;
;; LaTeX (let ((addr (+ 8 (logandc1 7 (kernel:get-lisp-obj-address data))))
;; LaTeX (type-size (let ((type (array-element-type data)))
;; LaTeX (cond ((or (equal type '(signed-byte 8))
;; LaTeX (equal type '(unsigned-byte 8)))
;; LaTeX 1)
;; LaTeX ((or (equal type '(signed-byte 16))
;; LaTeX (equal type '(unsigned-byte 16)))
;; LaTeX 2)
;; LaTeX ((or (equal type '(signed-byte 32))
;; LaTeX (equal type '(unsigned-byte 32)))
;; LaTeX 4)
;; LaTeX ((equal type 'single-float)
;; LaTeX 4)
;; LaTeX ((equal type 'double-float)
;; LaTeX 8)
;; LaTeX (t
;; LaTeX (error \"Unknown specialized array element type\"))))))
;; LaTeX (declare (type (unsigned-byte 32) addr)
;; LaTeX (optimize (speed 3) (safety 0) (ext:inhibit-warnings 3)))
;; LaTeX (system:int-sap (the (unsigned-byte 32)
;; LaTeX (+ addr (* type-size start)))))))
;; LaTeX \end{example}
;; LaTeX
;; LaTeX Assume we have the C function below that we wish to use:
;; LaTeX \begin{example}
;; LaTeX double dotprod(double* x, double* y, int n)
;; LaTeX \{
;; LaTeX int k;
;; LaTeX double sum = 0;
;; LaTeX
;; LaTeX for (k = 0; k < n; ++k) \{
;; LaTeX sum += x[k] * y[k];
;; LaTeX \}
;; LaTeX \}
;; LaTeX \end{example}
;; LaTeX The following example generates two large arrays in Lisp, and calls the C
;; LaTeX function to do the desired computation. This would not have been
;; LaTeX possible using \code{malloc} or \code{make-alien} since we need about
;; LaTeX 16 MB of memory to hold the two arrays.
;; LaTeX \begin{example}
;; LaTeX (define-alien-routine \"dotprod\" double
;; LaTeX (x (* double-float) :in)
;; LaTeX (y (* double-float) :in)
;; LaTeX (n int :in))
;; LaTeX
;; LaTeX (let ((x (make-array 1000000 :element-type 'double-float))
;; LaTeX (y (make-array 1000000 :element-type 'double-float)))
;; LaTeX ;; Initialize X and Y somehow
;; LaTeX (let ((x-addr (system:int-sap (array-data-address x)))
;; LaTeX (y-addr (system:int-sap (array-data-address y))))
;; LaTeX (dotprod x-addr y-addr 1000000)))
;; LaTeX \end{example}
;; LaTeX In this example, it may be useful to wrap the inner \code{let}
;; LaTeX expression in an \code{unwind-protect} that first turns off garbage
;; LaTeX collection and then turns garbage collection on afterwards. This will
;; LaTeX prevent garbage collection from moving \code{x} and \code{y} after we
;; LaTeX have obtained the (now erroneous) addresses but before the call to
;; LaTeX \code{dotprod} is made.
;; LaTeX
(defsection @calling-lisp-from-c (:title "Calling Lisp From C")
"SBCL supports the calling of Lisp functions using the C calling
convention. This is useful for both defining callbacks and for creating
an interface for calling into Lisp as a shared library directly from C.
The DEFINE-ALIEN-CALLABLE macro wraps Lisp code and creates a C
foreign function which can be called with the C calling convention.
On x86-64 and ARM64, callbacks may receive and return structures by
value."
(define-alien-callable macro)
"The ALIEN-CALLABLE-FUNCTION function returns the foreign callable
value associated with any name defined by DEFINE-ALIEN-CALLABLE, so
that we can, for example, pass the callable value to C as a
callback."
(alien-callable-function function)
"The WITH-ALIEN-CALLABLE macro wraps Lisp code and establishes
local C foreign functions which can be called with the C calling
convention. This macro is handy for passing callbacks which close over
Lisp values into C."
(with-alien-callable macro)
"Note that the garbage collector moves objects, and won't be able to fix
up any references in C variables. There are three mechanisms for
coping with this:
- SB-EXT:PURIFY moves all live Lisp data into static or read-only
areas such that it will never be moved (or freed) again in the
life of the Lisp session
- SB-SYS:WITH-PINNED-OBJECTS is a macro which arranges for some set
of objects to be pinned in memory for the dynamic extent of its
body forms. On ports which use the @GENERATIONAL-GC
(most, as of this writing) this affects exactly the specified
objects. On other ports it is implemented by turning off GC for
the duration (so could be said to have a whole-world granularity).
- Disable GC, using the SB-EXT:WITHOUT-GCING macro."
(@lisp-as-a-shared-library section))
(defsection @lisp-as-a-shared-library (:title "Lisp as a Shared Library")
"SBCL supports the use of Lisp as a shared library that can be used by
C programs using the DEFINE-ALIEN-CALLABLE interface. See the
:CALLABLE-EXPORTS argument of SB-EXT:SAVE-LISP-AND-DIE for how to
save the Lisp image in a way that allows a C program to initialize
the Lisp runtime and the exported symbols. When SBCL is built as a
library, it exposes the symbol `initialize_lisp` which can be used
in conjunction with a core initializing global symbols to foreign
callables as function pointers and with object code allocating those
symbols to initialize the runtime properly. The arguments to
`initialize_lisp` are the same as the arguments to the main `sbcl`
program.
> _Note_: There is currently no way to run exit hooks or otherwise
> undo Lisp initialization gracefully from C.")
(defsection @step-by-step-example-of-the-foreign-function-interface
(:title "Step-By-Step Example of the Foreign Function Interface")
"This section presents a complete example of an interface to a somewhat
complicated C function.
Suppose you have the following C function which you want to be able
to call from Lisp in the file `test.c`:
struct c_struct
{
int x;
char *s;
};
struct c_struct *c_function (i, s, r, a)
int i;
char *s;
struct c_struct *r;
int a[10];
{
int j;
struct c_struct *r2;
printf(\"i = %d\n\", i);
printf(\"s = %s\n\", s);
printf(\"r->x = %d\n\", r->x);
printf(\"r->s = %s\n\", r->s);
for (j = 0; j < 10; j++) printf(\"a[%d] = %d.\n\", j, a[j]);
r2 = (struct c_struct *) malloc (sizeof(struct c_struct));
r2->x = i + 5;
r2->s = \"a C string\";
return(r2);
};
It is possible to call this C function from Lisp using the file
`test.lisp` containing
(cl:defpackage \"TEST-C-CALL\" (:use \"CL\" \"SB-ALIEN\" \"SB-C-CALL\"))
(cl:in-package \"TEST-C-CALL\")
;;; Define the record C-STRUCT in Lisp.
(define-alien-type nil
(struct c-struct
(x int)
(s c-string)))
;;; Define the Lisp function interface to the C routine. It returns a
;;; pointer to a record of type C-STRUCT. It accepts four parameters:
;;; I, an int; S, a pointer to a string; R, a pointer to a C-STRUCT
;;; record; and A, a pointer to the array of 10 ints.
;;;
;;; The INLINE declaration eliminates some efficiency notes about heap
;;; allocation of alien values.
(declaim (inline c-function))
(define-alien-routine c-function
(* (struct c-struct))
(i int)
(s c-string)
(r (* (struct c-struct)))
(a (array int 10)))
;;; a function which sets up the parameters to the C function and
;;; actually calls it
(defun call-cfun ()
(with-alien ((ar (array int 10))
(c-struct (struct c-struct)))
(dotimes (i 10) ; Fill array.
(setf (deref ar i) i))
(setf (slot c-struct 'x) 20)
(setf (slot c-struct 's) \"a Lisp string\")
(with-alien ((res (* (struct c-struct))
(c-function 5 \"another Lisp string\" (addr c-struct) ar)))
(format t \"~&back from C function~%\")
(multiple-value-prog1
(values (slot res 'x)
(slot res 's))
;; Deallocate result. (after we are done referring to it:
;; \"Pillage, *then* burn.\")
(free-alien res)))))
To execute the above example, it is necessary to compile the C
routine, e.g. with `cc -c test.c && ld -shared -o test.so test.o`.
In order to enable incremental loading with some linkers, you may
need to say `cc -G 0 -c test.c`.
Once the C code has been compiled, you can start up Lisp and load it
in: `sbcl`. Lisp should start up with its normal prompt.
Within Lisp, compile the Lisp file:
(compile-file \"test.lisp\")
This step can be done separately. You don't have to recompile every
time.
Within Lisp, load the foreign object file to define the necessary
symbols:
(load-shared-object \"test.so\")
Now you can load the compiled Lisp (fasl) file into Lisp:
(load \"test.fasl\")
And once the Lisp file is loaded, you can call the Lisp routine
that sets up the parameters and calls the C function:
(test-c-call::call-cfun)
The C routine should print the following information to standard output:
i = 5
s = another Lisp string
r->x = 20
r->s = a Lisp string
a[0] = 0.
a[1] = 1.
a[2] = 2.
a[3] = 3.
a[4] = 4.
a[5] = 5.
a[6] = 6.
a[7] = 7.
a[8] = 8.
a[9] = 9.
After return from the C function,
the Lisp wrapper function should print the following output:
back from C function
And upon return from the Lisp wrapper function,
before the next prompt is printed, the
Lisp read-eval-print loop should print the following return values:
10
\"a C string\"")

View file

@ -0,0 +1,502 @@
(in-package :sb-manual)
(defsection @introduction (:title "Introduction")
"SBCL is a mostly-conforming implementation of the ANSI Common Lisp
standard. This manual focuses on behavior which is specific to SBCL,
not on behavior which is common to all implementations of ANSI Common
Lisp."
(@ansi-conformance section)
(@extensions section)
(@idiosyncrasies section)
(@development-tools section)
(@more-sbcl-information section)
(@more-common-lisp-information section)
(@history-and-implementation-of-sbcl section))
(defsection @ansi-conformance (:title "ANSI Conformance")
"Essentially every type of non-conformance is considered a bug. (The
exceptions involve internal inconsistencies in the standard.) See
@REPORTING-BUGS.
- PROG2 returns the primary value of its second form, as
specified in the _Arguments and Values_ section of the
specification for that operator, not that of its first form, as
specified in the _Description_.
- The STRING type is considered to be the union of all types
`(ARRAY C (SIZE))` for all non-`NIL` subtypes `C` of
[CHARACTER][type], excluding arrays specialized to the empty
type.
- The `:ORDER` long form option in DEFINE-METHOD-COMBINATION method
group specifiers accepts the value NIL as well as
:MOST-SPECIFIC-FIRST and :MOST-SPECIFIC-LAST, in order to allow
programmers to declare that the order of methods playing that role
in the method combination does not matter.")
;;; FIXME: Document SERVE-EVENT?
(defsection @extensions (:title "Extensions")
"SBCL comes with numerous extensions, some in core and some in modules
loadable with REQUIRE. Unfortunately, not all of these extensions
have proper documentation yet.
- __System Definition Tool:__ ASDF is a flexible and popular
protocol-oriented system definition tool by Daniel Barlow.
- __Foreign Function Interface:__ The `SB-ALIEN` package allows
interfacing with C-code, loading shared object files, etc. See
@FOREIGN-FUNCTION-INTERFACE.
@SB-GROVEL can be used to partially automate generation of
foreign function interface definitions.
- __Recursive Event Loop:__ SBCL provides a recursive event
loop (`SERVE-EVENT`) for doing non-blocking IO on multiple streams
without using threads.
- __Timeouts and Deadlines:__ SBCL allows restricting the execution
time of individual operations or parts of a computation using
:TIMEOUT arguments to certain blocking operations, synchronous
timeouts and asynchronous timeouts. The latter two affect operations
without explicit timeout support (such as standard functions and
macros). See @TIMEOUTS-AND-DEADLINES.
- __Metaobject Protocol:__ The `SB-MOP` package provides an
implementation of the metaobject protocol for the Common Lisp
Object System as described in _The Art of the Metaobject Protocol_
by Kiczales et al.
- __Extensible Sequences:__ SBCL allows users to define subclasses
of the SEQUENCE class. See @EXTENSIBLE-SEQUENCES.
- __Native Threads:__ SBCL has native threads on numerous platforms,
capable of taking advantage of SMP on multiprocessor machines. See
@THREADING.
- __Network Interface:__ The `SB-BSD-SOCKETS` module is a low-level
networking interface, providing both TCP and UDP sockets. See
@NETWORKING.
- __Introspective Facilities:__ The @SB-INTROSPECT module offers
numerous introspective extensions, including access to function
lambda-lists and a cross referencing facility.
- __Operating System Interface:__ The `SB-EXT` package contains a
number of functions for running external processes, accessing
environment variables, etc.
The @SB-POSIX module provides a lispy interface to standard
POSIX facilities.
- __Extensible Streams:__ The package `SB-GRAY` provides an
implementation of @GRAY-STREAMS.
The @SB-SIMPLE-STREAMS module is an implementation of the Simple
Streams API proposed by Franz Inc.
- __Profiling:__ The `SB-PROFILE` package provides an exact,
per-function @DETERMINISTIC-PROFILER.
The `SB-SPROF` module is SBCL's @STATISTICAL-PROFILER, capable
of call-graph generation and instruction level profiling, which
also supports allocation profiling.
- __Customization Hooks:__ SBCL contains a number of extra-standard
customization hooks that can be used to tweak the behaviour of the
system. See @CUSTOMIZATION-HOOKS-FOR-USERS.
- __sb-aclrepl:__ The @SB-ACLREPL module provides an Allegro-style
toplevel for SBCL, as an alternative to the classic CMUCL-style
one.
- __CLTL2 Compatibility Layer:__ The SB-CLTL2 module provides
SB-CLTL2:COMPILER-LET and environment access functionality
described in _Common Lisp The Language, 2nd Edition_ which were
removed from the language during the ANSI standardization process.
- __Executable Delivery:__ The :EXECUTABLE argument to
SB-EXT:SAVE-LISP-AND-DIE can produce a \"standalone\" executable
containing both an image of the current Lisp session and an SBCL
runtime.
- __Bitwise Rotation:__ The @SB-ROTATE-BYTE module provides an
efficient primitive for bitwise rotation of integers, an operation
required by e.g. numerous cryptographic algorithms but not
available as a primitive in ANSI Common Lisp.
- __Test Harness:__ The `SB-RT` module is a simple yet attractive
regression and unit-test framework.
- __MD5 Sums:__ The @SB-MD5 module provides an implementation of the
MD5 message digest algorithm for Common Lisp, using the
@MODULAR-ARITHMETIC optimizations provided by SBCL.")
(defsection @idiosyncrasies (:title "Idiosyncrasies")
"The information in this section describes some of the ways that SBCL
deals with choices that the ANSI standard leaves to the
implementation."
(@declarations section)
(@fasl-format section)
(@compiler-only-implementation section)
(@defining-constants section)
(@style-warnings section))
(defsection @declarations (:title "Declarations")
"Declarations are generally treated as assertions. This general
principle, and its implications, and the bugs which still keep the
compiler from quite satisfying this principle, are discussed in
@DECLARATIONS-AS-ASSERTIONS.")
(defsection @fasl-format (:title "FASL format")
"SBCL fasl-format is binary compatible only with the exact SBCL version
it was generated with. While this is obviously suboptimal, it has
proven more robust than trying to maintain fasl compatibility across
versions: accidentally breaking things is far too easy, and can lead
to hard to diagnose bugs.
The following snippet handles fasl recompilation automatically for
ASDF-based systems, and makes a good candidate for inclusion in the
user or system initialization file (see @INITIALIZATION-FILES).
(require :asdf)
;;; If a fasl was stale, try to recompile and load (once).
(defmethod asdf:perform :around ((o asdf:load-op)
(c asdf:cl-source-file))
(handler-case (call-next-method o c)
;; If a fasl was stale, try to recompile and load (once).
(sb-ext:invalid-fasl ()
(asdf:perform (make-instance 'asdf:compile-op) c)
(call-next-method))))")
(defsection @compiler-only-implementation
(:title "Compiler-only Implementation")
"SBCL is essentially a compiler-only implementation of Common Lisp.
That is, for all but a few special cases, EVAL creates a lambda
expression, calls COMPILE on the lambda expression to create a
compiled function, and then calls FUNCALL on the resulting function
object. A more traditional interpreter is also available on default
builds; it is usually only called internally. This is explicitly
allowed by the ANSI standard but leads to some oddities; e.g. at
default settings, FUNCTIONP and COMPILED-FUNCTION-P are equivalent,
and they collapse into the same function when SBCL is built without
the interpreter.")
(defsection @defining-constants (:title "Defining Constants")
"SBCL is quite strict about ANSI's definition of DEFCONSTANT.
ANSI says that doing DEFCONSTANT of the same symbol more than once
is undefined unless the new value is EQL to the old value.
Conforming to this specification is a nuisance when the \"constant\"
value is only constant under some weaker test like STRING= or EQUAL.
It's especially annoying because, in SBCL, DEFCONSTANT takes effect
not only at load time but also at compile time, so that just
compiling and loading reasonable code like
(defconstant +foobyte+ '(1 4))
runs into this undefined behavior. Many implementations of Common
Lisp try to help the programmer around this annoyance by silently
accepting the undefined code and trying to do what the programmer
probably meant.
SBCL instead treats the undefined behavior as an error. Often such
code can be rewritten in portable ANSI Common Lisp which has the
desired behavior. E.g., the code above can be given an exactly
defined meaning by replacing DEFCONSTANT either with DEFPARAMETER or
with a customized macro which does the right thing, e.g.
(defmacro define-constant (name value &optional doc)
`(defconstant ,name (if (boundp ',name) (symbol-value ',name) ,value)
,@(when doc (list doc))))
or possibly along the lines of the SB-INT:DEFCONSTANT-EQX macro used
internally in the implementation of SBCL itself. In circumstances
where this is not appropriate, the programmer can handle the
condition type SB-EXT:DEFCONSTANT-UNEQL and choose either the
CONTINUE restart or ABORT restart as appropriate.")
(defsection @style-warnings (:title "Style Warnings")
"SBCL gives style warnings about various kinds of perfectly legal code,
e.g.
- multiple DEFUNs of the same symbol in different units;
- special variables not named in the conventional `*foo*` style, and
lexical variables unconventionally named in the `*FOO*` style.
This causes friction with people who point out that other ways of
organizing code (especially avoiding the use of DEFGENERIC) are just
as aesthetically stylish. However, these warnings should be read not
as _warning, bad aesthetics detected, you have no style_ but as
_warning, this style keeps the compiler from understanding the code
as well as you might like_. That is, unless the compiler warns about
such conditions, there's no way for the compiler to warn about some
programming errors which would otherwise be easy to
overlook. (Related bug: The warning about multiple DEFUNs is
pointlessly annoying when you compile and then load a function
containing DEFUN wrapped in EVAL-WHEN, and ideally should be
suppressed in that case, but still isn't as of SBCL 0.7.6.)")
(defsection @development-tools (:title "Development Tools")
(@editor-integration section)
(@language-reference section)
(@generating-executables section))
(defsection @editor-integration (:title "Editor Integration")
"Though SBCL can be used running \"bare\", the recommended mode of
development is with an editor connected to SBCL, supporting not
only basic lisp editing (paren-matching, etc), but providing among
other features an integrated debugger, interactive compilation, and
automated documentation lookup.
Currently _SLIME_ (Superior Lisp Interaction Mode for Emacs)
together with Emacs is recommended for use with SBCL, though other
options exist as well. Historically, the ILISP package at
<http://ilisp.cons.org/> provided similar functionality, but it does
not support modern SBCL versions.
SLIME can be downloaded from <https://slime.common-lisp.dev/>.")
(defsection @language-reference (:title "Language Reference")
"_\\CLHS_ (Common Lisp HyperSpec) is a hypertext version of the ANSI
standard, made freely available by LispWorks -- an invaluable
reference.
See <https://www.lispworks.com/documentation/HyperSpec/Front/index.htm>.")
(defsection @generating-executables (:title "Generating Executables")
"SBCL can generate stand-alone executables. The generated executables
include the SBCL runtime itself, so no restrictions are placed on
program functionality. For example, a deployed program can call
COMPILE and LOAD, which requires the compiler to be present in the
executable. For further information, SB-EXT:SAVE-LISP-AND-DIE.")
(defsection @more-sbcl-information (:title "More SBCL Information")
(@sbcl-homepage section)
(@online-documentation section)
(@additional-documentation-files section)
(@internals-documentation section))
(defsection @sbcl-homepage (:title "SBCL Homepage")
"The SBCL website at <http://www.sbcl.org/> has some general
information, plus links to mailing lists devoted to SBCL, and to
archives of these mailing lists. Subscribing to the mailing lists
`sbcl-help` and `sbcl-announce` is recommended: both are fairly
low-volume, and help you keep abreast with SBCL development.")
(defsection @online-documentation (:title "Online Documentation")
"Documentation for non-ANSI extensions for various commands is
available online from the SBCL executable itself. The extensions for
functions which have their own command prompts (e.g. the debugger,
and INSPECT) are documented in text available by typing `help` at
their command prompts. The extensions for functions which don't have
their own command prompt (such as TRACE) are described in their
documentation strings, unless your SBCL was compiled with an option
not to include documentation strings, in which case the
documentation strings are only readable in the source code.")
(defsection @additional-documentation-files
(:title "Additional Documentation Files")
"Besides this user manual both SBCL source and binary distributions
include some other SBCL-specific documentation files, which should
be installed along with this manual on your system, e.g. in
`/usr/local/share/doc/sbcl/`.
- `COPYING`: Licence and copyright summary.
- `CREDITS`: Authorship information on various parts of SBCL.
- `INSTALL`: Covers installing SBCL from both source and binary
distributions on your system, and also has some installation
related troubleshooting information.
- `NEWS`: Summarizes changes between various SBCL versions.")
(defsection @internals-documentation (:title "Internals Documentation")
"If you're interested in the development of the SBCL system itself,
then subscribing to
[sbcl-devel@lists.sourceforge.net](mailto:sbcl-devel@lists.sourceforge.net)
is a good idea.
SBCL internals documentation -- besides comments in the source -- is
available in the Web Archive:
<https://web.archive.org/web/20120814000933/http://sbcl-internals.cliki.net/index>.
Some low-level information describing the programming details of the
conversion from CMUCL to SBCL is available in the
`doc/FOR-CMUCL-DEVELOPERS` file.")
(defsection @more-common-lisp-information
(:title "More Common Lisp Information")
(@internet-community section)
(@third-party-libraries section)
(@common-lisp-books section))
(defsection @internet-community (:title "Internet Community")
"IRC channels on <https://libera.chat/>:
- `#common-lisp`: \"Common Lisp, the #1=(programmable . #1#)
programming language\"
- `#lispcafe`: \"The Lisp Café; sit down, have a drink, chat about
anything, and enjoy your stay. | <https://www.cliki.net/lispcafe> |
Be insuperable to each other\".
- `#sbcl`: \"Steel Bank Common Lisp Dev Hangout\"
You can use <https://web.libera.chat> or a normal IRC client.
Also, see <https://www.reddit.com/r/Common_Lisp/>, as well as
<https://www.lisp.org> and <https://cliki.net>, which contain
numerous pointers places in the net where lispers talks shop.")
(defsection @third-party-libraries (:title "Third-party Libraries")
"For a wealth of information about free Common Lisp libraries and tools
we recommend checking out _CLiki_: <https://cliki.net/>.
The most popular library manager is Quicklisp:
<https://www.quicklisp.org/beta/>.")
(defsection @common-lisp-books (:title "Common Lisp Books")
"If you're not a programmer and you're trying to learn, many
introductory Lisp books are available. However, we don't have any
standout favorites.
If you are an experienced programmer in other languages but need to
learn about Common Lisp, some books stand out:
- Practical Common Lisp, by Peter Seibel
An excellent introduction to the language, covering both the
basics and \"advanced topics\" like macros, CLOS, and packages.
Available both in print format and on the web:
<https://gigamonkeys.com/book/>.
- Paradigms Of Artificial Intelligence Programming, by Peter Norvig
Good information on general Common Lisp programming, and many
nontrivial examples. Whether or not your work is AI, it's a very
good book to look at.
- On Lisp, by Paul Graham
An in-depth treatment of macros, but not recommended as a first
Common Lisp book, since it is slightly pre-ANSI so you need to
be on your guard against non-standard usages, and since it
doesn't really even try to cover the language as a whole,
focusing solely on macros. Downloadable from
<https://www.paulgraham.com/onlisp.html>.
- Object-Oriented Programming In Common Lisp, by Sonya Keene
With the exception of _Practical Common Lisp_, most introductory
books don't emphasize CLOS. This one does. Even if you're very
knowledgeable about object oriented programming in the abstract,
it's worth looking at this book if you want to do any OO in
Common Lisp. Some abstractions in CLOS (especially multiple
dispatch) go beyond anything you'll see in most OO systems, and
there are a number of lesser differences as well. This book
tends to help with the culture shock.
- Art Of Metaobject Programming, by Gregor Kiczales et al.
Currently the prime source of information on the Common Lisp
Metaobject Protocol, which is supported by SBCL. Section
2 (Chapters 5 and 6) are freely available at
<http://mop.lisp.se/www.alu.org/mop/>.")
(defsection @history-and-implementation-of-sbcl
(:title "History and Implementation of SBCL")
"You can work productively with SBCL without knowing or understanding
anything about where it came from, how it is implemented, or how it
extends the ANSI Common Lisp standard. However, a little knowledge
can be helpful in order to understand error messages, to
troubleshoot problems, to understand why some parts of the system
are better debugged than others, and to anticipate which known bugs,
known performance problems, and missing extensions are likely to be
fixed, tuned, or added.
SBCL is descended from CMUCL, which is itself descended from Spice
Lisp, including early implementations for the Mach operating system on
the IBM RT, back in the 1980s. Some design decisions from that time are
still reflected in the current implementation:
- The system expects to be loaded into a fixed-at-compile-time
location in virtual memory, and also expects the location of all
of its heap storage to be specified at compile time.
- The system overcommits memory, allocating large amounts of address
space from the system (often more than the amount of virtual
memory available) and then failing if it ends up using too much of
the allocated storage.
- The system is implemented as a C program which is responsible for
supplying low-level services and loading a Lisp `.core` file.
SBCL also inherited some newer architectural features from CMUCL.
The most important is that on some architectures it has a
@GENERATIONAL-GC, which has various implications (mostly good) for
performance. These are discussed in another chapter, @EFFICIENCY.
SBCL has diverged from CMUCL in that SBCL is now essentially a
compiler-only implementation of Common Lisp. This is a change in
implementation strategy, taking advantage of the freedom \"any of
these facilities might share the same execution strategy\"
guaranteed in CLHS `3.1` (Evaluation). It does not mean SBCL can't
be used interactively, and in fact the change is largely invisible
to the casual user, since SBCL still can and does execute code
interactively by compiling it on the fly. (It is visible if you know
how to look, like using COMPILED-FUNCTION-P; and it is visible in
the way that SBCL doesn't have many bugs which behave differently in
interpreted code than in compiled code.) What it means is that in
SBCL, the EVAL function only truly \"interprets\" a few easy kinds
of forms, such as symbols which are BOUNDP. More complicated forms
are evaluated by calling COMPILE and then calling FUNCALL on the
returned result.
The direct ancestor of SBCL is the x86 port of CMUCL. This port was in
some ways the most cobbled-together of all the CMUCL ports, since a
number of strange changes had to be made to support the register-poor
x86 architecture. Some things (like tracing and debugging) do not work
particularly well there. SBCL should be able to improve in these areas
(and has already improved in some other areas), but it takes a while.
On the x86 SBCL -- like the x86 port of CMUCL -- uses a
_@CONSERVATIVE-GC_. This means that it doesn't maintain a strict
separation between tagged and untagged data, instead treating some
untagged data (e.g. raw floating point numbers) as possibly-tagged
data and so not collecting any Lisp objects that they point to. This
has some negative consequences for average time efficiency (though
possibly no worse than the negative consequences of trying to
implement an exact GC on a processor architecture as register-poor
as the X86) and also has potentially unlimited consequences for
worst-case memory efficiency. In practice, @CONSERVATIVE-GCs work
reasonably well, not getting anywhere near the worst case. But they
can occasionally cause odd patterns of memory usage.
The fork from CMUCL was based on a major rewrite of the system
bootstrap process. CMUCL has for many years tolerated a very unusual
\"build\" procedure which doesn't actually build the complete system
from scratch, but instead progressively overwrites parts of a
running system with new versions. This quasi-build procedure can
cause various bizarre bootstrapping hangups, especially when a major
change is made to the system. It also makes the connection between
the current source code and the current executable more tenuous than
in other software systems -- it's easy to accidentally build a CMUCL
system containing characteristics not reflected in the current
version of the source code.
Other major changes since the fork from CMUCL include:
- SBCL has removed many CMUCL extensions, (e.g. IP networking,
remote procedure call, Unix system interface, and X11 interface)
from the core system. Most of these are available as contributed
modules (distributed with SBCL) or third-party modules instead.
- SBCL has deleted or deprecated some nonstandard features and code
complexity which helped efficiency at the price of
maintainability. For example, the SBCL compiler no longer
implements memory pooling internally (and so is simpler and more
maintainable, but generates more garbage and runs more slowly).")

View file

@ -0,0 +1,261 @@
(in-package :sb-manual)
(defsection @package-locks (:title "Package Locks"
:concepts (("package" "lock")
("lock," "package")))
"None of the following sections apply to SBCL built without package
locking support.
The interface described here is experimental: incompatible changes
in future SBCL releases are possible, even expected: the concept of
_implementation packages_ and the associated operators may be
renamed; more operations (such as naming restarts or catch tags) may
be added to the list of operations violating package locks."
(@package-lock-concepts section)
(@package-lock-dictionary section))
(defsection @package-lock-concepts (:title "Package Lock Concepts")
"Package locks protect against unintentional modifications of a package:
they provide similar protection to user packages as is mandated to
`COMMON-LISP` package by the ANSI specification. They are not, and
should not be used as, a security measure.
Newly created packages are by default unlocked (see the :LOCK option
to DEFPACKAGE).
The package `COMMON-LISP` and SBCL internal implementation packages
are locked by default, including `SB-EXT`.
It may be beneficial to lock `COMMON-LISP-USER` as well, to ensure
that various libraries don't pollute it without asking, but this is
not currently done by default."
(@implementation-packages section)
(@package-lock-violations section)
(@package-locks-in-compiled-code section)
(@operations-violating-package-locks section))
(defsection @implementation-packages (:title "Implementation Packages")
"Each package has a list of associated implementation packages. A
locked package, and the symbols whose home package it is, can be
modified without violating package locks only when *PACKAGE* is
bound to one of the implementation packages of the locked package.
Unless explicitly altered by DEFPACKAGE,
SB-EXT:ADD-IMPLEMENTATION-PACKAGE, or
SB-EXT:REMOVE-IMPLEMENTATION-PACKAGE, each package is its own
(only) implementation package.")
(defsection @package-lock-violations (:title "Package Lock Violations")
(@lexical-bindings-and-declarations section)
(@other-operations section))
(defsection @lexical-bindings-and-declarations
(:title "Lexical Bindings and Declarations")
"Lexical bindings or @DECLARATIONs that violate package locks cause a
compile-time warning, and a runtime PROGRAM-ERROR when the form that
violates package locks would be executed.
A complete listing of operators affected by this is: LET, LET*,
FLET, LABELS, MACROLET, SYMBOL-MACROLET, DECLARE.
Package locks affecting both lexical bindings and declarations can
be disabled locally with the SB-EXT:DISABLE-PACKAGE-LOCKS
declaration, and re-enabled with the SB-EXT:ENABLE-PACKAGE-LOCKS
declaration.
Example:
(in-package :locked)
(defun foo () ...)
(defmacro with-foo (&body body)
`(locally (declare (disable-package-locks locked:foo))
(flet ((foo () ...))
(declare (enable-package-locks locked:foo)) ; re-enable for body
,@body)))")
(defsection @other-operations (:title "Other Operations")
"If a non-lexical operation violates a package lock, a continuable
error that is of a subtype of SB-EXT:PACKAGE-LOCK-VIOLATION
(subtype of PACKAGE-ERROR) is signalled when the operation is
attempted.
Additional restarts may be established for continuable package lock
violations for interactive use.
The actual type of the error depends on circumstances that caused
the violation: operations on packages signal errors of type
SB-EXT:PACKAGE-LOCKED-ERROR, and operations on symbols signal errors
of type SB-EXT:SYMBOL-PACKAGE-LOCKED-ERROR.")
(defsection @package-locks-in-compiled-code
(:title "Package Locks in Compiled Code")
"If file-compiled code contains interned symbols, then loading that
code into an image without the said symbols will not cause a package
lock violation, even if the packages in question are locked.
With the exception of interned symbols, behaviour is unspecified if
package locks affecting compiled code are not the same during
loading of the code or execution.
Specifically, code compiled with packages unlocked may or may not
fail to signal package-lock-violations even if the packages are
locked at runtime, and code compiled with packages locked may or may
not signal spurious package-lock-violations at runtime even if the
packages are unlocked.
In practice all this means that package-locks have a negligible
performance penalty in compiled code as long as they are not
violated.")
(defsection @operations-violating-package-locks
(:title "Operations Violating Package Locks")
(@operations-on-packages section)
(@operations-on-symbols section))
(defsection @operations-on-packages (:title "Operations on Packages")
"The following actions cause a package lock violation if the package
operated on is locked, and *PACKAGE* is not an implementation
package of that package, and the action would cause a change in the
state of the package (so e.g. exporting already external symbols is
never a violation). Package lock violations caused by these
operations signal errors of type SB-EXT:PACKAGE-LOCKED-ERROR.
- Shadowing a symbol in a package.
- Importing a symbol to a package.
- Uninterning a symbol from a package.
- Exporting a symbol from a package.
- Unexporting a symbol from a package.
- Changing the packages used by a package.
- Renaming a package.
- Deleting a package.
- Adding a new package local nickname to a package.
- Removing an existing package local nickname from a package.")
(defsection @operations-on-symbols (:title "Operations on Symbols")
"Following actions cause a package lock violation if the home package
of the symbol operated on is locked, and *PACKAGE* is not an
implementation package of that package. Package lock violations
caused by these action signal errors of type
SB-EXT:SYMBOL-PACKAGE-LOCKED-ERROR.
These actions cause only one package lock violation per lexically
apparent violated package.
Example:
;;; Packages FOO and BAR are locked.
;;;
;;; Two lexically apparent violated packages: exactly two
;;; package-locked-errors will be signalled.
(defclass foo:point ()
((x :accessor bar:x)
(y :accessor bar:y)))
- Binding or altering its value lexically or dynamically, or
establishing it as a symbol-macro.
Exceptions:
- If the symbol is not defined as a constant, global
symbol-macro or a global dynamic variable, it may be lexically
bound or established as a local symbol macro.
- If the symbol is defined as a global dynamic variable, it may
be assigned or bound.
- Defining, undefining, or binding it, or its setf name as a
function.
Exceptions:
- If the symbol is not defined as a function, macro, or special
operator it and its setf name may be lexically bound as a
function.
- Defining, undefining, or binding it as a macro or compiler macro.
Exceptions:
- If the symbol is not defined as a function, macro, or special
operator it may be lexically bound as a macro.
- Defining it as a type specifier or structure.
- Defining it as a declaration with a declaration proclamation.
- Declaring or proclaiming it special.
- Declaring or proclaiming its type or ftype.
Exceptions:
- If the symbol may be lexically bound, the type of that binding
may be declared.
- If the symbol may be lexically bound as a function, the ftype
of that binding may be declared.
- Defining a setf expander for it.
- Defining it as a method combination type.
- Using it as the CLASS-NAME argument to (SETF FIND-CLASS).
- Defining it as a hash table test using SB-EXT:DEFINE-HASH-TABLE-TEST.")
(defsection @package-lock-dictionary (:title "Package Lock Dictionary")
(sb-ext:disable-package-locks declaration)
(sb-ext:enable-package-locks declaration)
(sb-ext:package-lock-violation condition)
(sb-ext:package-locked-error condition)
(sb-ext:symbol-package-locked-error condition)
(sb-ext:package-locked-error-symbol function)
(sb-ext:package-locked-p function)
(sb-ext:lock-package function)
(sb-ext:unlock-package function)
(sb-ext:package-implemented-by-list function)
(sb-ext:package-implements-list function)
(sb-ext:add-implementation-package function)
(sb-ext:remove-implementation-package function)
(sb-ext:without-package-locks macro)
(sb-ext:with-unlocked-packages macro)
"The DEFPACKAGE options are extended to include the following:
- :LOCK `<boolean>` (defaults to NIL)
If the argument to :LOCK is T, the package is locked, else it is
unlocked. Existing package are also affected.
- :IMPLEMENT `<package-designator>*`
The package is added as an implementation package to the
packages named. If :IMPLEMENT is not provided, it defaults to
the package itself.
Example:
(defpackage \"FOO\" (:export \"BAR\") (:lock t) (:implement))
(defpackage \"FOO-INT\" (:use \"FOO\") (:implement \"FOO\" \"FOO-INT\"))
;;; is equivalent to
(defpackage \"FOO\") (:export \"BAR\"))
(lock-package \"FOO\")
(remove-implementation-package \"FOO\" \"FOO\")
(defpackage \"FOO-INT\" (:use \"BAR\"))
(add-implementation-package \"FOO-INT\" \"FOO\")")

View file

@ -0,0 +1,153 @@
(in-package :sb-manual)
(defsection @pathnames (:title "Pathnames"
:concepts ("pathname"))
(@lisp-pathnames section)
(@native-filenames section))
(defsection @lisp-pathnames (:title "Lisp Pathnames")
"There are many aspects of ANSI Common Lisp's pathname support
which are implementation-defined and so need documentation."
(@home-directory-specifiers section)
(@the-sys-logical-pathname-host section))
;; FIXME: as a matter of ANSI conformance, we are required to document
;; implementation-defined stuff, which for pathnames (chapter 19 of CLtS)
;; includes:
;;
;; * Otherwise, the parsing of thing is implementation-defined.
;; (PARSE-NAMESTRING)
;;
;; * If thing contains an explicit host name and no explicit device name,
;; then it is implementation-defined whether parse-namestring will supply
;; the standard default device for that host as the device component of
;; the resulting pathname. (PARSE-NAMESTRING)
;;
;; * The specific nature of the search is implementation-defined.
;; (LOAD-LOGICAL-PATHNAME-TRANSLATIONS)
;;
;; * Any additional elements are implementation-defined.
;; (LOGICAL-PATHNAME-TRANSLATIONS)
;;
;; * The matching rules are implementation-defined but should be consistent
;; with directory. (PATHNAME-MATCH-P)
;;
;; * Any such additional translations are implementation-defined.
;; (TRANSLATE-LOGICAL-PATHNAMES)
;;
;; * ...or an implementation-defined portion of a component...
;; (TRANSLATE-PATHNAME)
;;
;; * The portion of source that is copied into the resulting pathname is
;; implementation-defined. (TRANSLATE-PATHNAME)
;;
;; * During the copying of a portion of source into the resulting
;; pathname, additional implementation-defined translations of case or
;; file naming conventions might occur. (TRANSLATE-PATHNAME)
;;
;; * In general, the syntax of namestrings involves the use of
;; implementation-defined conventions. (19.1.1)
;;
;; * The nature of the mapping between structure imposed by pathnames and
;; the structure, if any, that is used by the underlying file system is
;; implementation-defined. (19.1.2)
;;
;; * The mapping of the pathname components into the concepts peculiar to
;; each file system is implementation-defined. (19.1.2)
;;
;; * Whether separator characters are permitted as part of a string in a
;; pathname component is implementation-defined; (19.2.2.1.1)
;;
;; * Whether a value of :unspecific is permitted for any component on any
;; given file system accessible to the implementation is
;; implementation-defined. (19.2.2.2.3)
;;
;; * Other symbols and integers have implementation-defined meaning.
;; (19.2.2.4.6)
(defsection @home-directory-specifiers (:title "Home Directory Specifiers")
"SBCL accepts the keyword :HOME and a list of the form
`(:HOME` `\"username\")` as a directory component immediately
following :ABSOLUTE.
:HOME is represented in namestrings by `~/` and `(:HOME`
`\"username\")` by `~username/` at the start of the namestring.
Tilde-characters elsewhere in namestrings represent themselves.
Home directory specifiers are resolved to home directory of the
current or specified user by SB-EXT:NATIVE-NAMESTRING, which is used
by the implementation to translate pathnames before passing them on
to operating system specific routines.
Using `(:HOME` `\"user\")` form on Windows signals an error.")
(defsection @the-sys-logical-pathname-host
(:title "The SYS Logical Pathname Host")
;; The existence and meaning of SYS: logical pathnames is
;; implementation-defined (CLHS 19.3.1.1.1).
"The @LOGICAL-PATHNAME host named by `\"SYS\"` exists in SBCL.
Its LOGICAL-PATHNAME-TRANSLATIONS may be set by the site or the user
applicable to point to the locations of the system's sources; in
particular, the core system's source files match the logical
pathname `\"SYS:SRC;**;*.*.*\"`, and the contributed modules' source
files match `\"SYS:CONTRIB;**;*.*.*\"`."
(sb-ext:set-sbcl-source-location function))
(defsection @native-filenames (:title "Native Filenames")
"In some circumstances, what is wanted is a Lisp pathname object which
corresponds to a string produced by the Operating System. In this
case, some of the default parsing rules are inappropriate: most
filesystems do not have a native understanding of wild pathnames;
such functionality is often provided by shells above the OS, often
in mutually-incompatible ways.
To allow the user to deal with this, the following functions are
provided: SB-EXT:PARSE-NATIVE-NAMESTRING and SB-EXT:NATIVE-PATHNAME
return the closest equivalent Lisp pathname to a given string
(appropriate for the Operating System), while
SB-EXT:NATIVE-NAMESTRING converts a non-wild pathname designator to
the equivalent native namestring, if possible. Some Lisp pathname
concepts (such as the :BACK directory component) have no direct
equivalents in most Operating Systems; the behaviour of
SB-EXT:NATIVE-NAMESTRING is unspecified if an inappropriate pathname
designator is passed to it. Additionally, note that conversion from
pathname to native filename and back to pathname should not be
expected to preserve equivalence under EQUAL."
(sb-ext:parse-native-namestring function)
(sb-ext:native-pathname function)
(sb-ext:native-namestring function)
"Because some file systems permit the names of directories to be
expressed in multiple ways, it is occasionally necessary to parse a
native file name as a directory name or to produce a native file
name that names a directory as a file. For these cases,
PARSE-NATIVE-NAMESTRING accepts the keyword argument
:AS-DIRECTORY to force a filename to parse as a directory, and
SB-EXT:NATIVE-NAMESTRING accepts the keyword argument :AS-FILE
to force a pathname to unparse as a file. For example,
; On Unix, the directory \"/tmp/\" can be denoted by \"/tmp/\" or \"/tmp\".
; Under the default rules for native filenames, these parse and
; unparse differently.
(defvar *p*)
(setf *p* (parse-native-namestring \"/tmp/\")) => #P\"/tmp/\"
(pathname-name *p*) => NIL
(pathname-directory *p*) => (:ABSOLUTE \"tmp\")
(native-namestring *p*) => \"/tmp/\"
(setf *p* (parse-native-namestring \"/tmp\")) => #P\"/tmp\"
(pathname-name *p*) => \"tmp\"
(pathname-directory *p*) => (:ABSOLUTE)
(native-namestring *p*) => \"/tmp\"
; A non-NIL AS-DIRECTORY argument to PARSE-NATIVE-NAMESTRING forces
; both the second string to parse the way the first does.
(setf *p* (parse-native-namestring \"/tmp\"
nil *default-pathname-defaults*
:as-directory t)) => #P\"/tmp/\"
(pathname-name *p*) => NIL
(pathname-directory *p*) => (:ABSOLUTE \"tmp\")
; A non-NIL AS-FILE argument to NATIVE-NAMESTRING forces the pathname
; parsed from the first string to unparse as the second string.
(setf *p* (parse-native-namestring \"/tmp/\")) => #P\"/tmp/\"
(native-namestring *p* :as-file t) => \"/tmp\"")

View file

@ -0,0 +1,162 @@
(in-package :sb-manual)
(defsection @profiling (:title "Profiling"
:concepts ("profiling"))
"SBCL includes both a deterministic profiler, that can collect
statistics on individual functions, and a more \"modern\",
statistical profiler.
Inlined functions do not appear in the results reported by either."
(@deterministic-profiler section)
(@statistical-profiler section))
(defsection @deterministic-profiler
(:title "Deterministic Profiler"
:concepts (("profiling," "deterministic")))
"The package `SB-PROFILE` provides a classic, per-function-call
profiler.
> __Warning__: When profiling code executed by multiple threads in
> parallel, the consing attributed to each function is inaccurate."
(sb-profile:profile macro)
(sb-profile:unprofile macro)
(sb-profile:report function)
(sb-profile:reset function))
(defsection @statistical-profiler (:title "Statistical Profiler"
:concepts (("profiling," "statistical")))
"The `SB-SPROF` module, loadable by
(require :sb-sprof)
provides an alternate profiler which works by taking samples of the
program execution at regular intervals, instead of instrumenting
functions as SB-PROFILE:PROFILE does. You might find `SB-SPROF` more
useful than the deterministic profiler when profiling functions in the
`COMMON-LISP` package, SBCL internals, or code where the instrumenting
overhead is excessive.
Additionally `SB-SPROF` includes a limited deterministic profiler
which can be used for reporting the amounts of calls to some functions
during
__Example usage:__
(in-package :cl-user)
(require :sb-sprof)
(declaim (optimize speed))
(defun cpu-test-inner (a i)
(logxor a
(* i 5)
(+ a i)))
(defun cpu-test (n)
(let ((a 0))
(dotimes (i (expt 2 n) a)
(setf a (cpu-test-inner a i)))))
;;;; CPU profiling
;;; Take up to 1000 samples of running (CPU-TEST 26), and give a flat
;;; table report at the end. Profiling will end one the body has been
;;; evaluated once, whether or not 1000 samples have been taken.
(sb-sprof:with-profiling (:max-samples 1000
:report :flat
:loop nil)
(cpu-test 26))
;;; Record call counts for functions defined on symbols in the CL-USER
;;; package.
(sb-sprof:profile-call-counts \"CL-USER\")
;;; Take 1000 samples of running (CPU-TEST 24), and give a flat
;;; table report at the end. The body will be re-evaluated in a loop
;;; until 1000 samples have been taken. A sample count will be printed
;;; after each iteration.
(sb-sprof:with-profiling (:max-samples 1000
:report :flat
:loop t
:show-progress t)
(cpu-test 24))
;;;; Allocation profiling
(defun foo (&rest args)
(mapcar (lambda (x) (float x 1d0)) args))
(defun bar (n)
(declare (fixnum n))
(apply #'foo (loop repeat n collect n)))
(sb-sprof:with-profiling (:max-samples 10000
:mode :alloc
:report :flat)
(bar 1000))
__Output:__
The flat report format will show a table of all functions that the
profiler encountered on the call stack during sampling, ordered by
the number of samples taken while executing that function.
Self Total Cumul
Nr Count % Count % Count % Calls Function
------------------------------------------------------------------------
1 69 24.4 97 34.3 69 24.4 67108864 CPU-TEST-INNER
2 64 22.6 64 22.6 133 47.0 - SB-VM::GENERIC-+
3 39 13.8 256 90.5 172 60.8 1 CPU-TEST
4 31 11.0 31 11.0 203 71.7 - SB-KERNEL:TWO-ARG-XOR
For each function, the table will show three absolute and relative
sample counts. The `Self` column shows samples taken while directly
executing that function. The `Total` column shows samples taken
while executing that function or functions called from it (sampled
to a platform-specific depth). The `Cumul` column shows the sum of
all `Self` columns up to and including that line in the table.
Additionally the `Calls` column will record the amount of calls that
were made to the function during the profiling run. This value will
only be reported for functions that have been explicitly marked for
call counting with SB-SPROF:PROFILE-CALL-COUNTS.
The profiler also hooks into the disassembler such that instructions
which have been sampled are annotated with their relative frequency
of sampling. This information is not stored across different
sampling runs.
; 6CF: 702E JO L4 ; 6/242 samples
; 6D1: D1E3 SHL EBX, 1
; 6D3: 702A JO L4
; 6D5: L2: F6C303 TEST BL, 3 ; 2/242 samples
; 6D8: 756D JNE L8
; 6DA: 8BC3 MOV EAX, EBX ; 5/242 samples
; 6DC: L3: 83F900 CMP ECX, 0 ; 4/242 samples
__Platform support__
Allocation profiling is only supported on SBCL builds that use the
@GENERATIONAL-GC. Tracking of call stacks at a depth of more than
two levels is only supported on x86 and x86-64.
__Macros__"
(sb-sprof:with-profiling macro)
(sb-sprof:with-sampling macro)
"__Functions__"
(sb-sprof:map-traces function)
(sb-sprof:sample-pc function)
(sb-sprof:report function)
(sb-sprof:reset function)
(sb-sprof:start-profiling function)
(sb-sprof:stop-profiling function)
(sb-sprof:profile-call-counts function)
(sb-sprof:unprofile-call-counts function)
"__Variables__"
(sb-sprof:*max-samples* variable)
(sb-sprof:*sample-interval* variable)
"__Credits__
`SB-SPROF` is an SBCL port, with enhancements, of Gerd Moellmann's
statistical profiler for CMUCL.")

View file

@ -0,0 +1,53 @@
(in-package :sb-manual)
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun documentation-generation-date-string (&key long)
(multiple-value-bind (second minute hour day month year)
(decode-universal-time (get-universal-time))
(if long
(format nil "~D-~2,'0D-~2,'0D ~2,'0D:~2,'0D:~2,'0D"
year month day hour minute second)
(format nil "~D-~2,'0D" year month))))
(defun package-exists-p/reader (name)
(if (find-package name) '(and) '(or))))
(defsection @sbcl-manual (:title "SBCL Manual")
;; This docstring is not used in the Texinfo version (see
;; EMIT-TEXINFO-FOR-SECTION).
#.(format nil "This is an unofficial rendering of the SBCL Manual
using [MGL-PAX][pax::@pax-manual] with the same content as the
official version at <https://www.sbcl.org/> but with heavy linking
internally, to the CLHS, and to the source code on
[GitHub](https://github.com/sbcl/sbcl).
The output is for SBCL version `~A`, generated _~A_. See
<https://fixnum.com> for this document in other formats.
This manual is part of the SBCL software system. See the
`\\\\README` file for more information. The manual is largely
derived from the manual for the [CMUCL](https://cmucl.org/) system,
which was produced at Carnegie Mellon University and later released
into the public domain. The manual is in the public domain and is
provided with absolutely no warranty. See the `\\\\COPYING` and
`\\\\CREDITS` files for more information."
(lisp-implementation-version)
(documentation-generation-date-string :long t))
(@support-and-bugs section)
(@introduction section)
(@starting-and-stopping section)
(@compiler section)
(@debugger section)
(@efficiency section)
(@beyond-the-ansi-standard section)
(@external-formats section)
(@foreign-function-interface section)
(@pathnames section)
(@streams section)
(@package-locks section)
(@threading section)
(@timers section)
#+#.(sb-manual::package-exists-p/reader '#:sb-bsd-sockets)
(@networking section)
(@profiling section)
(@contributed-modules section)
(@deprecation section))

View file

@ -0,0 +1,340 @@
(in-package :sb-manual)
(defsection @starting-and-stopping (:title "Starting and Stopping")
(@starting-sbcl section)
(@stopping-sbcl section)
(@command-line-options section)
(@initialization-files section)
(@initialization-and-exit-hooks section))
(defsection @starting-sbcl (:title "Starting SBCL")
(@running-from-shell section)
(@running-from-emacs section)
(@shebang-scripts section))
(defsection @running-from-shell (:title "Running from Shell")
"To run SBCL, type `sbcl` at the command line.
You should end up in the toplevel _REPL_ (read-eval-print loop),
where you can interact with SBCL by typing expressions.
$ sbcl
This is SBCL 0.8.13.60, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
* (+ 2 2)
4
* (exit)
$
Also see @COMMAND-LINE-OPTIONS and @STOPPING-SBCL.")
(defsection @running-from-emacs (:title "Running from Emacs")
"To run SBCL as an `inferior-lisp` from Emacs, in your `.emacs` do
something like:
;;; The SBCL binary and command-line arguments
(setq inferior-lisp-program \"/usr/local/bin/sbcl --noinform\")
For more information on using SBCL with Emacs, see
@EDITOR-INTEGRATION.")
(defsection @shebang-scripts (:title "Shebang Scripts")
"Standard Unix tools that are interpreters follow a common command line
protocol that is necessary to work with \"shebang scripts\". SBCL
supports this via the `--script` command line option (see
@COMMAND-LINE-OPTIONS).
Example file (`hello.lisp`):
#!/usr/local/bin/sbcl --script
(write-line \"Hello, World!\")
Usage from the command line:
$ ./hello.lisp
Hello, World!
Note that SBCL skips the shebang line when it reads the file:
$ sbcl --script hello.lisp
Hello, World!")
(defsection @stopping-sbcl (:title "Stopping SBCL")
(@exit section)
(@end-of-file section)
(@saving-a-core-image section)
(@exit-on-errors section))
(defsection @exit (:title "Exit")
"SBCL can be stopped at any time by calling SB-EXT:EXIT,
optionally returning a specified numeric value to the calling
process. See @THREADING for information about terminating individual
threads."
(sb-ext:exit function))
(defsection @end-of-file (:title "End of File")
"By default SBCL also exits on end of input, caused either by user
pressing `Control-D` on an attached terminal, or end of input when
using SBCL as part of a shell pipeline.")
(defsection @saving-a-core-image (:title "Saving a Core Image")
"SBCL has the ability to save its state as a file for later
execution. This functionality is important for its bootstrapping
process, and is also provided as an extension to the user."
(sb-ext:save-lisp-and-die function)
;; When Swank is loaded, it sets this variable.
(sb-ext:*save-hooks* (variable nil))
"In cases where the standard initialization files have already been loaded
into the saved core, and alternative ones should be used (or none at
all), SBCL allows customizing the initfile pathname computation."
(sb-ext:*sysinit-pathname-function* variable)
(sb-ext:*userinit-pathname-function* variable)
"To facilitate distribution of SBCL applications using external
resources, the filesystem location of the SBCL core file being used
is available from Lisp."
(sb-ext:*core-pathname* (variable "<site-specific>")))
(defsection @exit-on-errors (:title "Exit on Errors")
"SBCL can also be configured to exit if an unhandled error occurs,
which is mainly useful for acting as part of a shell pipeline; doing
so under most other circumstances would mean giving up large parts
of the flexibility and robustness of Common Lisp. See
@DEBUGGER-ENTRY and the command line option `--disable-debugger` in
@RUNTIME-OPTIONS.")
(defsection @command-line-options (:title "Command Line Options")
"Command line options can be considered an advanced topic; for ordinary
interactive use, no command line arguments should be necessary.
In order to understand the command line argument syntax for SBCL, it
is helpful to understand that the SBCL system is implemented as two
components, a low-level runtime environment written in \\C and a
higher-level system written in Common Lisp itself. Some command line
arguments are processed during the initialization of the low-level
runtime environment, some command line arguments are processed
during the initialization of the Common Lisp system, and any
remaining command line arguments are made available to user code via
SB-EXT:*POSIX-ARGV*.
The full, unambiguous syntax for invoking SBCL at the command line
is:
sbcl <runtime-option>* --end-runtime-options \\
<toplevel-option>* --end-toplevel-options \\
<user-option>*
For convenience, `--end-runtime-options` and
`--end-toplevel-options` can be omitted, which can be convenient
when you are running the program interactively, and you can see that
no ambiguities are possible with the option values you are using.
Omitting these elements is probably a bad idea for any batch file
where any of the options are under user control, since it makes it
impossible for SBCL to detect erroneous command line input, so that
erroneous command line arguments will be passed on to the user
program even if they was intended for the runtime system or the Lisp
system."
(@runtime-options section)
(@toplevel-options section))
(defsection @runtime-options (:title "Runtime Options")
"- `--core <corefilename>`
Run the specified Lisp core file instead of the default. Note
that if the Lisp core file is a user-created core file, it may
run a nonstandard toplevel which does not recognize the standard
toplevel options.
- `--dynamic-space-size <megabytes>`
Size of the dynamic space reserved on startup in megabytes.
Default value is platform dependent.
- `--control-stack-size <megabytes>`
Size of control stack reserved for each thread in megabytes.
Default value is 2.
- `--tls-limit <positive integer>`
Maximum number of thread-local symbols in threaded builds.
Default value is 4096.
- `--noinform`
Suppress the printing of any banner or other informational
message at startup. This makes it easier to write Lisp programs
which work cleanly in Unix pipelines. See also the `--noprint`
and `--disable-debugger` options.
- `--disable-ldb`
Disable the low-level debugger. Only effective if SBCL is
compiled with @LDB. ~DISABLING-LDB
- `--lose-on-corruption`
There are some dangerous low-level errors (for instance, control
stack exhausted, memory fault) that (or whose handlers) can
corrupt the image. By default, SBCL prints a warning, then tries
to continue and handle the error in Lisp, but this will not
always work, and SBCL may malfunction or even hang. With this
option, upon encountering such an error, SBCL will exit instead
of invoking @LDB (if present and enabled ~ENABLING-LDB).
- `--script <filename>`
As a _runtime_ option, this is equivalent to `--noinform`
`--disable-ldb` `--lose-on-corruption`
`--end-runtime-options` `--script` `<filename>`. See
the description of `--script` as a _toplevel_ option below.
If there are no other command line arguments following
`--script`, the filename argument can be omitted.
- `--merge-core-pages`
When platform support is present, provide hints to the operating
system that identical pages may be shared between processes
until they are written to. This can be useful to reduce the
memory usage on systems with multiple SBCL processes started
from similar but differently-named core files, or from
compressed cores. Without platform support, do nothing. By
default only compressed cores trigger hinting.
- `--no-merge-core-pages`
Ensures that no sharing hint is provided to the operating
system.
- `--help`
Print some basic information about SBCL, then exit.
- `--version`
Print SBCL's version information, then exit.
In the future, runtime options may be added to control behaviour
such as lazy allocation of memory.
Runtime options, including any `--end-runtime-options` option, are
stripped out of the command line before the Lisp toplevel logic gets
a chance to see it.")
(defsection @toplevel-options (:title "Toplevel Options")
"The following options are processed and removed by the default
toplevel (see SB-EXT:SAVE-LISP-AND-DIE).
- `--sysinit <filename>`
Load `FILENAME` instead of the default system initialization
file (see @INITIALIZATION-FILES).
- `--no-sysinit`
Don't load a system-wide initialization file. If this option is
given, the `--sysinit` option is ignored.
- `--userinit <filename>`
Load `FILENAME` instead of the default user initialization file
(see @INITIALIZATION-FILES.)
- `--no-userinit`
Don't load a user initialization file. If this option is given,
the `--userinit` option is ignored.
- `--eval <command>`
After executing any initialization file, but before starting the
read-eval-print loop on standard input, read and evaluate
`COMMAND`. More than one `--eval` option can be used, and all
will be read and executed, in the order they appear on the
command line.
- `--load <filename>`
This is equivalent to `--eval '(load \"<filename>\")'`. The
special syntax is intended to reduce quoting headaches when
invoking SBCL from shell scripts.
- `--noprint`
When ordinarily the toplevel \"read-eval-print loop\" would be
executed, execute a \"read-eval loop\" instead, i.e. don't print
a prompt and don't echo results. Combined with the `--noinform`
runtime option, this makes it easier to write Lisp \"scripts\"
which work cleanly in Unix pipelines.
- `--disable-debugger`
By default when SBCL encounters an error, it enters the builtin
debugger, allowing interactive diagnosis and possible
intercession. This option disables the debugger, causing errors
to print a backtrace and exit with status 1 instead. When given,
this option takes effect before loading of initialization files
or processing `--eval` and `--load` options. See
SB-EXT:DISABLE-DEBUGGER and @DEBUGGER-ENTRY.
- `--script <filename>`
Implies `--no-userinit` `--no-sysinit` `--disable-debugger`
`--end-toplevel-options`.
Causes the system to load the specified file instead of entering
the read-eval-print-loop, and exit afterwards. If the file
begins with a shebang line, it is ignored.
If there are no other command line arguments following, the
filename can be omitted: this causes the script to be loaded
from standard input instead. Shebang lines in standard input
script are currently _not_ ignored.
In either case, if there is an unhandled error (e.g. end of
file, or a broken pipe) on either standard input, standard
output, or standard error, the script silently exits with code
0. This allows e.g. safely piping output from SBCL to `head -n1`
or similar.
Additionally, the option sets *COMPILE-VERBOSE* and
*LOAD-VERBOSE* to NIL while loading the file to avoid
potentially verbose diagnostic messages printed on the standard
output.")
(defsection @initialization-files (:title "Initialization Files")
"SBCL processes initialization files with READ and EVAL,
not LOAD; hence initialization files can be used to set startup
*PACKAGE* and *READTABLE*, and for proclaiming a global optimization
policy.
- __System Initialization File:__ Defaults to `$SBCL_HOME/sbclrc`,
or if that doesn't exist to `/etc/sbclrc`. Can be overridden with
the command line option `--sysinit` or `--no-sysinit` (see
@TOPLEVEL-OPTIONS).
The system initialization file is intended for system
administrators and software packagers to configure locations of
installed third party modules, etc.
- __User Initialization File:__ Defaults to `$HOME/.sbclrc`. Can be
overridden with the command line option `--userinit` or
`--no-userinit` (see @TOPLEVEL-OPTIONS).
The user initialization file is intended for personal
customizations, such as loading certain modules at startup,
defining convenience functions to use in the @REPL,
handling automatic recompilation of FASLs (see @FASL-FORMAT),
etc.
Neither initialization file is required.")
(defsection @initialization-and-exit-hooks
(:title "Initialization and Exit Hooks")
"SBCL provides hooks into the system initialization and exit."
(sb-ext:*init-hooks* variable)
(sb-ext:*exit-hooks* variable))

View file

@ -0,0 +1,322 @@
(in-package :sb-manual)
(defsection @streams (:title "Streams")
"Streams which read or write Lisp character data from or to the outside
world -- files, sockets or other external entities -- require the
specification of a conversion between the external, binary data and
the Lisp characters. In ANSI Common Lisp, this is done by specifying
the :EXTERNAL-FORMAT argument when the stream is created. The major
information required is an _encoding_, specified by a keyword naming
that encoding; however, it is also possible to specify refinements
to that encoding as additional options to the external format
designator.
In addition, SBCL supports various extensions of ANSI Common Lisp
streams:
- _Bivalent Streams_: A type of stream that can read and write both
CHARACTER and `(UNSIGNED-BYTE 8)` values.
- _Gray Streams_: User-overloadable CLOS classes whose instances can
be used as Lisp streams (e.g. passed as the first argument to
FORMAT).
- _Simple Streams_: The bundled contrib module `SB-SIMPLE-STREAMS`
implements a subset of the Franz Allegro simple-streams proposal."
(@stream-external-formats section)
(@bivalent-streams section)
(@gray-streams section)
(@sb-simple-streams section))
(defsection @stream-external-formats (:title "Stream External Formats")
"The function STREAM-EXTERNAL-FORMAT returns the canonical name of
the @EXTERNAL-FORMAT (see @EXTERNAL-FORMATS) used by the stream for
character-based input and/or output.
When constructing file streams, for example using OPEN or
WITH-OPEN-FILE, the external format to use is specified via the
:EXTERNAL-FORMAT argument which accepts an external format
designator (see @EXTERNAL-FORMAT-DESIGNATORS).")
(defsection @bivalent-streams (:title "Bivalent Streams")
"A _bivalent stream_ can be used to read and write both
CHARACTER and `(UNSIGNED-BYTE 8)` values. A bivalent stream is
created by calling OPEN with the argument :ELEMENT-TYPE
:DEFAULT. On such a stream, both binary and character data can be
read and written with the usual input and output functions.
Streams are _not_ created bivalent by default for performance
reasons. Bivalent streams are incompatible with `FAST-READ-CHAR`, an
internal optimization in SBCL's stream machinery that bulk-converts
octets to characters and implements a fast path through READ-CHAR.")
(defsection @gray-streams (:title "Gray Streams")
"The Gray Streams interface is a widely supported extension that
provides for definition of CLOS-extensible stream classes. Gray
stream classes are implemented by adding methods to generic
functions analogous to Common Lisp's standard I/O functions.
Instances of Gray stream classes may be used with any I/O operation
where a non-Gray stream can, provided that all required methods have
been implemented suitably."
(@gray-streams-classes section)
(@methods-common-to-all-streams section)
(@input-stream-methods section)
(@character-input-stream-methods section)
(@output-stream-methods section)
(@character-output-stream-methods section)
(@binary-stream-methods section)
(@gray-streams-examples section))
(defsection @gray-streams-classes (:title "Gray Streams classes")
"The defined Gray Stream classes are these:"
(sb-gray:fundamental-stream class)
(sb-gray:fundamental-input-stream class)
"The function INPUT-STREAM-P will return true of any generalized
instance of SB-GRAY:FUNDAMENTAL-INPUT-STREAM."
(sb-gray:fundamental-output-stream class)
"The function OUTPUT-STREAM-P will return true of any generalized
instance of SB-GRAY:FUNDAMENTAL-OUTPUT-STREAM."
(sb-gray:fundamental-binary-stream class)
"Note that instantiable subclasses of SB-GRAY:FUNDAMENTAL-BINARY-STREAM
should provide (or inherit) an applicable method for the generic
function STREAM-ELEMENT-TYPE."
(sb-gray:fundamental-character-stream class)
(sb-gray:fundamental-binary-input-stream class)
(sb-gray:fundamental-binary-output-stream class)
(sb-gray:fundamental-character-input-stream class)
(sb-gray:fundamental-character-output-stream class))
(defsection @methods-common-to-all-streams
(:title "Methods common to all streams")
"These generic functions can be specialized on any generalized instance
of fundamental-stream."
(stream-element-type generic-function)
(close generic-function)
(sb-gray:stream-file-position generic-function))
(defsection @input-stream-methods (:title "Input stream methods")
"These generic functions may be specialized on any generalized instance
of fundamental-input-stream."
(sb-gray:stream-clear-input generic-function)
(sb-gray:stream-read-sequence generic-function))
(defsection @character-input-stream-methods
(:title "Character input stream methods")
"These generic functions are used to implement subclasses of
SB-GRAY:FUNDAMENTAL-INPUT-STREAM:"
(sb-gray:stream-peek-char generic-function)
(sb-gray:stream-read-char-no-hang generic-function)
(sb-gray:stream-read-char generic-function)
(sb-gray:stream-read-line generic-function)
(sb-gray:stream-listen generic-function)
(sb-gray:stream-unread-char generic-function))
(defsection @output-stream-methods (:title "Output stream methods")
"These generic functions are used to implement subclasses of
SB-GRAY:FUNDAMENTAL-OUTPUT-STREAM:"
(sb-gray:stream-clear-output generic-function)
(sb-gray:stream-finish-output generic-function)
(sb-gray:stream-force-output generic-function)
(sb-gray:stream-write-sequence generic-function))
(defsection @character-output-stream-methods
(:title "Character output stream methods")
"These generic functions are used to implement subclasses of
SB-GRAY:FUNDAMENTAL-CHARACTER-OUTPUT-STREAM:"
(sb-gray:stream-advance-to-column generic-function)
(sb-gray:stream-fresh-line generic-function)
(sb-gray:stream-line-column generic-function)
(sb-gray:stream-line-length generic-function)
(sb-gray:stream-start-line-p generic-function)
(sb-gray:stream-terpri generic-function)
(sb-gray:stream-write-char generic-function)
(sb-gray:stream-write-string generic-function))
(defsection @binary-stream-methods (:title "Binary stream methods")
"The following generic functions are available for subclasses of
SB-GRAY:FUNDAMENTAL-BINARY-STREAM:"
(sb-gray:stream-read-byte generic-function)
(sb-gray:stream-write-byte generic-function))
(defsection @gray-streams-examples (:title "Gray Streams Examples")
"Below are two classes of stream that can be conveniently defined as
wrappers for Common Lisp streams. These are meant to serve as
examples of minimal implementations of the protocols that must be
followed when defining Gray streams. Realistic uses of the Gray
Streams API would implement the various methods that can do I/O in
batches, such as SB-GRAY:STREAM-READ-LINE,
SB-GRAY:STREAM-WRITE-STRING, SB-GRAY:STREAM-READ-SEQUENCE, and
SB-GRAY:STREAM-WRITE-SEQUENCE."
(@character-counting-input-stream section)
(@output-prefixing-character-stream section))
(defsection @character-counting-input-stream
(:title "Character Counting Input Stream")
" It is occasionally handy for programs that process input files to
count the number of characters and lines seen so far, and the number
of characters seen on the current line, so that useful messages may
be reported in case of parsing errors, etc. Here is a character
input stream class that keeps track of these counts. Note that all
character input streams must implement SB-GRAY:STREAM-READ-CHAR and
SB-GRAY:STREAM-UNREAD-CHAR.
(defclass wrapped-stream (fundamental-stream)
((stream :initarg :stream :reader stream-of)))
(defmethod stream-element-type ((stream wrapped-stream))
(stream-element-type (stream-of stream)))
(defmethod close ((stream wrapped-stream) &key abort)
(close (stream-of stream) :abort abort))
(defclass wrapped-character-input-stream
(wrapped-stream fundamental-character-input-stream)
())
(defmethod stream-read-char ((stream wrapped-character-input-stream))
(read-char (stream-of stream) nil :eof))
(defmethod stream-unread-char ((stream wrapped-character-input-stream)
char)
(unread-char char (stream-of stream)))
(defclass counting-character-input-stream
(wrapped-character-input-stream)
((char-count :initform 1 :accessor char-count-of)
(line-count :initform 1 :accessor line-count-of)
(col-count :initform 1 :accessor col-count-of)
(prev-col-count :initform 1 :accessor prev-col-count-of)))
(defmethod stream-read-char ((stream counting-character-input-stream))
(with-accessors ((inner-stream stream-of) (chars char-count-of)
(lines line-count-of) (cols col-count-of)
(prev prev-col-count-of)) stream
(let ((char (call-next-method)))
(cond ((eql char :eof)
:eof)
((char= char #\Newline)
(incf lines)
(incf chars)
(setf prev cols)
(setf cols 1)
char)
(t
(incf chars)
(incf cols)
char)))))
(defmethod stream-unread-char ((stream counting-character-input-stream)
char)
(with-accessors ((inner-stream stream-of) (chars char-count-of)
(lines line-count-of) (cols col-count-of)
(prev prev-col-count-of)) stream
(cond ((char= char #\Newline)
(decf lines)
(decf chars)
(setf cols prev))
(t
(decf chars)
(decf cols)
char))
(call-next-method)))
The default methods for SB-GRAY:STREAM-READ-CHAR-NO-HANG,
SB-GRAY:STREAM-PEEK-CHAR, SB-GRAY:STREAM-LISTEN,
SB-GRAY:STREAM-CLEAR-INPUT, SB-GRAY:STREAM-READ-LINE, and
SB-GRAY:STREAM-READ-SEQUENCE should be sufficient (though the last
two will probably be slower than methods that forwarded directly).
Here's a sample use of this class:
(with-input-from-string (input \"1 2
3 :foo \")
(let ((counted-stream (make-instance 'counting-character-input-stream
:stream input)))
(loop for thing = (read counted-stream) while thing
unless (numberp thing) do
(error \"Non-number ~S (line ~D, column ~D)\" thing
(line-count-of counted-stream)
(- (col-count-of counted-stream)
(length (format nil \"~S\" thing))))
end
do (print thing))))
Output:
1
2
3
Non-number :FOO (line 2, column 5)
[Condition of type SIMPLE-ERROR]")
(defsection @output-prefixing-character-stream
(:title "Output Prefixing Character Stream")
"One use for a wrapped output stream might be to prefix each line of
text with a timestamp, e.g. for a logging stream. Here's a simple
stream that does this, though without any fancy line-wrapping. Note
that all character output stream classes must implement
SB-GRAY:STREAM-WRITE-CHAR and SB-GRAY:STREAM-LINE-COLUMN.
(defclass wrapped-stream (fundamental-stream)
((stream :initarg :stream :reader stream-of)))
(defmethod stream-element-type ((stream wrapped-stream))
(stream-element-type (stream-of stream)))
(defmethod close ((stream wrapped-stream) &key abort)
(close (stream-of stream) :abort abort))
(defclass wrapped-character-output-stream
(wrapped-stream fundamental-character-output-stream)
((col-index :initform 0 :accessor col-index-of)))
(defmethod stream-line-column ((stream wrapped-character-output-stream))
(col-index-of stream))
(defmethod stream-write-char ((stream wrapped-character-output-stream)
char)
(with-accessors ((inner-stream stream-of) (cols col-index-of)) stream
(write-char char inner-stream)
(if (char= char #\Newline)
(setf cols 0)
(incf cols))))
(defclass prefixed-character-output-stream
(wrapped-character-output-stream)
((prefix :initarg :prefix :reader prefix-of)))
(defgeneric write-prefix (prefix stream)
(:method ((prefix string) stream) (write-string prefix stream))
(:method ((prefix function) stream) (funcall prefix stream)))
(defmethod stream-write-char ((stream prefixed-character-output-stream)
char)
(with-accessors ((inner-stream stream-of) (cols col-index-of)
(prefix prefix-of)) stream
(when (zerop cols)
(write-prefix prefix inner-stream))
(call-next-method)))
As with the example input stream, this implements only the minimal
protocol. A production implementation should also provide methods
for at least SB-GRAY:STREAM-WRITE-STRING,
SB-GRAY:STREAM-WRITE-SEQUENCE.
And here's a sample use of this class:
(flet ((format-timestamp (stream)
(apply #'format stream \"[~2@*~2,' D:~1@*~2,'0D:~0@*~2,'0D] \"
(multiple-value-list (get-decoded-time)))))
(let ((output (make-instance 'prefixed-character-output-stream
:stream *standard-output*
:prefix #'format-timestamp)))
(loop for string in '(\"abc\" \"def\" \")ghi\") do
(write-line string output)
(sleep 1))))
Output:
[ 0:30:05] abc
[ 0:30:06] def
[ 0:30:07] ghi
NIL")

View file

@ -0,0 +1,125 @@
(in-package :sb-manual)
(defsection @support-and-bugs (:title "Getting Support and Reporting Bugs")
(@volunteer-support section)
(@commercial-support section)
(@reporting-bugs section))
(defsection @volunteer-support (:title "Volunteer Support")
"Your primary source of SBCL support should probably be the mailing
list `sbcl-help`: in addition to other users SBCL developers monitor
this list and are available for advice. As an anti-spam measure
subscription is required for posting:
<https://lists.sourceforge.net/lists/listinfo/sbcl-help>
Remember that the people answering your question are volunteers, so
you stand a much better chance of getting a good answer if you ask a
good question.
Before sending mail, check the list archives at either
<http://sourceforge.net/mailarchive/forum.php?forum_name=sbcl-help>
or
<http://news.gmane.org/gmane.lisp.steel-bank.general>
to see if your question has been answered already. Checking the bug
database is also worth it (see @REPORTING-BUGS), to see if the issue
is already known.
For general advice on asking good questions, see
<http://www.catb.org/~esr/faqs/smart-questions.html>.")
(defsection @commercial-support (:title "Commercial Support")
"There is no formal organization developing SBCL, but if you need a
paid support arrangement or custom SBCL development, we maintain the
list of companies and consultants below. Use it to identify service
providers with appropriate skills and interests, and contact them
directly.
The SBCL project cannot verify the accuracy of the information or
the competence of the people listed, and they have provided their
own blurbs below: you must make your own judgement of suitability
from the available information - refer to the links they provide,
the CREDITS file, mailing list archives, CVS commit messages, and so
on. Please feel free to ask for advice on the sbcl-help list.
(At present, no companies or consultants wish to advertise paid
support or custom SBCL development in this manual).")
(defsection @reporting-bugs (:title "Reporting Bugs")
"SBCL uses Launchpad to track bugs. The bug database is available at
<https://bugs.launchpad.net/sbcl>
Reporting bugs there requires registering at Launchpad. However,
bugs can also be reported on the mailing list `sbcl-bugs`, which is
moderated but does _not_ require subscribing. Simply send email to
[`sbcl-bugs@lists.sourceforge.net`](mailto:sbcl-bugs@lists.sourceforge.net)
and the bug will be checked and added to Launchpad by SBCL
maintainers.
See the `\\\\HACKING` file on how to send patches."
(@how-to-report-bugs-effectively section)
(@how-to-report-signal-related-bugs section))
(defsection @how-to-report-bugs-effectively
(:title "How to Report Bugs Effectively")
"Please include enough information in a bug report that someone reading
it can reproduce the problem, i.e. don't write
Subject: apparent bug in PRINT-OBJECT (or *PRINT-LENGTH*?)
PRINT-OBJECT doesn't seem to work with *PRINT-LENGTH*. Is this a bug?
but instead
Subject: apparent bug in PRINT-OBJECT (or *PRINT-LENGTH*?)
In sbcl-1.2.3 running under OpenBSD 4.5 on my Alpha box, when
I compile and load the file
(DEFSTRUCT (FOO (:PRINT-OBJECT (LAMBDA (X Y)
(LET ((*PRINT-LENGTH* 4))
(PRINT X Y)))))
X Y)
then at the command line type
(MAKE-FOO)
the program loops endlessly instead of printing the object.
A more in-depth discussion on reporting bugs effectively can be
found at
<http://www.chiark.greenend.org.uk/~sgtatham/bugs.html>.")
(defsection @how-to-report-signal-related-bugs
(:title "How to Report Signal-related Bugs")
"If you run into a signal related bug, you are getting fatal errors
such as `signal N is [un]blocked` or just hangs, and you want to
send a useful bug report then:
- Compile SBCL with @LDB enabled (feature `:SB-LDB`, see
`base-target-features.lisp-expr`).
- Isolate a smallish test case, run it.
- If it just hangs kill it with `SIGABRT`: `kill -ABRT <pidof sbcl>`.
- Print the backtrace from ldb by typing `ba`.
- Attach gdb: `gdb -p <pidof sbcl>` and get backtraces for all
threads: `thread apply all ba`.
- If multiple threads are in play then still in gdb, try to get Lisp
backtrace for all threads: `thread apply all call
backtrace_from_fp($ebp, 100, 0)`. Substitute `$ebp` with `$rbp` on
x86-64. The backtraces will appear in the stdout of the SBCL
process.
- Send a report with the backtraces and the output (both stdout and
stderr) produced by SBCL.
- Don't forget to include OS and SBCL version.
- If available, include information on outcome of the same test with
other versions of SBCL, OS, ...")

View file

@ -0,0 +1,334 @@
(in-package :sb-manual)
(defsection @threading (:title "Threading")
"SBCL supports a fairly low-level threading interface that maps onto
the host operating system's concept of threads or lightweight
processes. This means that threads may take advantage of hardware
multiprocessing on machines that have more than one CPU, but it does
not allow Lisp control of the scheduler. This is found in the
`SB-THREAD` package.
Threads are part of the default build on x86[-64]/ARM64 Linux and
Windows.
They are also supported on: x86[-64] Darwin (Mac OS X), x86[-64]
FreeBSD, x86 SunOS (Solaris), PPC Linux, ARM64 Linux, RISC-V Linux.
On these platforms threads must be explicitly enabled at build-time,
see `INSTALL` for directions."
(@threading-basics section)
(@special-variables section)
(@atomic-operations section)
(@mutex-support section)
(@semaphores section)
(@waitqueue/condition-variables section)
(@barriers section)
(@sessions/debugging section)
(@foreign-threads section)
(@implementation-on-linux-x86oids section))
(defsection @threading-basics (:title "Threading Basics")
"```
(make-thread (lambda () (write-line \"Hello, world\")))
```"
(@thread-objects section)
(@running-threads section)
(@asynchronous-operations section)
(@miscellaneous-operations section)
(@error-conditions section))
(defsection @thread-objects (:title "Thread Objects")
(sb-thread:thread structure)
(sb-thread:*current-thread* variable)
(sb-thread:list-all-threads function)
(sb-thread:thread-alive-p function)
(sb-thread:thread-name function)
(sb-thread:main-thread-p function)
(sb-thread:main-thread function))
(defsection @running-threads (:title "Running Threads")
(sb-thread:make-thread function)
(sb-thread:return-from-thread macro)
(sb-thread:abort-thread function)
(sb-thread:join-thread function)
(sb-thread:thread-yield function))
(defsection @asynchronous-operations (:title "Asynchronous Operations")
(sb-thread:interrupt-thread function)
(sb-thread:terminate-thread function))
(defsection @miscellaneous-operations (:title "Miscellaneous Operations")
(sb-thread:symbol-value-in-thread function))
(defsection @error-conditions (:title "Error Conditions")
(sb-thread:thread-error condition)
(sb-thread:thread-error-thread function)
(sb-thread:symbol-value-in-thread-error condition)
(sb-thread:interrupt-thread-error condition)
(sb-thread:join-thread-error condition))
(defsection @special-variables (:title "Special Variables")
"The interaction of special variables with multiple threads is mostly
as one would expect, with behaviour very similar to other
implementations.
- Global special values are visible across all threads.
- Bindings (e.g. using LET) are local to the thread.
- Threads do not inherit dynamic bindings from the parent thread.
The last point means that
(defparameter *x* 0)
(let ((*x* 1))
(sb-thread:make-thread (lambda () (print *x*))))
prints `0` and not `1`.
Note, however, that there is a hard limit on the number of distinct
symbols that can be bound dynamically in threaded builds (see
`--tls-limit` in @RUNTIME-OPTIONS). Exceeding this limit triggers
the low-level error `Thread local storage exhausted.`")
(defsection @atomic-operations (:title "Atomic Operations")
"Following atomic operations are particularly useful for implementing
lockless algorithms."
(sb-ext:atomic-decf macro)
(sb-ext:atomic-incf macro)
(sb-ext:atomic-pop macro)
(sb-ext:atomic-push macro)
(sb-ext:atomic-update macro)
(sb-ext:compare-and-swap macro)
"Our SB-EXT:COMPARE-AND-SWAP is user-extensible by defining functions
named `(CAS <PLACE>)`, allowing users to add CAS support to new
places."
(sb-ext:cas macro)
(sb-ext:get-cas-expansion function))
(defsection @mutex-support (:title "Mutex Support")
"Mutexes are used for controlling access to a shared resource. One
thread is allowed to hold the mutex, others which attempt to take it
will be made to wait until it's free. Threads are woken in the order
that they go to sleep.
(defpackage :demo (:use \"CL\" \"SB-THREAD\" \"SB-EXT\"))
(in-package :demo)
(defvar *a-mutex* (make-mutex :name \"my lock\"))
(defun thread-fn ()
(format t \"Thread ~A running ~%\" *current-thread*)
(with-mutex (*a-mutex*)
(format t \"Thread ~A got the lock~%\" *current-thread*)
(sleep (random 5)))
(format t \"Thread ~A dropped lock, dying now~%\" *current-thread*))
(make-thread #'thread-fn)
(make-thread #'thread-fn)"
(sb-thread:mutex structure)
(sb-thread:with-mutex macro)
(sb-thread:with-recursive-lock macro)
(sb-thread:make-mutex function)
(sb-thread:mutex-name function)
(sb-thread:mutex-owner function)
(sb-thread:mutex-value function)
(sb-thread:grab-mutex function)
(sb-thread:release-mutex function))
(defsection @semaphores (:title "Semaphores")
"Semaphores are among other things useful for keeping track of a
countable resource, e.g. messages in a queue, and sleep when the
resource is exhausted."
(sb-thread:semaphore structure)
(sb-thread:make-semaphore function)
(sb-thread:signal-semaphore function)
(sb-thread:wait-on-semaphore function)
(sb-thread:try-semaphore function)
(sb-thread:semaphore-count function)
(sb-thread:semaphore-name function)
(sb-thread:semaphore-notification structure)
(sb-thread:make-semaphore-notification function)
(sb-thread:semaphore-notification-status function)
(sb-thread:clear-semaphore-notification function))
(defsection @waitqueue/condition-variables
(:title "Waitqueue/condition variables")
"These are based on the POSIX condition variable design, hence the
annoyingly CL-conflicting name. For use when you want to check a
condition and sleep until it's true. For example: you have a shared
queue, a writer process checking _queue is empty_ and one or more
readers that need to know when _queue is not empty_. It sounds
simple but is astonishingly easy to deadlock if another process runs
when you weren't expecting it to.
There are three components:
- the condition itself (not represented in code)
- the condition variable (a.k.a. waitqueue) which proxies for it
- a lock to hold while testing the condition
Important stuff to be aware of:
- when calling condition-wait, you must hold the mutex.
condition-wait will drop the mutex while it waits, and obtain it
again before returning for whatever reason;
- likewise, you must be holding the mutex around calls to
SB-THREAD:CONDITION-NOTIFY;
- a process may return from SB-THREAD:CONDITION-WAIT in several
circumstances: it is not guaranteed that the underlying condition
has become true. You must check that the resource is ready for
whatever you want to do to it.
(defvar *buffer-queue* (make-waitqueue))
(defvar *buffer-lock* (make-mutex :name \"buffer lock\"))
(defvar *buffer* (list nil))
(defun reader ()
(with-mutex (*buffer-lock*)
(loop
(condition-wait *buffer-queue* *buffer-lock*)
(loop
(unless *buffer* (return))
(let ((head (car *buffer*)))
(setf *buffer* (cdr *buffer*))
(format t \"reader ~A woke, read ~A~%\"
*current-thread* head))))))
(defun writer ()
(loop
(sleep (random 5))
(with-mutex (*buffer-lock*)
(let ((el (intern
(string (code-char
(+ (char-code #\A) (random 26)))))))
(setf *buffer* (cons el *buffer*)))
(condition-notify *buffer-queue*))))
(make-thread #'writer)
(make-thread #'reader)
(make-thread #'reader)"
(sb-thread:waitqueue structure)
(sb-thread:make-waitqueue function)
(sb-thread:waitqueue-name function)
(sb-thread:condition-wait function)
(sb-thread:condition-notify function)
(sb-thread:condition-broadcast function))
(defsection @barriers (:title "Barriers")
"These are based on the Linux kernel barrier design, which is in turn
based on the Alpha CPU memory model. They are presently implemented for
x86, x86-64, PPC, ARM64, and RISC-V systems, and behave as compiler
barriers on all other CPUs.
In addition to explicit use of the SB-THREAD:BARRIER macro, the
following functions and macros also serve as :MEMORY barriers:
- SB-EXT:ATOMIC-DECF, SB-EXT:ATOMIC-INCF, SB-EXT:ATOMIC-PUSH,
and SB-EXT:ATOMIC-POP
- SB-EXT:COMPARE-AND-SWAP
- SB-THREAD:GRAB-MUTEX, SB-THREAD:RELEASE-MUTEX,
SB-THREAD:WITH-MUTEX and SB-THREAD:WITH-RECURSIVE-LOCK
- SB-THREAD:SIGNAL-SEMAPHORE, SB-THREAD:TRY-SEMAPHORE and
SB-THREAD:WAIT-ON-SEMAPHORE
- SB-THREAD:CONDITION-WAIT, SB-THREAD:CONDITION-NOTIFY and
SB-THREAD:CONDITION-BROADCAST."
(sb-thread:barrier macro))
(defsection @sessions/debugging (:title "Sessions/Debugging")
"If the user has multiple views onto the same Lisp image (for example,
using multiple terminals, or a windowing system, or network access)
they are typically set up as multiple _sessions_ such that each view
has its own collection of foreground, background, and stopped
threads. A thread which wishes to create a new session can use
SB-THREAD:WITH-NEW-SESSION to remove itself from the current
session (which it shares with its parent and siblings) and create a
fresh one."
(sb-thread:with-new-session macro)
#-win32
(sb-thread:make-listener-thread function)
"Within a single session, threads arbitrate between themselves for
the user's attention. A thread may be in one of three notional
states: foreground, background, or stopped. When a background
process attempts to print a repl prompt or to enter the debugger, it
will stop and print a message saying that it has stopped. The user
at his leisure may switch to that thread to find out what it needs.
If a background thread enters the debugger, selecting any restart
will put it back into the background before it resumes. Arbitration
for the input stream is managed by calls to
SB-THREAD:GET-FOREGROUND (which may block) and
SB-THREAD:RELEASE-FOREGROUND."
(sb-thread:get-foreground function)
(sb-thread:release-foreground function))
(defsection @foreign-threads (:title "Foreign threads")
"Direct calls to `pthread_create(3)` (instead of SB-THREAD:MAKE-THREAD)
create threads that SBCL is not aware of, these are called foreign
threads. Currently, it is not possible to run Lisp code in such
threads. This means that the Lisp side signal handlers cannot work.
The best solution is to start foreign threads with signals blocked,
but since third party libraries may create threads, it is not always
feasible to do so. As a workaround, upon receiving a signal in a
foreign thread, SBCL changes the thread's sigmask to block all
signals that it wants to handle and resends the signal to the
current process which should land in a thread that does not block
it, that is, a Lisp thread.
The resignalling trick cannot work for synchronously triggered signals
(`SIGSEGV` and co), take care not to trigger any. Resignalling for
synchronously triggered signals in foreign threads is subject to
`--lose-on-corruption`, see @RUNTIME-OPTIONS.")
(defsection @implementation-on-linux-x86oids
(:title "Implementation on Linux x86oids")
"Threading is implemented using pthreads and some Linux specific bits
like futexes.
On x86, the per-thread local bindings for special variables is
achieved using the `%fs` segment register to point to a per-thread
storage area. This may cause interesting results if you link to
foreign code that expects threading or creates new threads, and the
thread library in question uses %fs in an incompatible way. On
x86-64 the r12 register has a similar role.
Queues require the `futex(2)` system call to be available: this is
the reason for the NPTL requirement. We test at runtime that this
system call exists.
Garbage collection is done with the existing Conservative
Generational GC. Allocation is done in small (typically 8k) regions:
each thread has its own region so this involves no stopping.
However, when a region fills, a lock must be obtained while another
is allocated, and when a collection is required, all processes are
stopped. This is achieved by sending them signals, which may make
for interesting behaviour if they are interrupted in system calls.
The streams interface is believed to handle the required system call
restarting correctly, but this may be a consideration when making
other blocking calls e.g. from foreign library code.
Large amounts of the SBCL library have not been inspected for
thread-safety. Some of the obviously unsafe areas have large locks
around them, so compilation and fasl loading, for example, cannot be
parallelized. Work is ongoing in this area.
A new thread by default is created in the same POSIX process group and
session as the thread it was created by. This has an impact on
keyboard interrupt handling: pressing your terminal's intr key
(typically `Control-C`) will interrupt all processes in the
foreground process group, including Lisp threads that SBCL considers
to be notionally _background_. This is undesirable, so background
threads are set to ignore the `SIGINT` signal.
`SB-THREAD:MAKE-LISTENER-THREAD` in addition to creating a new Lisp
session makes a new POSIX session, so that pressing `Control-C` in
one window will not interrupt another listener - this has been found
to be embarrassing.")

View file

@ -0,0 +1,41 @@
(in-package :sb-manual)
(defsection @timers (:title "Timers")
"SBCL supports a system-wide event scheduler implemented on top of
`setitimer(2)` that also works with threads but does not require a
separate scheduler thread.
The following example schedules a timer that writes `Hello, world`
after two seconds.
(schedule-timer (make-timer (lambda ()
(write-line \"Hello, world\")
(force-output)))
2)
It should be noted that writing timer functions requires special
care, as the dynamic environment in which they run is unpredictable:
dynamic variable bindings, locks held, etc, all depend on whatever
code was running when the timer fired. The following example should
serve as a cautionary tale:
(defvar *foo* nil)
(defun show-foo ()
(format t \"~&foo=~S~%\" *foo*)
(force-output t))
(defun demo ()
(schedule-timer (make-timer #'show-foo) 0.5)
(schedule-timer (make-timer #'show-foo) 1.5)
(let ((*foo* t))
(sleep 1.0))
(let ((*foo* :surprise!))
(sleep 2.0)))"
(sb-ext:timer structure)
(sb-ext:make-timer function)
(sb-ext:timer-name function)
(sb-ext:timer-scheduled-p function)
(sb-ext:schedule-timer function)
(sb-ext:unschedule-timer function)
(sb-ext:list-all-timers function))

View file

@ -0,0 +1,70 @@
(in-package :sb-manual)
;;;; Determining the package for parsing docstrings
;;;;
;;;; The package for parsing is the package that was in effect when
;;;; the docstring of the definition was read. This is basically the
;;;; nearest IN-PACKAGE above the definition in the sources.
;;;;
;;;; With these semantics, when editing a docstring in Slime, if M-.
;;;; works on an uppercase symbol name, then you can expect it to be
;;;; codified by MARKDOWN-TO-TEXINFO. For symbols without a
;;;; definition, you can use TAB-completion to check, but it's better
;;;; to actually load PAX and check (see
;;;; PAX::@BROWSING-LIVE-DOCUMENTATION).
;;; To avoid conflicting with PAX's heuristics, DOCSTRING-PACKAGE
;;; always returns a non-NIL package. We use a reimplementation of
;;; DREF-EXT:DEFINITION-PROPERTY for DREF-EXT:DOCSTRING*, which we
;;; feed to DOCSTRING-PACKAGE-OVERRIDES-TO-PAX in USE-PAX.
;;; These map the SYMBOL-PACKAGE of a definition's XREF-NAME to the
;;; docstring package.
(defparameter *package-to-docstring-package*
'(("COMMON-LISP" "SB-IMPL")
("SB-ACLREPL" "SB-ACLREPL")
("SB-ALIEN" "SB-ALIEN")
("SB-BSD-SOCKETS" "SB-BSD-SOCKETS")
("SB-CONCURRENCY" "SB-CONCURRENCY")
("SB-COVER" "SB-COVER")
("SB-DEBUG" "SB-DEBUG")
("SB-EXT" "SB-IMPL")
("SB-GRAY" "SB-GRAY")
("SB-GROVEL" "SB-GROVEL")
("SB-INTROSPECT" "SB-INTROSPECT")
("SB-MANUAL" "SB-MANUAL")
("SB-MD5" "SB-MD5")
("SB-POSIX" "SB-POSIX")
("SB-SEQUENCE" "SB-IMPL")
("SB-PROFILE" "SB-PROFILE")
("SB-ROTATE-BYTE" "SB-ROTATE-BYTE")
("SB-UNICODE" "SB-UNICODE")
("SB-SPROF" "SB-SPROF")
("SB-SYS" "SB-IMPL")
("SB-THREAD" "SB-THREAD")))
;;; The package-wide docstring packages are almost correct, but there
;;; are a couple of definitions in random files.
(defparameter *definition-to-docstring-package*
'(((with-compilation-unit macro) "SB-C")
((sb-ext:restrict-compiler-policy function) "SB-C")
((trace macro) "SB-DEBUG")))
;;; For when this file is recompiled in interactive development after
;;; a later, explicit call to USE-PAX
(eval-when (:load-toplevel :execute)
(when *using-pax*
(convert-docstring-package-overrides-to-pax)))
(defun docstring-package (xref)
(let* ((name (xref-name xref))
(key (list name (xref-locative xref))))
(or (find-package
(or (second (find key *definition-to-docstring-package*
:key #'first :test #'equal))
(when (symbolp name)
(second (find (package-name (symbol-package name))
*package-to-docstring-package*
:key #'first :test #'equal)))))
(assert nil () "Cannot determine package of the docstring of ~S."
xref))))

View file

@ -0,0 +1,5 @@
(in-package :sb-manual)
(eval-when (:load-toplevel :execute)
(when (find-package '#:mgl-pax)
(use-pax)))

View file

@ -0,0 +1,99 @@
;;;; Generate the SBCL manual in various formats in doc/manual/ with PAX
(eval-when (:compile-toplevel :load-toplevel :execute)
(require :mgl-pax/full)
(require :sb-manual))
(eval-when (:compile-toplevel :load-toplevel :execute)
(sb-manual::use-pax))
(in-package :sb-manual)
(defvar *git-forge-uri*)
(defvar *git-root*)
(defvar *output-dir*)
(defvar *directory* (truename (make-pathname :name nil :type nil
:defaults *load-truename*)))
(defun sbcl-pages* (format)
(let ((source-uri-fn (when (and (not (eq format :plain))
*git-forge-uri*)
(pax:make-git-source-uri-fn nil *git-forge-uri*
:git-root *git-root*)))
(output-file (ecase format
((:plain) "sbcl-manual.txt")
((:markdown) "sbcl-manual.md")
((:pdf) "sbcl-manual.pdf")
((:html) "html/sbcl-manual.html"))))
`((:objects (, @sbcl-manual)
:output (,(merge-pathnames output-file *output-dir*)
:if-does-not-exist :create
:if-exists :supersede
,@(when (eq format :pdf)
'(:element-type (unsigned-byte 8)))
:ensure-directories-exist t)
,@(when source-uri-fn
`(:source-uri-fn ,source-uri-fn))))))
;;; Adjust the width of section numbers in the PDF table of contents, so
;;; that e.g "17.10.13" doesn't protude from its box.
(defparameter *pandoc-pdf-adjusted-table-of-contents
"\\makeatletter
% \\@dottedtocline{level}{indent_before_number}{width_of_number_box}
\\renewcommand*\\l@subsection{\\@dottedtocline{2}{1.5em}{2.8em}}
\\renewcommand*\\l@subsubsection{\\@dottedtocline{3}{4.3em}{4.0em}}
\\makeatother")
(defun muffle-uninteresting-warnings (condition)
(let ((string (princ-to-string condition)))
;; We know that there is no source location for declarations.
(when (and (search "No source location" string)
(search "DECLARATION" string))
(muffle-warning condition))))
(defun make-pax-docs (&optional git-forge-uri)
(let ((*git-forge-uri* (or (and (plusp (length git-forge-uri))
git-forge-uri)
"https://github.com/sbcl/sbcl"))
(*git-root* (truename (merge-pathnames "../../" *directory*)))
(*output-dir* (merge-pathnames "output/" *directory*))
(pax:*document-downcase-uppercase-code* t)
(pax:*document-url-versions* '(1))
(pax:*document-pandoc-pdf-header-includes*
(format nil "~A~%~A~%"
pax:*document-pandoc-pdf-header-includes*
*pandoc-pdf-adjusted-table-of-contents))
(pax:*document-pandoc-pdf-options*
'(("-V" "papersize=a4")
("-V" "margin-left=0.8in")
("-V" "margin-right=0.8in")
("-V" "margin-top=1.0in")
("-V" "margin-bottom=1.0in")
("-V" "fontfamily=XCharter")
("-V" "fontsize=10pt")
("-V" "colorlinks=true")
("-V" "linkcolor=blue")
("-V" "urlcolor=Maroon")
("-V" "toccolor=blue")
#+nil
"--verbose")))
(handler-bind ((warning #'muffle-uninteresting-warnings))
(format t "Git root: ~A~%Git forge URI: ~A~%Output dir: ~A~%"
*git-root* *git-forge-uri* *output-dir*)
(format t "Generating manual in plain text format~%")
(pax:document @sbcl-manual :pages (sbcl-pages* :plain) :format :plain)
(format t "Generating manual in Markdown format~%")
(pax:document @sbcl-manual :pages (sbcl-pages* :markdown)
:format :markdown)
(format t "Generating manual in PDF format~%")
(pax:document @sbcl-manual :pages (sbcl-pages* :pdf) :format :pdf)
(format t "Generating manual in HTML format~%")
(pax:update-asdf-system-html-docs
@sbcl-manual "sb-manual"
:pages (sbcl-pages* :html)
:target-dir (merge-pathnames "html/" *output-dir*)
:style :charter))))
#+nil
(make-pax-docs)

View file

@ -0,0 +1,36 @@
#!/bin/sh
# This software is part of the SBCL system. See the README file for
# more information.
#
# This software is in the public domain and is provided with
# absolutely no warranty. See the COPYING and CREDITS files for
# more information.
BASE=`dirname "$0"`
git_forge_uri="$1"
if [ -z "$2" ] ; then
SBCL_TOP="$BASE/../.."
sbclsystem=$SBCL_TOP/src/runtime/sbcl
sbclcore=$SBCL_TOP/output/sbcl.core
if [ -f $sbclsystem ] && [ -f $sbclcore ]
then
SBCLRUNTIME="$sbclsystem --core $sbclcore"
SBCL_HOME=$SBCL_TOP/obj/sbcl-home/; export SBCL_HOME
else
SBCLRUNTIME="`command -v sbcl`"
fi
. $SBCL_TOP/output/build-config
else
SBCLRUNTIME="$2"
fi
# We *don't* add --no-sysinit and --no-userinit because we rely on the
# user to have set things up so that PAX can be loaded.
${SBCLRUNTIME} \
--noinform --noprint --disable-debugger \
--load ${BASE}/make-pax-docs.lisp \
--eval "(sb-manual::make-pax-docs \"${git_forge_uri}\")" \
--quit

View file

@ -0,0 +1,82 @@
(in-package :sb-manual)
(defsection @sb-manual (:title "sb-manual")
"The `SB-MANUAL` module has the SBCL user manual in forms
mimicking `PAX:DEFSECTION`:
(defsection @example (:title \"Example\")
\"This is an example, but see the real @SB-MANUAL.\"
(print function)
(@subexample section))
The names of the variables holding the documentation are exported
from the `SB-MANUAL` package. Since sections are basically
variables, in Slime, `\\\\M-.` on `\"@SB-MANUAL\"`, `\"print\"`, or
on `\"@subexample\"` will take you to the respective definition.
This makes it easy to navigate the documentation. Normal Lisp
definition docstrings and section docstrings reference sections
following the usual convention of uppercasing the name. Docstrings
are in a subset of Markdown and use very little markup in general,
so they are easy to read directly in the source.
The official manual in Info, HTML and PDF formats is generated via
Texinfo generated from these definitions."
(@using-pax section)
(@browsing-live-with-pax section)
(@fancy-documentation-with-pax section))
(defsection @using-pax (:title "Using \\PAX")
"However, `SB-MANUAL::DEFSECTION` is but a dummy implementation of
`PAX:DEFSECTION` to avoid a hard dependency on \\PAX.
See the `MGL-PAX` ASDF:SYSTEM or <https://github.com/melisgl/mgl-pax/>.
When \\PAX is loaded, the dummy `DEFSECTION` definitions are made
real, so that \\PAX can work with them."
(use-pax function))
(defsection @browsing-live-with-pax (:title "Browsing Live with \\PAX")
"With \\PAX, you can browse the manual live. The documentation of this
feature is available at
[online](https://melisgl.github.io/mgl-pax-world/pax-manual.html#MGL-PAX:@BROWSING-LIVE-DOCUMENTATION%20MGL-PAX:SECTION).
If you are browsing this manual live right now, here is the
equivalent live link: `PAX::@BROWSING-LIVE-DOCUMENTATION`.
Notable features:
- Autolinks within the manual: if SB-EXT:EXIT is mentioned, then
it's linked to its documentation. You basically get links to where
`\\\\M-.` would go in the sources.
- Autolinks to the \\CLHS.
- View the documentation of any Lisp definition or section without
generating the entire manual.
- Locatives (e.g. the `\"[function]\"` in `\"- [function]
SB-EXT:EXIT\"`) are also links in live browsing: they tell Slime
to visit the definition.
For this to work, you need to allow Slime to evaluate Elisp sent
from SBCL:
(setq slime-enable-evaluate-in-emacs t)
and maybe your window manager focus stealing configuration needs
tweaking as well.
Live browsing can greatly reduce the latency of Edit-Compile-View
Loop, when working on documentation.")
(defsection @fancy-documentation-with-pax
(:title "Fancy Documentation with \\PAX")
"\\PAX can generate dead documentation, too. In the SBCL sources,
`contrib/sb-manual/make-pax-docs.sh` generates the manual in plain
text, Markdown, PDF, and HTML formats. These differ from those
generated via Texinfo in that they are autolinked (like when
@BROWSING-LIVE-WITH-PAX).
Also, you can generate documentation yourself with e.g.
(pax:document sb-manual:@sbcl-manual :format :markdown)")

View file

@ -0,0 +1,897 @@
;;;; A Markdown-to-Texinfo converter for the SBCL manual.
;;;; This software is part of the SBCL software system. SBCL is in the
;;;; public domain and is provided with absolutely no warranty. See
;;;; the COPYING file for more information.
;;;;
;;;; Written by Rudi Schlatte <rudi@constantly.at>, mangled by
;;;; Nikodemus Siivola. Brought closer to Markdown, extended with
;;;; section linking and concept indexing by Gabor Melis.
(in-package :sb-manual)
(defvar *concept-keys-to-prepend*)
;;; MARKDOWN-TO-TEXINFO converts a strict subset of Markdown to
;;; Texinfo. It also codifies (marks up as code) and downcases
;;; uppercase symbols (those that actually exist in the image), and
;;; autolinks references to sections, attempting to approximate PAX
;;; semantics.
;;;
;;; Note that for writing docstrings, you need to know two more pieces:
;;;
;;; - See REINDENT-DOCSTRING for how the docstring relates to the
;;; Markdown string passed to MARKDOWN-TO-TEXINFO.
;;;
;;; - See DOCSTRING-PACKAGE to understand what *PACKAGE* is when
;;; MARKDOWN-TO-TEXINFO is called. This is package in effect when
;;; the docstring was READ. If it's wrong, you will see missed
;;; opportunities for codification and linking.
;;;
;;;
;;; Markdown Formatting
;;; -------------------
;;;
;;; The supported Markdown constructs are:
;;;
;;; - Emphasis: _italic_ -> @emph{italic}
;;;
;;; - Strong emphasis: __bold__ -> @strong{bold}
;;;
;;; - Inline code: `monospace` -> @code{monospace}
;;;
;;; - Itemized lists (like this one). List items can span multiple
;;; lines.
;;;
;;; - Nested lists are indented 4 spaces. A blank line is required
;;; before the first one.
;;;
;;; - Indented code blocks are indented with 4 extra spaces after a
;;; blank line:
;;;
;;; Like this:
;;;
;;; void main();
;;;
;;; - Fenced code blocks are indented at the normal level after a
;;; blank line:
;;;
;;; ```
;;; void main();
;;; ```
;;;
;;; Use fenced code blocks only when you have consecutive code
;;; blocks, which would be collapsed into a single code block when
;;; indented.
;;;
;;; - Blockquotes:
;;;
;;; > _Note_: They can span multiple lines and anything can be
;;; > nested in them. Rendered indented, typically with a vertical
;;; > bar on the left.
;;;
;;; - Note that ``abc'' is *not* supported and *will* screw up the
;;; rendering of the Markdown. This is because it's impossible to
;;; reconcile it with backticks: consider the possible semantics of
;;;
;;; ``x'' and ``y''
;;;
;;;
;;; Codification and Downcasing
;;; ---------------------------
;;
;;; Summary: Some text is automatically codified (e.g. FOO -> `FOO`)
;;; and most code is downcased.
;;;
;;; We approximate the semantics of PAX::@CODIFICATION with the
;;; settings PAX:*DOCUMENT-UPPERCASE-IS-CODE* and
;;; PAX:*DOCUMENT-DOWNCASE-UPPERCASE-CODE* both true.
;;;
;;; - Fully-qualified all-uppercase string representatation of symbols
;;; are codified (SB-EXT:CAS, :XYZ).
;;;
;;; - All-uppercase SYMBOL-NAMEs accessible in *PACKAGE*.
;;;
;;; - When at least 3 uppercase characters are followed by a lowercase
;;; character (e.g. SETFable), then the uppercase prefix is codified
;;; with the previous rules.
;;;
;;; When there is no corresponding symbol, the Markdown backtick
;;; syntax (`PRINT`) can be used to codify.
;;;
;;; When there are no lowercase nor #\" characters in inline code (as
;;; opposed to code blocks), be it auto-codified or explicitly
;;; backticked, it's downcased.
;;;
;;; When there is a corresponding symbol, but codification or
;;; downcasing should not happen, use backslash escapes.
;;;
;;; Escaping (following PAX::@OVERVIEW-OF-ESCAPING):
;;;
;;; PRINT -> @code{print} (Should be autolinked, unimplemented)
;;; \PRINT -> @code{print} (Prevent autolinking)
;;; \\PRINT -> PRINT (Prevent autolinking and codification)
;;; `PRINT` -> @code{print} (Should be autolinked, unimplemented)
;;; `\PRINT` -> @code{print} (Prevent autolinking)
;;; `\\PRINT` -> @code{PRINT} (Prevent autolinking and downcasing)
;;;
;;; Note that in docstrings, the backslashes need to be doubled.
;;;
;;;
;;; Linking
;;; -------
;;;
;;; - <http...> -> @url{http...}
;;;
;;; - [label](uri) -> @uref{uri, label}
;;;
;;; - [label][id] -> label
;;;
;;; This just strips Markdown reference links. These are used by
;;; PAX to disambiguate, e.g. "[FUNCTION][type]" links to the
;;; FUNCTION class only while FUNCTION links to both the class and
;;; macro.
;;;
;;; - SECTION references (see DEFSECTION):
;;;
;;; @SECTION-NAME -> @ref{<section name>}
;;;
;;; - CONCEPT references (see DEFINE-CONCEPT):
;;;
;;; - pure concept: @CONCEPT-NAME -> "" (no output)
;;; - titled concept: @CONCEPT-NAME -> <title>
;;;
;;; TODO:
;;;
;;; - Maybe implement glossary-terms (for books, "safe type", etc).
;;;
;;; Also, see SB-PCL::NORMALIZE-SBCL-DOCSTRING, an expedient docstring
;;; to plain text converter that supports the subset of this
;;; functionality necessary for the docstrings in SBCL core.
(defun markdown-to-texinfo (string &optional lambda-list)
(let ((*texinfo-local-variables* (flatten lambda-list))
(lines (string-lines string))
(line-number 0)
(current-paragraph nil))
(declare (special *texinfo-local-variables*))
(flet ((flush-paragraph ()
(when current-paragraph
(let* ((*concept-keys-to-prepend* ())
(string (process-inline-markdown
(format nil "~{~A~^~%~}"
(nreverse current-paragraph)))))
(write-concept-keys *concept-keys-to-prepend* t)
(write-string string))
(terpri)
(setf current-paragraph nil))))
(loop while (< line-number (length lines))
for line = (svref lines line-number)
do (let ((*concept-keys-to-prepend* ()))
(multiple-value-bind (count collected)
(parse-markdown-block lines line-number 0)
(cond
(count
(flush-paragraph)
(write-concept-keys *concept-keys-to-prepend* t)
(dolist (c collected)
(write-line c))
(incf line-number count))
((blankp line)
(flush-paragraph)
(write-line line)
(incf line-number))
(t
(push line current-paragraph)
(incf line-number))))))
(flush-paragraph))))
;;;; Utilities
(defun flatten (list)
(cond ((null list)
nil)
((consp (car list))
(nconc (flatten (car list)) (flatten (cdr list))))
((null (cdr list))
(cons (car list) nil))
(t
(cons (car list) (flatten (cdr list))))))
(defun flatten-to-string (list)
(format nil "~{~A~^-~}" (flatten list)))
(defun internedp (symbol-name package)
(nth-value 1 (find-symbol symbol-name package)))
(defun external-symbol-p (symbol &optional (package (symbol-package symbol)))
(and package
(multiple-value-bind (symbol* status)
(find-symbol (symbol-name symbol) package)
(and (eq status :external)
(eq symbol symbol*)))))
;;;; Texinfo escaping
(defparameter *texinfo-special-chars* "@{}")
(defun escape-texinfo (string)
(with-output-to-string (s)
(loop for char across string
do (when (find char *texinfo-special-chars*)
(write-char #\@ s))
(write-char char s))))
(defun unescape-texinfo (string)
(with-output-to-string (s)
(let ((prev-escape-p nil))
(loop for char across string
do (cond (prev-escape-p
(write-char char s)
(setq prev-escape-p nil))
((char= char #\@)
(setq prev-escape-p t))
(t
(write-char char s)))))))
(progn
(assert (equal (escape-texinfo "@code{x}") "@@code@{x@}"))
(assert (equal (unescape-texinfo "@@code@{x@}") "@code{x}")))
;;;; Codification (following PAX::@CODIFICATION)
(defvar *lower-case-chars* "abcdefghijklmnopqrstuvwxyz")
(defun codifiable-bounds (word)
(when (codifiable-word-p word)
;; PAX::@NAMES-IN-RAW-NAMES is involved. We only try two simple
;; cases to get a PAX::@NAME.
(flet ((try-name (start end)
(let ((name (subseq word start end)))
(multiple-value-bind (symbol foundp)
(read-symbol-without-interning name)
(when (and foundp (interesting-name-p word symbol))
(return-from codifiable-bounds (values start end)))))))
;; 1. Trim the lower-case characters
(let* ((name (string-left-trim *lower-case-chars* word))
(name-start (- (length word) (length name)))
(name (string-right-trim *lower-case-chars* name))
(name-end (+ name-start (length name))))
(try-name name-start name-end))
;; 2. Find the upper-case core
(multiple-value-bind (name-start name-end) (uppercase-core-bounds word)
(when name-start
(try-name name-start name-end))))))
(defun codifiable-word-p (string)
(uppercase-core-bounds string))
(defun read-symbol-without-interning (string)
(if (and (plusp (length string))
(char= (aref string 0) #\:))
(find-symbol (subseq string 1) :keyword)
(let ((pos (position #\: string)))
(if pos
(let* ((package-name (subseq string 0 pos))
(symbol-name (subseq string (1+ pos)))
(double-colon-p
(and (plusp (length symbol-name))
(char= (aref symbol-name 0) #\:))))
(when double-colon-p
(setq symbol-name (subseq symbol-name 1)))
(if package-name
(when (find-package package-name)
(multiple-value-bind (symbol status)
(find-symbol symbol-name package-name)
(when (or double-colon-p
(eq status :external))
(values symbol status))))
(find-symbol symbol-name *package*)))
(find-symbol string *package*)))))
;;; Approximating PAX::@INTERESTING. This is only called when we
;;; already found the interned SYMBOL.
(defun interesting-name-p (word symbol)
(or (<= 3 (length word))
(external-symbol-p symbol)
(has-local-reference-p symbol)))
(defun uppercase-core-bounds (string)
(let* ((first-uppercase-pos (position-if #'upper-case-p string))
(last-uppercase-pos (position-if #'upper-case-p string
:from-end t)))
(when (and first-uppercase-pos
(if (= last-uppercase-pos first-uppercase-pos)
(notany #'lower-case-p string)
(not (find-if #'lower-case-p string
:start (1+ first-uppercase-pos)
:end last-uppercase-pos))))
(values first-uppercase-pos (1+ last-uppercase-pos)))))
(defvar *texinfo-local-variables* ())
(defun has-local-reference-p (name)
(find name *texinfo-local-variables*))
#+nil
(progn
(assert (equal (multiple-value-list (codifiable-bounds "PRINT"))
'(0 5)))
(assert (equal (multiple-value-list (codifiable-bounds "T"))
'(0 1)))
(if (internedp "A" *package*)
(assert (equal (multiple-value-list (codifiable-bounds "A"))
'(0 1)))
(assert (null (codifiable-bounds "A"))))
(assert (equal (multiple-value-list (codifiable-bounds "*FEATURES*"))
'(0 10))))
;;; We parse words (e.g. nonREADable) and find symbols in them.
(defparameter *word-characters*
(format nil "abcdefghijklmnopqrstuvwxyz~
ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~
*~~@:-+&=<>#'"))
(defparameter *word-delimiters* " ',.!?;()[]{}")
;;; Return a list of index pairs of symbol-like parts of LINE.
(defun locate-symbols (line)
(let (result)
(flet ((grab (word-start word-end)
(let ((word (subseq line word-start word-end)))
(multiple-value-bind (name-start name-end)
(codifiable-bounds word)
(when name-start
(push (list (+ word-start name-start)
(+ word-start name-end))
result)))))
(got-symbol-p (start)
(let ((end (when (< start (length line))
(position-if (lambda (c)
(or (whitespacep c)
(find c *word-delimiters*)))
line :start start))))
(when end
(every (lambda (char) (find char *word-characters*))
(subseq line start end))))))
(do ((begin nil)
(maybe-begin t)
(i 0 (1+ i)))
((>= i (length line))
;; symbol at end of line
(when begin
(grab begin i))
(nreverse result))
(cond
((and begin
(or (whitespacep (char line i))
(find (char line i) *word-delimiters*)
;; For e.g. "T:"
(and (char= (char line i) #\:)
(or (= (1+ i) (length line))
(whitespacep (char line (1+ i)))))))
;; symbol end
(grab begin i)
(setf begin nil
maybe-begin t))
((and begin (not (find (char line i) *word-characters*)))
;; Not a symbol: abort
(setf begin nil))
((and maybe-begin (not begin)
(find (char line i) *word-characters*))
;; potential symbol begin at this position
(setf begin i
maybe-begin nil))
((or (whitespacep (char line i))
(find (char line i) *word-delimiters*))
;; potential symbol begin after this position
(setf maybe-begin t))
((and (eql #\( (char line i)) (got-symbol-p (1+ i)))
;; a type designator, or a function call as part of the text?
(multiple-value-bind (exp end)
(let ((*package* (find-package :cl-user)))
(ignore-errors (read-from-string line nil nil :start i)))
(when exp
(grab i end)
(setf begin nil
maybe-begin nil
i (1- end)))))
(t
;; Not reading a symbol, not at potential start of symbol
(setf maybe-begin nil)))))))
(unwind-protect
(progn
(defsection @test-section (:title "test section"))
(defsection @test5 (:title "Test5"))
(assert (equal (locate-symbols "PRINT") '((0 5))))
(assert (equal (locate-symbols "CL:PRINT") '((0 8))))
(assert (equal (locate-symbols "*FEATURES*") '((0 10))))
(assert (equal (locate-symbols "SETFable") '((0 4))))
(assert (equal (locate-symbols "SETF-able") '((0 4))))
(assert (equal (locate-symbols "nonREADable") '((3 7))))
(assert (equal (locate-symbols "NOSUCHSYMBOL-able") '()))
(assert (equal (locate-symbols "ASDF-like") '()))
(assert (equal (locate-symbols "@TEST-SECTION") '((0 13))))
(assert (equal (locate-symbols "SB-MANUAL:@TEST-SECTION") '((0 23))))
(assert (equal (locate-symbols "@NOSUCHSECTION") '()))
(assert (equal (locate-symbols "@TEST5") '((0 6))))
(assert (equal (locate-symbols ":IR1-CONVERT") '((0 12)))))
(makunbound '@test-section)
(makunbound '@test5))
;;;; Processing Markdown inline elements
;;; Format symbols either as Texinfo @code{}, link sections, and
;;; handle concepts.
(defun codify-and-link (line)
(with-output-to-string (result)
(let ((last 0))
(dolist (symbol/index (locate-symbols line))
;; Flush unwritten text since the end of the previous symbol.
(write-string (escape-texinfo (subseq line last
(first symbol/index)))
result)
(let* ((symbol-name (apply #'subseq line symbol/index))
(symbol (read-from-string symbol-name)))
(cond ((doc-name-p symbol :section)
(format result "@ref{~A}"
(texinfo-node-id (symbol-value symbol))))
((doc-name-p symbol :concept)
(let* ((concept (symbol-value symbol))
(title (doctitle concept)))
(when title
(format result "~A" (escape-texinfo title)))
(setq *concept-keys-to-prepend*
(append *concept-keys-to-prepend*
(multiplexing-concept-keys concept)))))
(t
;; We could use for @var{} if
;; (HAS-LOCAL-REFERENCE-P SYMBOL).
(format result "@code{~A}"
(escape-texinfo (maybe-downcase symbol-name))))))
(setf last (second symbol/index)))
(write-string (escape-texinfo (subseq line last)) result))))
(defun write-concept-keys (keys stream)
(dolist (key (remove-duplicates keys :test #'equal))
(typecase key
(list
;; We don't use @subentry because with it Texinfo always
;; presents it as as hierarchical list even if it has only one
;; branch.
(format stream "~&@cindex~{ ~A~}~%" key))
(symbol
(assert (and (boundp key)
(typep (symbol-value key) (dummy 'concept)))
() "Variable ~S does not hold a concept." key)
(write-concept-keys (concept-keys (symbol-value key)) stream))
(t
(format stream "~&@cindex ~A~%" key)))))
(defvar *downcase-uppercase-code* t)
(defun maybe-downcase (string)
(if *downcase-uppercase-code*
(string-downcase string)
string))
(defun texinfo-node-id (section)
(let ((name (symbol-name (section-name section))))
(assert (char= (char name 0) #\@))
(let ((name (subseq name 1)))
(assert (null (find-if (lambda (char)
(find char *texinfo-special-chars*))
name))
() "Section name ~S contains special texinfo characters." name)
(substitute #\Space #\- (string-downcase name)))))
(when (and (not *using-pax*)
*downcase-uppercase-code*)
(defsection @test-section (:title "Test Section"))
(unwind-protect
(progn
(assert (equal (codify-and-link "@TEST-SECTION") "@ref{test section}"))
(assert (equal (codify-and-link "@NOSUCHSECTION") "@@NOSUCHSECTION"))
(assert (equal (codify-and-link ":START") "@code{:start}"))
(assert (equal (codify-and-link "[:START") "[@code{:start}"))
(assert (equal (codify-and-link "{:START") "@{@code{:start}")))
(makunbound '@test-section)))
;;; Translate backticks, emphasis and codification escapes, while
;;; delegating normal text to CODIFY-AND-LINK.
(defun process-inline-markdown (string)
(let ((len (length string))
(i 0)
(codifiable-buffer (make-string-output-stream))
(out (make-string-output-stream)))
(labels ((out (string)
(write-string string out))
(out-escaped (string)
(out (escape-texinfo (string string))))
(buffer-codifiable-char (char)
(write-char char codifiable-buffer))
(flush-codifiable-buffer ()
(let ((codifiable (get-output-stream-string codifiable-buffer)))
(when (plusp (length codifiable))
(out (codify-and-link codifiable))))))
(loop while (< i len)
for char = (char string i)
do (cond
;; Escapes: \FOO
((char= char #\\)
(flush-codifiable-buffer)
(incf i)
(when (< i len)
(out-escaped (char string i))
(incf i)
;; Protect the rest of the contiguous word from
;; CODIFY-AND-LINK.
(loop
while (and (< i len)
(not (or (whitespacep (char string i))
(find (char string i)
",.!?;()'[]{}\""))))
do (out-escaped (char string i))
(incf i))
(decf i)))
;; Backticks: `CODE` with PAX downcasing and escape rules
((char= char #\`)
(flush-codifiable-buffer)
(incf i)
(let ((code-buffer (make-string-output-stream)))
(loop while (and (< i len) (char/= (char string i) #\`))
do (write-char (char string i) code-buffer)
(incf i))
(let* ((code-str (get-output-stream-string code-buffer))
(slash-count (loop for c across code-str
while (char= c #\\)
count t))
;; Consume up to 2 leading backslashes as PAX escapes
(actual-code (subseq code-str (min slash-count 2))))
(out "@code{")
(if (< slash-count 2)
;; 0 or 1 backslash: Downcase if there are
;; no lowercase letters (1 backslash turns
;; off autolinking, which is naturally
;; handled by bypassing CODIFY-AND-LINK).
(if (and (not (find-if #'lower-case-p actual-code))
(not (find #\" actual-code)))
(out-escaped (maybe-downcase actual-code))
(out-escaped actual-code))
;; 2 backslashes turn off autolinking AND downcasing.
(out-escaped actual-code))
(out "}"))))
;; Strong emphasis: __foo__ -> @strong{foo}
((and (char= char #\_)
(< (1+ i) len)
(char= (char string (1+ i)) #\_))
(let ((close-pos (search "__" string :start2 (+ i 2))))
(if close-pos
(progn
(flush-codifiable-buffer)
(format out "@strong{~A}"
(process-inline-markdown
(subseq string (+ i 2) close-pos)))
(setf i (+ close-pos 1)))
(buffer-codifiable-char char))))
;; Emphasis: _foo_ -> @emph{foo}
((char= char #\_)
(let ((close-pos nil)
(j (1+ i)))
(loop while (< j len)
do (if (char= (char string j) #\_)
(if (and (< (1+ j) len)
(char= (char string (1+ j)) #\_))
;; Skip double underscores so
;; they don't falsely close a
;; single underscore.
(incf j 2)
(progn
(setf close-pos j)
(return)))
(incf j)))
(if close-pos
(progn
(flush-codifiable-buffer)
(format out "@emph{~A}"
(process-inline-markdown
(subseq string (1+ i) close-pos)))
(setf i close-pos))
(buffer-codifiable-char char))))
;; Markdown autolinks: <http...> -> @url{http...}
((and (char= char #\<)
(<= (+ i 5) len)
(string-equal string "http" :start1 (1+ i)
:end1 (+ i 5)))
(let ((close-pos (position #\> string :start (1+ i))))
(if close-pos
(progn
(flush-codifiable-buffer)
(out "@url{")
(out-escaped (subseq string (1+ i) close-pos))
(out "}")
(setf i close-pos))
(buffer-codifiable-char char))))
;; Markdown explicit links: [label](url) -> @uref{url, label}
;;
;; Markdown reflinks: [label][id] -> label
((char= char #\[)
(let* ((close-bracket (position #\] string :start (1+ i)))
(next-char (when (and close-bracket
(< (1+ close-bracket) len))
(char string (1+ close-bracket))))
(open-paren (when (eql next-char #\()
(1+ close-bracket)))
(close-paren (when open-paren
(position #\) string
:start (1+ open-paren))))
(open-bracket2 (when (eql next-char #\[)
(1+ close-bracket)))
(close-bracket2
(when open-bracket2
(position #\] string :start (1+ open-bracket2)))))
(cond
;; Explicit link: [label](url)
(close-paren
(flush-codifiable-buffer)
(out "@uref{")
(out-escaped (subseq string (1+ open-paren)
close-paren))
(out ", ")
(out (process-inline-markdown
(subseq string (1+ i) close-bracket)))
(out "}")
(setf i close-paren))
;; Reflink: [label][id]
(close-bracket2
(flush-codifiable-buffer)
;; Process the name, drop the id
(out (process-inline-markdown
(subseq string (1+ i) close-bracket)))
(setf i close-bracket2))
;; Not a recognized link structure, treat as a
;; normal character
(t
(buffer-codifiable-char char)))))
(t
(buffer-codifiable-char char)))
(incf i))
(flush-codifiable-buffer)
(get-output-stream-string out))))
(when *downcase-uppercase-code*
(assert (equal (process-inline-markdown "`abc`") "@code{abc}"))
(assert (equal (process-inline-markdown "_abc_") "@emph{abc}"))
(assert (equal (process-inline-markdown "__abc__") "@strong{abc}"))
(assert (equal (process-inline-markdown "_PRINT_") "@emph{@code{print}}"))
(assert (equal (process-inline-markdown "<httpabc>") "@url{httpabc}"))
(assert (equal (process-inline-markdown "`N`") "@code{n}"))
(assert (equal (process-inline-markdown "`N`th") "@code{n}th"))
(assert (equal (process-inline-markdown "[x](uri)") "@uref{uri, x}"))
(assert (equal (process-inline-markdown "[`x`](uri)") "@uref{uri, @code{x}}"))
(assert (equal (process-inline-markdown "[function][type]") "function"))
(assert (equal (process-inline-markdown "[`function`][type]")
"@code{function}")))
;;;; Processing Markdown block elements
;;; Collect lines enclosed in Markdown ``` fences. Returns the number
;;; of lines consumed and a list of lines.
(defun collect-fenced-code (lines starting-line base-indent)
(let* ((first-line (svref lines starting-line))
(trimmed (string-left-trim " " first-line)))
(when (and (>= (length trimmed) 3)
(string= (subseq trimmed 0 3) "```"))
(let ((lang (string-trim " " (subseq trimmed 3)))
(consumed 1)
(result nil))
(loop for index from (1+ starting-line) below (length lines)
for line = (svref lines index)
for line-trimmed = (string-left-trim " " line)
do (incf consumed)
if (and (>= (length line-trimmed) 3)
(string= (subseq line-trimmed 0 3) "```"))
do (loop-finish) ; Closing fence found
else
;; Strip up to the base indentation of the environment
do (push (if (and (indentation line)
(>= (indentation line) base-indent))
(subseq line base-indent)
line)
result))
(let ((env (if (string-equal lang "lisp") "lisp" "example")))
(values consumed
`(,(format nil "@~A" env)
,@(mapcar #'escape-texinfo (nreverse result))
,(format nil "@end ~A" env))))))))
;;; Collect lines that start with a Markdown blockquote marker (">").
;;; A blockquote must be preceded by a blank line or be the first
;;; line. The marker can be indented up to 3 characters on top of
;;; BASE-INDENT. By leveraging string streams and passing the stripped
;;; content recursively back to MARKDOWN-TO-TEXINFO, we maintain full
;;; support for nested blocks, lists, and inline text wrapping.
(defun collect-blockquote (lines starting-line base-indent)
(unless (and (> starting-line 0)
(not (blankp (svref lines (1- starting-line)))))
(let* ((first-line (svref lines starting-line))
(first-indent (indentation first-line)))
(when (and first-indent
(<= first-indent (+ base-indent 3))
(< first-indent (length first-line))
(char= (char first-line first-indent) #\>))
(let ((n-lines 0)
(stripped-lines nil))
(loop for index from starting-line below (length lines)
for line = (svref lines index)
for indent = (indentation line)
do (cond
((and indent
(<= indent (+ base-indent 3))
(< indent (length line))
(char= (char line indent) #\>))
(let* ((start (1+ indent))
(content-start
(if (and (< start (length line))
(char= (char line start) #\Space))
(1+ start)
start)))
(push (subseq line content-start) stripped-lines)
(incf n-lines)))
(t
(loop-finish))))
;; Trim trailing empty lines
(loop while (and stripped-lines (string= (car stripped-lines) ""))
do (pop stripped-lines) (decf n-lines))
(when stripped-lines
(let ((inner-texinfo
;; Process the stripped sub-document cleanly using
;; the main loop to handle paragraphs, nesting,
;; and formatting automatically.
(with-output-to-string (*standard-output*)
(markdown-to-texinfo
(format nil "~{~A~^~%~}" (nreverse stripped-lines))
*texinfo-local-variables*))))
(values n-lines
`("@quotation"
,@(coerce (string-lines inner-texinfo) 'list)
"@end quotation")))))))))
;;; Collect lines indented with an extra 4 character on top of
;;; BASE-INDENT. An indented code block must be preceeded by a blank
;;; line or be the first line.
(defun collect-indented-code (lines starting-line base-indent)
(unless (and (> starting-line 0)
(not (blankp (svref lines (1- starting-line)))))
(let ((indent (indentation (svref lines starting-line))))
(when (and indent (>= indent (+ base-indent 4)))
(let ((n-lines 0)
(result nil))
(loop for index from starting-line below (length lines)
for line = (svref lines index)
for line-indent = (indentation line)
do (cond
((blankp line)
;; Blank lines are allowed inside indented code blocks.
(push "" result)
(incf n-lines))
((>= line-indent (+ base-indent 4))
(push (subseq line (+ base-indent 4)) result)
(incf n-lines))
(t
;; Indentation dropped, so the code block ends.
(loop-finish))))
;; Trim trailing empty lines.
(loop while (and result (string= (car result) ""))
do (pop result) (decf n-lines))
(if result
(values n-lines `("@example"
,@(mapcar #'escape-texinfo (nreverse result))
"@end example"))
nil))))))
;;; Return the indent if the line starts with a Markdown list marker
;;; (#\- or \*) followed by a space.
(defun maybe-itemize-offset (line)
(let ((indent (indentation line)))
(when indent
(let ((trimmed (string-left-trim " " line)))
(when (and (>= (length trimmed) 2)
(member (char trimmed 0) '(#\- #\*))
(char= (char trimmed 1) #\Space))
indent)))))
;;; Collect a bulleted list.
(defun collect-markdown-itemize (lines starting-line base-indent)
(let ((this-offset (maybe-itemize-offset (svref lines starting-line))))
(when (and this-offset (= this-offset base-indent))
(let ((result nil)
(lines-consumed 0)
(child-base (+ base-indent 4))
(current-paragraph nil)
(item-pending-p nil))
(flet ((flush-paragraph ()
(if current-paragraph
(let ((processed (process-inline-markdown
(format nil "~{~A~^~%~}"
(nreverse current-paragraph)))))
(if item-pending-p
(push (format nil "@item ~A" processed) result)
(push processed result))
(setf current-paragraph nil)
(setf item-pending-p nil))
(when item-pending-p
(push "@item" result)
(setf item-pending-p nil)))))
(loop for line-number = starting-line then (+ starting-line
lines-consumed)
while (< line-number (length lines))
for line = (svref lines line-number)
for indent = (indentation line)
for offset = (maybe-itemize-offset line)
do (cond
((blankp line)
;; Blank lines inside lists are buffered
(flush-paragraph)
(push "" result)
(incf lines-consumed))
;; New Item in the same list
((and offset (= offset base-indent))
(flush-paragraph)
(setf item-pending-p t)
(let ((item-text (subseq line (+ offset 2))))
(unless (blankp item-text)
(push item-text current-paragraph)))
(incf lines-consumed))
;; Indented block/text inside the list item (>= 4 spaces)
((and indent (>= indent child-base))
(flush-paragraph)
(multiple-value-bind (sub-consumed sub-result)
(parse-markdown-block lines line-number child-base)
(if sub-consumed
(progn
(setf result (append (reverse sub-result) result))
(incf lines-consumed sub-consumed))
;; Fallback: normal text continuing the item body
(progn
(push (subseq line child-base) current-paragraph)
(incf lines-consumed)))))
;; Normal text continuing the item body
((and indent (> indent base-indent))
(push line current-paragraph)
(incf lines-consumed))
;; If we get here, the line is NOT a new bullet,
;; and it less than 4 spaces of relative
;; indentation, so the list is over.
(t
(loop-finish))))
(flush-paragraph)
;; Trim trailing empty lines, so they return to the outer scope.
(loop while (and result (string= (car result) ""))
do (pop result) (decf lines-consumed))
(values lines-consumed `("@itemize" ,@(reverse result)
"@end itemize")))))))
;;; Parse the line at INDEX in LINES as a Markdown block. Return the
;;; number of lines consumed and the parse.
(defun parse-markdown-block (lines index base-indent)
(let ((line (svref lines index)))
(multiple-value-bind (n-lines-consumed result)
(collect-fenced-code lines index base-indent)
(when n-lines-consumed
(return-from parse-markdown-block (values n-lines-consumed result))))
(multiple-value-bind (n-lines-consumed result)
(collect-blockquote lines index base-indent)
(when n-lines-consumed
(return-from parse-markdown-block (values n-lines-consumed result))))
(cond
((and (indentation line) (>= (indentation line) (+ base-indent 4)))
(collect-indented-code lines index base-indent))
((maybe-itemize-offset line)
(collect-markdown-itemize lines index (maybe-itemize-offset line)))
(t nil))))

View file

@ -0,0 +1,9 @@
(locally (declare (sb-ext:muffle-conditions sb-int:package-at-variance))
(handler-bind ((sb-int:package-at-variance #'muffle-warning))
(defpackage :sb-manual
(:use :cl :sb-alien)
(:export #:use-pax)
#+sb-doc
(:import-from #:sb-pcl
#:string-lines #:whitespacep #:indentation #:blankp
#:reindent-docstring))))

329
contrib/sb-manual/pax.lisp Normal file
View file

@ -0,0 +1,329 @@
;;;; PAX stubs
;;;;
;;;; Contribs cannot depend on external libraries, so we fake as much
;;;; of PAX and DRef as necessary. USE-PAX switches to the real
;;;; implementation.
;;;;
;;;; If PAX is not loaded, the dummy DEFSECTION below still gives us
;;;; the ability to use M-. on section names in docstrings as they are
;;;; just variables, which makes navigating the documentation faster.
;;;;
;;;; When PAX is loaded, we have PAX::@BROWSING-LIVE-DOCUMENTATION for
;;;; low-latency, interactive documentation work and
;;;; PAX::@GENERATING-DOCUMENTATION for autolinked documentation
;;;; (also, see make-pax-docs.sh and http://fixnum.com).
;;;;
;;;; For browsing, use this setup:
;;;;
;;;; (setq pax:*document-downcase-uppercase-code* t
;;;; pax:*browse-context* :pax-world)
(in-package :sb-manual)
(eval-when (:compile-toplevel :load-toplevel :execute)
(defvar *using-pax* nil)
;; A list of (LOCAL-SYMBOL PACKAGE) elements. Originally,
;; LOCAL-SYMBOL has home package SB-MANUAL. For example, the element
;; (SECTION :PAX) causes PAX:SECTION to be SHADOWING-IMPORTed in
;; USE-PAX.
(defvar *dummies* ()))
(defmacro defun-dummy ((name package) lambda-list &body body)
`(eval-when (:compile-toplevel :load-toplevel :execute)
(pushnew '(,name ,package) *dummies* :test #'equal)
(declaim (notinline ,name))
(unless *using-pax*
(defun ,name ,lambda-list ,@body))))
(defmacro defmacro-dummy ((name package) lambda-list &body body)
(unless *using-pax*
`(eval-when (:compile-toplevel :load-toplevel :execute)
(pushnew '(,name ,package) *dummies* :test #'equal)
(unless *using-pax*
(defmacro ,name ,lambda-list ,@body)))))
(defparameter *extra-dummies*
'((argument :pax)
(macro :dref)
(setf-function :dref)
(setf-generic-function :dref)
(section :pax)
(concept :pax)
(clhs :pax)
(docstring :dref)))
(defun dummy (symbol)
(let ((*package* (find-package :sb-manual)))
(read-from-string (symbol-name symbol))))
;;; We might want to populate this with GUESS-PACKAGE-FROM-ARGLIST.
(defvar *definition-to-docstring-package*)
(defvar *package-to-docstring-package*)
(defun resolve-lazy-doc (&rest args)
(declare (ignore args))
(use-pax))
(defun lazy-doc-name-p (symbol &optional kind)
(when (boundp symbol)
(let ((value (symbol-value symbol)))
(and (listp value)
(listp (first value))
(eq (caar value) :%pax-lazy-doc)
(or (null kind)
(eq (third (first value)) kind))))))
(defun use-pax ()
"Ensure that exported variables are `PAX:SECTION`s.
It is an error if the `MGL-PAX` library is not loaded.
Calling this function explicitly is rarely necessary because it is
called automatically:
- when `SB-MANUAL` is loaded, if PAX is present;
- when `PAX:DOCUMENT` (more precisely, `DREF:LOCATE`) is called on
an `SB-MANUAL` section.
The latter feature requires v0.4.12 of PAX. See the `MGL-PAX`
asdf:system."
(unless *using-pax*
(assert (find-package '#:mgl-pax) ()
"The MGL-PAX package does not exist. Load PAX first.")
;; Replace dummies with the real symbols.
(loop for (name package) in (append *dummies* *extra-dummies*)
do (let ((new-symbol (read-from-string
(format nil "~A::~A" package name))))
(when (and (fboundp new-symbol)
(null (macro-function new-symbol)))
(setf (fdefinition name) (fdefinition new-symbol)))
(shadowing-import new-symbol :sb-manual)))
;; Ensure PAX:DEFSECTION exports only SECTIONs.
(eval-string
"(defmethod pax:exportable-reference-p
((package (eql (find-package 'sb-manual)))
symbol locative-type locative-args)
(eq locative-type 'section))")
;; Reevaluate DEFSECTION and DEFINE-CONCEPT forms with PAX.
(do-symbols (symbol :sb-manual)
(when (lazy-doc-name-p symbol)
(let ((value (symbol-value symbol))
(source-location
(sb-int:info :source-location :variable symbol)))
(eval (subst-dummies (second value)))
(setf (sb-int:info :source-location :variable symbol)
source-location))))
(convert-docstring-package-overrides-to-pax)
(eval-string
"(pax:register-doc-in-pax-world
'sb-manual:@sbcl-manual @sbcl-manual
`((:objects
(, @sbcl-manual)
:source-uri-fn ,(pax:make-git-source-uri-fn
nil \"https://github.com/sbcl/sbcl\"
:git-root (asdf:system-relative-pathname
:sb-manual \"../../../\")))))")
(setq *using-pax* t)))
;;; Convert *DEFINITION-TO-DOCSTRING-PACKAGE* to
;;; DREF:DEFINITION-PROPERTIES and *PACKAGE-TO-DOCSTRING-PACKAGE* to
;;; DREF:DEFINITION-PROPERTIES. See DREF-EXT:DOCSTRING*.
(defun convert-docstring-package-overrides-to-pax ()
(loop for ((name locative) package) in *definition-to-docstring-package*
do (eval-format
"(setf (dref-ext:definition-property (dref:xref '~S '~S)~
'docstring)
(list nil (find-package ~S)))"
name (subst-dummies locative) package))
(setq *definition-to-docstring-package*
(subst-dummies *definition-to-docstring-package*))
(loop for (from-package to-package) in *package-to-docstring-package*
do (eval-format
"(setf (dref-ext:definition-property `(:package ,(find-package ~S))
'docstring)
(list nil (find-package ~S)))"
from-package to-package)))
(defun eval-string (string)
(let ((*package* (find-package :sb-manual)))
(eval (read-from-string string))))
(defun eval-format (format-control &rest format-args)
(let ((*package* (find-package :sb-manual)))
(eval (read-from-string (apply #'format nil format-control format-args)))))
(defun subst-dummies (tree)
(let ((new-tree tree))
(loop
for (name package) in (append *dummies* *extra-dummies*)
do (let ((new-name (read-from-string
(format nil "~A::~A" package name))))
(setq new-tree (subst new-name name new-tree))))
new-tree))
;;; The main job DEFSECTION is to associate a title and a list of
;;; "entries" with a name. An entry is either a docstring or a
;;; reference to a definition of the form (<NAME> <DEFINITION-TYPE>).
;;;
;;; Concepts and index keys may also be used in DEFSECTION forms:
;;;
;;; (defsection @the-repl (:title "The REPL" :concepts (@repl))
;;; "The REPL is ...")
;;;
;;; When processed, this becomes
;;;
;;; @cindex Read-Eval-Print Loop
;;; @cindex REPL
;;; @node the repl
;;; @section The REPL
;;; The REPL is ...
;;;
;;; Note that it doesn't matter in :KEYS of DEFSECTION whether a
;;; concept is pure or titled.
;;;
;;; Note that referencing sections in docstrings does not cause
;;; indexing. This is due to examples like
;;;
;;; We now move on to the next section, @XXX.
;;; See @XXX, for other considerations.
;;;
;;; In general, mentioning and linking a section is not the same as
;;; being about it, and only the latter deserves a concept index
;;; entry.
;;;
;;; See also PAX:DEFSECTION.
(defmacro-dummy (defsection pax)
(name (&key (package *package*) (export t) title concepts)
&body entries)
(let ((value
`((:%pax-lazy-doc ,name :section resolve-lazy-doc)
(defsection ,name (:package ,package :export ,export :title ,title
:concepts ,concepts)
,@entries))))
`(progn
(defparameter ,name ',value)
,@(when export
`((export ',name :sb-manual))))))
(defun-dummy (section-name :pax) (section)
(second (second section)))
(defun-dummy (section-title :pax) (section)
(getf (third (second section)) :title))
(defun-dummy (concept-keys :pax) (section)
(resolve-concept-symbols (getf (third (second section)) :concepts)))
(defun-dummy (section-package :pax) (section)
(find-package (getf (third (second section)) :package)))
;;; This is a list of (NAME LOCATIVE) elements with our dummy DEFSECTION.
(defun-dummy (section-entries :pax) (section)
(nthcdr 3 (second section)))
(defun-dummy (xref-name :dref) (xref)
(first xref))
(defun-dummy (xref-locative :dref) (xref)
(normalize-locative (second xref)))
(defun normalize-locative (locative)
(if (and (listp locative)
(null (cdr locative)))
(first locative)
locative))
(defun-dummy (xref-locative-type :dref) (xref)
(first (sb-c::ensure-list (second xref))))
;;; DEFINE-CONCEPT names a set of index keys. When MARKDOWN-TO-TEXINFO
;;; encounters the name of a concept in a docstring, it emits Texinfo
;;; `@cindex' lines for its keys. There are two kinds of concepts.
;;;
;;; When a `pure' concept (that has no title) is processed in a
;;; docstring by MARKDOWN-TO-TEXINFO, it produces no visible output,
;;; but it emits Texinfo @cindex lines for its KEYS. It is thus _not_
;;; part of the normal flow of text.
;;;
;;; (define-concept ~repl (:keys ("Read-Eval-Print Loop" "REPL")))
;;;
;;; Example use:
;;;
;;; The REPL ~REPL is interactive.
;;;
;;; This becomes
;;;
;;; @cindex Read-Eval-Print Loop
;;; @cindex REPL
;;; The REPL is interactive.
;;;
;;; When a `titled' concept is processed, it is replaced by its title.
;;; Use this in the normal flow of text like section names. Note that
;;; other concepts can be referenced in KEYS. The definition below is
;;; the titled synonym of ~REPL.
;;;
;;; (define-concept @repl (:title "REPL" :keys (~repl)))
;;;
;;; Example use:
;;;
;;; The @REPL is interactive.
;;;
;;; This becomes
;;;
;;; @cindex Read-Eval-Print Loop
;;; @cindex REPL
;;; The REPL is interactive.
;;;
;;; By convention, names of pure concepts start with #\~, while those
;;; of titled concepts start with the usual #\@. The tilde is to draw
;;; attention to that the name is not part of the normal text.
;;;
;;; Finally, index keys can be hierarchical:
;;;
;;; (define-concept ~defining-macros (:keys (("defining" "macros")
;;; ("macros," "defining"))))
;;;
;;; This is processed into
;;;
;;; @cindex defining @subentry macros
;;; @cindex macros, @subentry defining
;;;
;;; Note Texinfo's @sortas is not supported yet. PAX implements that
;;; by allowing any subkey string to be a (<NAME> . <SORT-AS-STRING>)
;;; cons.
;;;
;;; See also PAX:DEFINE-CONCEPT.
(defmacro-dummy (define-concept pax) (name (&key title keys))
(let ((value
`((:%pax-lazy-doc ,name :concept resolve-lazy-doc)
(define-concept ,name (:title ,title :keys ,keys)))))
`(defparameter ,name ',value)))
(defun-dummy (multiplexing-concept-keys :pax) (concept)
(resolve-concept-symbols (getf (third (second concept)) :keys)))
(defun-dummy (doctitle :pax) (concept)
(getf (third (second concept)) :title))
(defun resolve-concept-symbols (list)
(if (find-if #'symbolp list)
(loop for x in list
append (if (symbolp x)
(multiplexing-concept-keys (find-concept x))
(list x)))
list))
(defun find-concept (name)
(if (doc-name-p name :concept)
(symbol-value name)
(error "Undefined ~S ~S." 'concept name)))
(defun doc-name-p (symbol kind)
(if *using-pax*
(and (boundp symbol)
(typep (symbol-value symbol) (dummy (ecase kind
(:section 'section)
(:concept 'concept)))))
(lazy-doc-name-p symbol kind)))

View file

@ -0,0 +1,44 @@
(error "Can't build contribs with ASDF")
(defsystem "sb-manual"
:serial t
:components ((:file "package")
(:file "pax")
(:file "docstring")
(:file "markdown" :if-feature :sb-doc)
(:file "texinfo" :if-feature :sb-doc)
(:file "manual")
(:module "doc/"
:serial t
:components ((:file "concepts")
(:file "sbcl")
(:file "support-and-bugs")
(:file "intro")
(:file "start-stop")
(:file "compiler")
(:file "debugger")
(:file "efficiency")
(:file "beyond-ansi")
(:file "external-formats")
(:file "ffi")
(:file "pathnames")
(:file "streams")
(:file "package-locks")
(:file "threading")
(:file "timers")
(:file "../../sb-bsd-sockets/manual")
(:file "profiling")
(:file "contrib-modules")
(:file "../../sb-aclrepl/manual")
(:file "../../sb-concurrency/manual")
(:file "../../sb-cover/manual")
(:file "../../sb-grovel/manual")
(:file "../../sb-introspect/manual")
(:file "../../sb-md5/manual")
(:file "../../sb-posix/manual")
(:file "../../sb-queue/manual")
(:file "../../sb-rotate-byte/manual")
(:file "../../sb-simd/manual")
(:file "../../sb-simple-streams/manual")
(:file "deprecation")))
(:file "late")))

View file

@ -0,0 +1,119 @@
@c Generated by the sb-manual contrib. Do not edit.
@node sb manual
@section sb-manual
@menu
* Using PAX: using pax.
* Browsing Live with PAX: browsing live with pax.
* Fancy Documentation with PAX: fancy documentation with pax.
@end menu
The @code{sb-manual} module has the SBCL user manual in forms
mimicking @code{pax:defsection}:
@example
(defsection @@example (:title "Example")
"This is an example, but see the real @@SB-MANUAL."
(print function)
(@@subexample section))
@end example
The names of the variables holding the documentation are exported
from the @code{sb-manual} package. Since sections are basically
variables, in Slime, @code{M-.} on @code{"@@SB-MANUAL"}, @code{"print"}, or
on @code{"@@subexample"} will take you to the respective definition.
This makes it easy to navigate the documentation. Normal Lisp
definition docstrings and section docstrings reference sections
following the usual convention of uppercasing the name. Docstrings
are in a subset of Markdown and use very little markup in general,
so they are easy to read directly in the source.
The official manual in Info, HTML and PDF formats is generated via
Texinfo generated from these definitions.
@node using pax
@subsection Using PAX
However, @code{sb-manual::defsection} is but a dummy implementation of
@code{pax:defsection} to avoid a hard dependency on PAX.
See the @code{mgl-pax} @code{asdf:system} or @url{https://github.com/melisgl/mgl-pax/}.
When PAX is loaded, the dummy @code{defsection} definitions are made
real, so that PAX can work with them.
@anchor{Function sb-manual use-pax}
@ffindex @sortas{use-pax sb-manual} use-pax [sb-manual]
@deffn{Function} sb-manual:use-pax
Ensure that exported variables are @code{pax:section}s.
It is an error if the @code{mgl-pax} library is not loaded.
Calling this function explicitly is rarely necessary because it is
called automatically:
@itemize
@item when @code{sb-manual} is loaded, if @code{pax} is present;
@item when @code{pax:document} (more precisely, @code{dref:locate}) is called on
an @code{sb-manual} section.
@end itemize
The latter feature requires v0.4.12 of @code{pax}. See the @code{mgl-pax}
asdf:system.
@end deffn
@node browsing live with pax
@subsection Browsing Live with PAX
With PAX, you can browse the manual live. The documentation of this
feature is available at
@uref{https://melisgl.github.io/mgl-pax-world/pax-manual.html#MGL-PAX:@@BROWSING-LIVE-DOCUMENTATION%20MGL-PAX:SECTION, online}.
If you are browsing this manual live right now, here is the
equivalent live link: @code{pax::@@browsing-live-documentation}.
Notable features:
@itemize
@item Autolinks within the manual: if @code{sb-ext:exit} is mentioned, then
it's linked to its documentation. You basically get links to where
@code{M-.} would go in the sources.
@item Autolinks to the CLHS.
@item View the documentation of any Lisp definition or section without
generating the entire manual.
@item Locatives (e.g. the @code{"[function]"} in @code{"- [function]
SB-EXT:EXIT"}) are also links in live browsing: they tell Slime
to visit the definition.
For this to work, you need to allow Slime to evaluate Elisp sent
from SBCL:
@example
(setq slime-enable-evaluate-in-emacs t)
@end example
and maybe your window manager focus stealing configuration needs
tweaking as well.
@end itemize
Live browsing can greatly reduce the latency of Edit-Compile-View
Loop, when working on documentation.
@node fancy documentation with pax
@subsection Fancy Documentation with PAX
PAX can generate dead documentation, too. In the SBCL sources,
@code{contrib/sb-manual/make-pax-docs.sh} generates the manual in plain
text, Markdown, PDF, and HTML formats. These differ from those
generated via Texinfo in that they are autolinked (like when
@ref{browsing live with pax}).
Also, you can generate documentation yourself with e.g.
@example
(pax:document sb-manual:@@sbcl-manual :format :markdown)
@end example

View file

@ -0,0 +1,315 @@
(in-package :sb-manual)
(defun xref-defined-p (xref)
(let ((name (xref-name xref))
(locative-type (xref-locative-type xref)))
(case locative-type
((function generic-function)
(ignore-errors (fdefinition name)))
((variable)
(member (sb-int:info :variable :kind name)
'(:global :special :constant)))
((declaration)
(find name (sb-cltl2:declaration-information 'declaration)))
((class structure condition)
(find-class name nil))
((type)
(sb-ext:defined-type-name-p name))
(t
(cond ((eq locative-type (dummy 'macro))
(ignore-errors (macro-function name)))
((or (eq locative-type (dummy 'setf-function))
(eq locative-type (dummy 'setf-generic-function)))
(ignore-errors (fdefinition name)))
(t
(assert nil () "Unexpected locative type in ~S."
xref)))))))
;;; We don't DEFINE-DUMMY DREF:ARGLIST and DREF:DOCSTRING because we
;;; don't want USE-PAX to affect Texinfo output, which it would
;;; because DREF:ARGLIST differs from the {incom,re}prehensible
;;; LAMBDA-LIST*.
(defun %arglist (xref)
(let ((name (xref-name xref))
(locative-type (xref-locative-type xref)))
(lambda-list* name locative-type)))
(defun %docstring (xref)
(let ((sb-pcl::*normalize-sbcl-docstrings* nil))
(values (let ((name (xref-name xref))
(locative-type (xref-locative-type xref)))
(case locative-type
((function variable declaration)
(documentation name locative-type))
((generic-function)
(documentation name 'function))
((type class structure condition)
(documentation name 'type))
(t
(cond ((eq locative-type (dummy 'macro))
(documentation (macro-function name) t))
((eq locative-type (dummy 'setf-function))
(documentation (fdefinition name) t))
((eq locative-type (dummy 'setf-generic-function))
(documentation (fdefinition name) t))
(t
(assert nil () "Unexpected locative type in ~S."
xref))))))
;; To be compatible with PAX::@PACKAGE-AND-READTABLE, we
;; always return a non-NIL package.
(docstring-package xref))))
(defun lambda-list* (name kind)
(case kind
((package constant variable type structure class condition method
declaration nil)
nil)
(t
;; KLUDGE: Eugh.
;;
;; believe it or not, the above comment was written before CSR
;; came along and obfuscated this. (2005-07-04)
(when (symbolp name)
(labels ((clean (x &key optional key)
(typecase x
(atom x)
((cons (member &optional))
(cons (car x) (clean (cdr x) :optional t)))
((cons (member &key))
(cons (car x) (clean (cdr x) :key t)))
((cons (member &whole &environment))
;; Skip these
(clean (cdr x) :optional optional :key key))
((cons cons)
(cons
(cond (key (if (consp (caar x))
(caaar x)
(caar x)))
(optional (caar x))
(t (clean (car x))))
(clean (cdr x) :key key :optional optional)))
(cons
(cons
(cond ((or key optional) (car x))
(t (clean (car x))))
(clean (cdr x) :key key :optional optional))))))
(multiple-value-bind (ll unknown)
(sb-introspect:function-lambda-list name)
(if unknown
(values nil t)
(clean ll))))))))
(defun locative-type-to-texinfo (locative-type)
(case locative-type
(function
(values "Function" "ffindex"))
(generic-function
(values "Generic function" "ffindex"))
(variable
(values "Variable" "vvindex"))
(class
(values "Class" "ttindex"))
(condition
(values "Condition" "ttindex"))
(structure
(values "Structure" "ttindex"))
(type
(values "Type" "ttindex"))
(declaration
(values "Declaration" "ddindex"))
(t
(cond
((eq locative-type (dummy 'macro))
(values "Macro" "ffindex"))
((eq locative-type (dummy 'setf-function))
(values "Setf function" "ffindex"))
((eq locative-type (dummy 'setf-generic-function))
(values "Setf generic function" "ffindex"))
(t
(assert nil () "Unexpected locative type ~S." locative-type))))))
(defmacro with-texinfo-to-file (file &body body)
`(call-maybe-with-texinfo-to-file (lambda () ,@body)
,file))
(defun call-maybe-with-texinfo-to-file (fn file)
(if file
(with-open-file (*standard-output* file :direction :output
:if-does-not-exist :create
:if-exists :supersede)
(format t "@c Generated by the sb-manual contrib. Do not edit.~%~%")
(funcall fn))
(funcall fn)))
(defun remove-markup (string)
(remove #\\ string))
;;; Write the Texinfo for SECTION to *STANDARD-OUTPUT*. When recursing
;;; into child sections, if a section is in PAGES, then emit an
;;; @include and open a new a file for output.
(defun emit-texinfo-for-section (section &key pages (depth 0)
top-level-menus-to-file
top-level-contents-to-file)
(let ((title (remove-markup (section-title section)))
(entries (section-entries section)))
(format t "@node ~A~%" (texinfo-node-id section))
(write-concept-keys (concept-keys section) *standard-output*)
(format t "~A ~A~%~%"
(ecase depth
(0 "@top")
(1 "@chapter")
(2 "@section")
(3 "@subsection")
(4 "@subsubsection"))
title)
;; Generate the @menu
(let ((child-sections
(loop for entry in entries
when (and (not (stringp entry))
(eq (xref-locative-type entry) (dummy 'section)))
collect (symbol-value (xref-name entry)))))
(when child-sections
(unless top-level-menus-to-file
(format t "@menu~%"))
(with-texinfo-to-file top-level-menus-to-file
(dolist (child-section child-sections)
(format t "* ~A: ~A.~%"
(remove-markup (section-title child-section))
(texinfo-node-id child-section))))
(unless top-level-menus-to-file
(format t "@end menu~%~%"))))
;; Generate the documentation
(let ((*package* (section-package section)))
(with-texinfo-to-file top-level-contents-to-file
(dolist (entry entries)
(cond ((stringp entry)
;; KLUDGE: @SBCL-MANUAL has an extra docstring that's
;; pretty much the same as @copying in
;; doc/manual/sbcl.texinfo. Skip it.
(unless top-level-contents-to-file
(emit-texinfo-for-docstring entry)
(format t "~%")))
(t
(if (not (eq (xref-locative-type entry) (dummy 'section)))
(emit-texinfo-for-definition entry)
(let ((page (find (xref-name entry) pages
:key #'first)))
(when page
(format t "@include ~A~%" (second page)))
(with-texinfo-to-file (second page)
(emit-texinfo-for-section
(symbol-value (xref-name entry))
:pages pages
:depth (1+ depth))))))))))))
(defun emit-texinfo-for-definition (xref)
(if (not (xref-defined-p xref))
(warn "~@<Not documenting ~S because it is not defined.~:@>" xref)
(multiple-value-bind (docstring *package*) (%docstring xref)
(multiple-value-bind (type index)
(locative-type-to-texinfo (xref-locative-type xref))
(let* ((name (xref-name xref))
(*print-case* :downcase)
;; For e.g. #'print
(*print-pretty* t)
;; The arglist must be on the @deffn line.
(*print-right-margin* most-positive-fixnum))
(format t "@anchor{~A ~A ~A}~%" type
(string-downcase (package-name (symbol-package name)))
(string-downcase (symbol-name name)))
;; E.g. @vvindex @sortas{save-hooks* sb-ext} *save-hooks* [sb-ext]
(let ((symbol-name (string-downcase (symbol-name name)))
(symbol-package-name
(string-downcase (package-name (symbol-package name)))))
(format t "@~A @sortas{~A ~A} ~A [~A]~%"
index
(sort-as-name symbol-name)
(sort-as-name symbol-package-name)
symbol-name
symbol-package-name))
;; Since we took indexing into our own hands, we just use
;; @deffn for all definitions. We could also use @defblock and
;; @defline.
(format t "@deffn{~A} ~A~{ ~A~}~%"
;; E.g. "Variable"
type
(let ((*package* (find-package :cl)))
(prin1-to-string name))
(%arglist xref))
(when docstring
(emit-texinfo-for-docstring docstring (%arglist xref)))
(format t "@end deffn~%"))))))
;;; Remove leading non-alphanumeric characters. They are not important
;;; when sorting names into indices.
(defun sort-as-name (name)
(subseq name (or (position-if #'alphanumericp name) 0)))
(defun emit-texinfo-for-docstring (docstring &optional arglist)
(markdown-to-texinfo (reindent-docstring docstring) arglist))
;;; Currently, we have the Texinfo file under version control to keep
;;; a closer eye on the Markdown-to-Texinfo converter, which is young.
;;; When that's no longer the case, this is no longer needed.
(defparameter *pages*
'((@support-and-bugs "support-and-bugs.texinfo")
(@introduction "intro.texinfo")
(@starting-and-stopping "start-stop.texinfo")
(@compiler "compiler.texinfo")
(@debugger "debugger.texinfo")
(@efficiency "efficiency.texinfo")
(@beyond-the-ansi-standard "beyond-ansi.texinfo")
(@external-formats "external-formats.texinfo")
(@foreign-function-interface "ffi.texinfo")
(@pathnames "pathnames.texinfo")
(@streams "streams.texinfo")
(@package-locks "package-locks.texinfo")
(@threading "threading.texinfo")
(@timers "timers.texinfo")
(@networking "../../contrib/sb-bsd-sockets/sb-bsd-sockets.texinfo")
(@profiling "profiling.texinfo")
(@statistical-profiler "../../contrib/sb-sprof/sb-sprof.texinfo")
(@contributed-modules "contrib-modules.texinfo")
(@sb-aclrepl "../../contrib/sb-aclrepl/sb-aclrepl.texinfo")
(@sb-concurrency "../../contrib/sb-concurrency/sb-concurrency.texinfo")
(@sb-cover "../../contrib/sb-cover/sb-cover.texinfo")
(@sb-grovel "../../contrib/sb-grovel/sb-grovel.texinfo")
(@sb-introspect "../../contrib/sb-introspect/sb-introspect.texinfo")
(@sb-manual "../../contrib/sb-manual/sb-manual.texinfo")
(@sb-md5 "../../contrib/sb-md5/sb-md5.texinfo")
(@sb-posix "../../contrib/sb-posix/sb-posix.texinfo")
(@sb-queue "../../contrib/sb-queue/sb-queue.texinfo")
(@sb-rotate-byte "../../contrib/sb-rotate-byte/sb-rotate-byte.texinfo")
(@sb-sb-simd "../../contrib/sb-simd/sb-simd.texinfo")
(@sb-simple-streams
"../../contrib/sb-simple-streams/sb-simple-streams.texinfo")
(@deprecation "deprecation.texinfo")))
(defun generate-texinfo ()
(let ((*default-pathname-defaults*
(truename (merge-pathnames
"../../doc/manual/"
sb-sys::*sbcl-homedir-pathname*))))
(with-texinfo-to-file "variables.texinfo"
(format t "@set VERSION ~A~%~
@set UPDATE-MONTH ~A~%"
(lisp-implementation-version)
(documentation-generation-date-string)))
;; We redirect most lines via *PAGES*, :TOP-LEVEL-MENUS-TO-FILE,
;; :TOP-LEVEL-CONTENTS-TO-FILE. Silence the rest, which are not
;; needed, as sbcl.texinfo only needs the includes.
(let ((*standard-output* (make-broadcast-stream)))
(emit-texinfo-for-section
(symbol-value '@sbcl-manual) :pages *pages*
:top-level-menus-to-file "sbcl-menu.texinfo"
:top-level-contents-to-file "sbcl-contents.texinfo"))))
#+nil
(generate-texinfo)
#+nil
(emit-texinfo-for-section @sb-aclrepl)
#+nil
(emit-texinfo-for-section @starting-and-stopping)

View file

@ -0,0 +1,18 @@
(in-package :sb-manual)
(defsection @sb-md5 (:title "sb-md5")
;; FIXME: cite
"The `SB-MD5` module implements the RFC1321 MD5 Message Digest
Algorithm."
(sb-md5:md5sum-file function)
(sb-md5:md5sum-sequence function)
(sb-md5:md5sum-stream function)
(sb-md5:md5sum-string function)
"The implementation for CMUCL was largely done by Pierre Mai, with help
from members of the `cmucl-help` mailing list. Since CMUCL and SBCL
are similar in many respects, it was not too difficult to extend the
low-level implementation optimizations for CMUCL to SBCL. Following
this, SBCL's compiler was extended to implement efficient
compilation of modular arithmetic (@MODULAR-ARITHMETIC), which
enabled the implementation to be expressed in portable arithmetical
terms, apart from the use of @SB-ROTATE-BYTE for bitwise rotation.")

View file

@ -314,8 +314,8 @@ registers A, B, C and D."
(defun update-md5-block (regs block)
"This is the core part of the MD5 algorithm. It takes a complete 16
word block of input, and updates the working state in A, B, C, and D
accordingly."
word block of input, and updates the working state in registers A,
B, C, and D accordingly."
(declare (type md5-regs regs)
(type md5-block block)
(optimize (speed 3) (safety 0) (space 0) (debug 0) #+lw-int32 (float 0)))
@ -358,7 +358,7 @@ accordingly."
(declaim (inline fill-block fill-block-ub8 fill-block-char))
(defun fill-block-ub8 (block buffer offset)
"Convert a complete 64 (unsigned-byte 8) input vector segment
starting from `offset' into the given 16 word MD5 block."
starting from OFFSET into the given 16 word MD5 block."
(declare (type (integer 0 #.(- most-positive-fixnum 64)) offset)
(type md5-block block)
(type (simple-array (unsigned-byte 8) (*)) buffer)
@ -384,7 +384,7 @@ starting from `offset' into the given 16 word MD5 block."
(defun fill-block-char (block buffer offset)
"DEPRECATED: Convert a complete 64 character input string segment
starting from `offset' into the given 16 word MD5 block."
starting from OFFSET into the given 16 word MD5 block."
(declare (type (integer 0 #.(- most-positive-fixnum 64)) offset)
(type md5-block block)
(type simple-string buffer)
@ -412,9 +412,9 @@ starting from `offset' into the given 16 word MD5 block."
(defun fill-block (block buffer offset)
"Convert a complete 64 byte input vector segment into the given 16
word MD5 block. This currently works on (unsigned-byte 8) and
character simple-arrays, via the functions `fill-block-ub8' and
`fill-block-char' respectively. Note that it will not work correctly
on character simple-arrays if `char-code-limit' is greater than 256."
character simple-arrays, via the functions FILL-BLOCK-UB8 and
FILL-BLOCK-CHAR respectively. Note that it will not work correctly
on character simple-arrays if CHAR-CODE-LIMIT is greater than 256."
(declare (type (integer 0 #.(- most-positive-fixnum 64)) offset)
(type md5-block block)
(type (simple-array * (*)) buffer)
@ -431,7 +431,7 @@ on character simple-arrays if `char-code-limit' is greater than 256."
(declaim (inline md5regs-digest))
(defun md5regs-digest (regs)
"Create the final 16 byte message-digest from the MD5 working state
in `regs'. Returns a (simple-array (unsigned-byte 8) (16))."
in REGS. Returns a (simple-array (unsigned-byte 8) (16))."
(declare (optimize (speed 3) (safety 0) (space 0) (debug 0)
#+lw-int32 (float 0) #+lw-int32 (hcl:fixnum-safety 0))
(type md5-regs regs))
@ -474,9 +474,9 @@ in `regs'. Returns a (simple-array (unsigned-byte 8) (16))."
(declaim (inline copy-to-buffer))
(defun copy-to-buffer (from from-offset count buffer buffer-offset)
"Copy a partial segment from input vector `from' starting at
`from-offset' and copying `count' elements into the 64 byte buffer
starting at `buffer-offset'."
"Copy a partial segment from input vector FROM starting at
FROM-OFFSET and copying COUNT elements into the 64 byte buffer
starting at BUFFER-OFFSET."
(declare (optimize (speed 3) (safety 0) (space 0) (debug 0)
#+lw-int32 (float 0) #+lw-int32 (hcl:fixnum-safety 0))
(type sb-int:index from-offset)
@ -510,12 +510,12 @@ starting at `buffer-offset'."
from-index))))))
(defun update-md5-state (state sequence &key (start 0) (end (length sequence)))
"Update the given md5-state from `sequence', which is either a
"Update the given md5-state from SEQUENCE, which is either a
simple-string or a simple-array with element-type (unsigned-byte 8),
bounded by `start' and `end', which must be numeric bounding-indices.
bounded by START and END, which must be numeric bounding-indices.
Note that usage on simple-strings is DEPRECATED, since this will not
work correctly if `char-code-limit' is more than 256. String input
should be converted to (unsigned-byte 8) simple-arrays with
work correctly if CHAR-CODE-LIMIT is more than 256. String input
should be converted to (UNSIGNED-BYTE 8) simple-arrays with
external-format conversion routines beforehand."
(declare (type md5-state state)
(type (simple-array * (*)) sequence)
@ -591,8 +591,8 @@ by processing any remaining input in its buffer, with suitable padding
and appended bit-length, as specified by the MD5 standard.
The resulting MD5 message-digest is returned as an array of sixteen
(unsigned-byte 8) values. Calling `update-md5-state' after a call to
`finalize-md5-state' results in unspecified behaviour."
(unsigned-byte 8) values. Calling UPDATE-MD5-STATE after a call to
FINALIZE-MD5-STATE results in unspecified behaviour."
(declare (type md5-state state)
(optimize (speed 3) (safety 1) (space 0) (debug 1) #+lw-int32 (float 0)))
(locally
@ -633,8 +633,8 @@ The resulting MD5 message-digest is returned as an array of sixteen
;;; High-Level Drivers
(defun md5sum-sequence (sequence &key (start 0) end)
"Calculate the MD5 message-digest of data in `sequence', which should
be a 1d simple-array with element type (unsigned-byte 8). On CMU CL
"Calculate the MD5 message-digest of data in SEQUENCE, which should
be a 1d SIMPLE-ARRAY with element type (UNSIGNED-BYTE 8). On CMU CL
and SBCL non-simple and non-1d arrays with this element-type are also
supported."
(declare (optimize (speed 3) (safety 3) (space 0) (debug 1))
@ -666,8 +666,8 @@ supported."
(defun md5sum-string (string &key (external-format :default) (start 0) end)
"Calculate the MD5 message-digest of the binary representation of
`string' (as octets) in the external format specified by
`external-format'. The boundaries `start' and `end' refer to character
STRING (as octets) in the external format specified by
EXTERNAL-FORMAT. The boundaries START and END refer to character
positions in the string, not to octets in the resulting binary
representation. The permissible external format specifiers are
determined by the underlying implementation."
@ -716,16 +716,16 @@ determined by the underlying implementation."
(eval-when (:compile-toplevel :load-toplevel :execute)
(defconstant +buffer-size+ (* 128 1024)
"Size of internal buffer to use for `md5sum-stream' and `md5sum-file'
"Size of internal buffer to use for MD5SUM-STREAM and MD5SUM-FILE
operations. This should be a multiple of 64, the MD5 block size."))
(deftype buffer-index () `(integer 0 ,+buffer-size+))
(defun md5sum-stream (stream)
"Calculate an MD5 message-digest of the contents of `stream'. Its
element-type has to be (unsigned-byte 8). Use on character streams is
"Calculate an MD5 message-digest of the contents of STREAM. Its
element-type has to be (UNSIGNED-BYTE 8). Use on character streams is
DEPRECATED, as this will not work correctly on implementations with
`char-code-limit' > 256 and ignores character coding issues."
CHAR-CODE-LIMIT > 256 and ignores character coding issues."
(declare (optimize (speed 3) (safety 3) (space 0) (debug 1)))
(locally
(declare (optimize (safety 1) (debug 0)))
@ -755,7 +755,7 @@ DEPRECATED, as this will not work correctly on implementations with
(stream-element-type stream) stream))))))
(defun md5sum-file (pathname)
"Calculate the MD5 message-digest of the file specified by `pathname'."
"Calculate the MD5 message-digest of the file specified by PATHNAME."
(declare (optimize (speed 3) (safety 3) (space 0) (debug 1)))
(with-open-file (stream pathname :element-type '(unsigned-byte 8))
(md5sum-stream stream)))

View file

@ -1,27 +1,48 @@
@node sb-md5
@c Generated by the sb-manual contrib. Do not edit.
@node sb md5
@section sb-md5
@cindex Hashing, cryptographic
The @code{sb-md5} module implements the RFC1321 MD5 Message Digest
Algorithm. [FIXME cite]
@include fun-sb-md5-md5sum-file.texinfo
@include fun-sb-md5-md5sum-sequence.texinfo
@include fun-sb-md5-md5sum-stream.texinfo
@include fun-sb-md5-md5sum-string.texinfo
@subsection Credits
Algorithm.
@anchor{Function sb-md5 md5sum-file}
@ffindex @sortas{md5sum-file sb-md5} md5sum-file [sb-md5]
@deffn{Function} sb-md5:md5sum-file pathname
Calculate the MD5 message-digest of the file specified by @code{pathname}.
@end deffn
@anchor{Function sb-md5 md5sum-sequence}
@ffindex @sortas{md5sum-sequence sb-md5} md5sum-sequence [sb-md5]
@deffn{Function} sb-md5:md5sum-sequence sequence &key start end
Calculate the MD5 message-digest of data in @code{sequence}, which should
be a 1d @code{simple-array} with element type (@code{unsigned-byte} 8). On CMU CL
and SBCL non-simple and non-1d arrays with this element-type are also
supported.
@end deffn
@anchor{Function sb-md5 md5sum-stream}
@ffindex @sortas{md5sum-stream sb-md5} md5sum-stream [sb-md5]
@deffn{Function} sb-md5:md5sum-stream stream
Calculate an MD5 message-digest of the contents of @code{stream}. Its
element-type has to be (@code{unsigned-byte} 8). Use on character streams is
DEPRECATED, as this will not work correctly on implementations with
@code{char-code-limit} > 256 and ignores character coding issues.
@end deffn
@anchor{Function sb-md5 md5sum-string}
@ffindex @sortas{md5sum-string sb-md5} md5sum-string [sb-md5]
@deffn{Function} sb-md5:md5sum-string string &key external-format start end
Calculate the MD5 message-digest of the binary representation of
@code{string} (as octets) in the external format specified by
@code{external-format}. The boundaries @code{start} and @code{end} refer to character
positions in the string, not to octets in the resulting binary
representation. The permissible external format specifiers are
determined by the underlying implementation.
@end deffn
The implementation for CMUCL was largely done by Pierre Mai, with help
from members of the @code{cmucl-help} mailing list. Since CMUCL and
SBCL are similar in many respects, it was not too difficult to extend
the low-level implementation optimizations for CMUCL to SBCL.
Following this, SBCL's compiler was extended to implement efficient
compilation of modular arithmetic (@pxref{Modular arithmetic}), which
from members of the @code{cmucl-help} mailing list. Since CMUCL and SBCL
are similar in many respects, it was not too difficult to extend the
low-level implementation optimizations for CMUCL to SBCL. Following
this, SBCL's compiler was extended to implement efficient
compilation of modular arithmetic (@ref{modular arithmetic}), which
enabled the implementation to be expressed in portable arithmetical
terms, apart from the use of @code{rotate-byte} for bitwise rotation.
@findex @sbrotatebyte{rotate-byte}
terms, apart from the use of @ref{sb rotate byte} for bitwise rotation.

View file

@ -438,8 +438,7 @@
;; utime(), utimes()
#-win32
(:type suseconds-t ; OAOOM warning: similar kludge in tools-for-build
#+(and os-provides-suseconds-t 64-bit-time) "__suseconds64_t"
#+(and os-provides-suseconds-t (not 64-bit-time)) "suseconds_t"
#+os-provides-suseconds-t "suseconds_t"
#-os-provides-suseconds-t "long")
#-win32
@ -451,9 +450,7 @@
(:structure alien-timeval
("struct timeval"
(time-t sec "time_t" "tv_sec")
(suseconds-t usec #+64-bit-time "__suseconds64_t"
#-64-bit-time "suseconds_t"
"tv_usec")))
(signed usec nil "tv_usec")))
(:integer veof "VEOF" nil t)
(:integer veol "VEOL" nil t)

View file

@ -20,7 +20,8 @@
#:stat-gid #:stat-size #:stat-atime #:stat-mtime #:stat-ctime
#:stat-rdev
#:termios-iflag #:termios-oflag #:termios-cflag
#:termios-lflag #:termios-cc #:timeval-sec #:timeval-usec
#:termios-lflag #:termios-cc
#:timeval-sec #:timeval-usec
#:flock-type #:flock-whence #:flock-start #:flock-len
#:flock-pid

View file

@ -4,10 +4,8 @@
(defmacro define-designator (name (lisp-type alien-type) doc
&body conversions)
(let ((designator-type `(or ,@(mapcar #'car conversions)))
(designator-name (intern (format nil "~A-~A"
(symbol-name name)
(symbol-name :designator))
#.*package*))
(designator-name
(sb-int:package-symbolicate #.*package* name "-DESIGNATOR"))
(name (intern (symbol-name name) :sb-posix)))
`(progn
(deftype ,name ()

View file

@ -2,18 +2,42 @@
(defmacro define-protocol-class
(name alien-type superclasses slots &rest options)
(let ((to-protocol (intern (format nil "ALIEN-TO-~A" name)))
(to-alien (intern (format nil "~A-TO-ALIEN" name))))
(let* ((to-protocol (intern (format nil "ALIEN-TO-~A" name)))
(to-alien (intern (format nil "~A-TO-ALIEN" name)))
(remaining-field-size sb-vm:n-word-bytes)
(remaining-fields (loop for field in (sb-alien::alien-record-type-fields
(sb-alien-internals:parse-alien-type alien-type nil))
for name = (sb-alien-internals:alien-record-field-name field)
for offset = (/ (sb-alien-internals:alien-record-field-offset field)
8)
for size = (/ (sb-alien-internals:alien-type-bits (sb-alien-internals:alien-record-field-type field))
8)
when (eql (search "PADDING-" (string name)) 0)
collect (cons offset size)
and do (cond ((not (and (zerop (rem offset 4))
(zerop (rem size 4))))
(setf remaining-field-size 1))
((not (and (zerop (rem offset sb-vm:n-word-bytes))
(zerop (rem size sb-vm:n-word-bytes))))
(setf remaining-field-size
(min remaining-field-size 4))))))
(remaining-fields-length (/ (reduce #'+ remaining-fields :key #'cdr)
remaining-field-size))
(remaining-fields-type `(simple-array (unsigned-byte ,(* remaining-field-size 8))
(,remaining-fields-length))))
`(progn
(export ',name :sb-posix)
(defclass ,name ,superclasses
;; KLUDGE: Splice out some slot options (they're
;; for the conversion functions, not for DEFCLASS).
,(loop for slotd in slots
collect
(let ((slotd (copy-list slotd)))
(dolist (keyword '(:array-length :from-alien) slotd)
(remf (cdr slotd) keyword))))
(,@(loop for slotd in slots
collect
(let ((slotd (copy-list slotd)))
(dolist (keyword '(:array-length :from-alien) slotd)
(remf (cdr slotd) keyword))))
,@(when remaining-fields
`((remaining-fields :initform (make-sequence ',remaining-fields-type ,remaining-fields-length
:initial-element 0)))))
,@options)
;; TODO (maybe): there's no reason to define to-alien routines
;; struct stat, passwd, or group: OS interfaces only ever write
@ -50,6 +74,18 @@
(,from-alien (sb-alien:slot alien ',(car slotd))))
`(setf (slot-value instance ',(car slotd))
(sb-alien:slot alien ',(car slotd)))))
,@(when remaining-fields
`((let ((vector (the ,remaining-fields-type
(slot-value instance 'remaining-fields))))
,@(loop with array-offset = 0
for (offset . size) in remaining-fields
append (loop repeat (/ size remaining-field-size)
for i from (/ offset remaining-field-size)
collect `(setf (aref vector ,array-offset)
(deref (sb-alien:cast alien (* (unsigned ,(* remaining-field-size 8))))
,i))
do
(incf array-offset))))))
instance)
(defun ,to-alien (instance &optional alien)
(declare (type (or null (sb-alien:alien (* ,alien-type))) alien)
@ -70,7 +106,19 @@
;; counterpart of :FROM-ALIEN so far.
else
collect `(setf (sb-alien:slot alien ',(car slotd))
(slot-value instance ',(car slotd)))))
(slot-value instance ',(car slotd))))
,@(when remaining-fields
`((let ((vector (the ,remaining-fields-type
(slot-value instance 'remaining-fields))))
,@(loop with array-offset = 0
for (offset . size) in remaining-fields
append (loop repeat (/ size remaining-field-size)
for i from (/ offset remaining-field-size)
collect `(setf (deref (sb-alien:cast alien (* (unsigned ,(* remaining-field-size 8))))
,i)
(aref vector ,array-offset))
do
(incf array-offset)))))))
(find-class ',name))))
(define-condition sb-posix:syscall-error (error)
@ -274,7 +322,8 @@
(arg alien-pointer-to-anything-or-nil))
(define-protocol-class flock alien-flock ()
((type :initarg :type :accessor flock-type
:documentation "Type of lock; F_RDLCK, F_WRLCK, F_UNLCK.")
:documentation "Type of lock; `\\\\F_RDLCK`, `\\\\F_WRLCK`,
`\\\\F_UNLCK`.")
(whence :initarg :whence :accessor flock-whence
:documentation "Flag for starting offset.")
(start :initarg :start :accessor flock-start
@ -286,8 +335,9 @@
;; so we initialize it to 0.
(pid :initform 0 :reader flock-pid
:documentation
"Process ID of the process holding the lock; returned with F_GETLK."))
(:documentation "Class representing locks used in fcntl(2)."))
"Process ID of the process holding the lock;
returned with `\\\\F_GETLK`."))
(:documentation "Class representing locks used in `\\fcntl(2)`."))
(define-entry-point "fcntl" (fd cmd &optional (arg nil argp))
(if argp
(etypecase arg
@ -509,6 +559,8 @@ not supported."
(define-call "munmap" int minusp
(start sb-sys:system-area-pointer) (length unsigned))
(define-call "mprotect" int minusp
(addr system-area-pointer) (length size-t) (prot unsigned))
(define-call "msync" int minusp
(addr sb-sys:system-area-pointer) (length unsigned) (flags int)))
@ -642,8 +694,10 @@ not supported."
,name (function ,result-type ,@(when arg-type `(,arg-type))))
,@(when arg `(,arg))))))
(if (null-alien r)
(when (plusp (get-errno))
(syscall-error ',lisp-name))
(let ((errno (get-errno)))
(when (and (plusp errno)
(/= errno ENOENT))
(syscall-error ',lisp-name)))
(,conv r)))))))
(define-enumerator-call (name assertion)
(let ((lisp-name (intern (string-upcase name) :sb-posix)))
@ -811,15 +865,15 @@ not supported."
#-win32
(define-protocol-class termios alien-termios ()
((iflag :initarg :iflag :accessor sb-posix:termios-iflag
((iflag :initarg :iflag :accessor termios-iflag
:documentation "Input modes.")
(oflag :initarg :oflag :accessor sb-posix:termios-oflag
(oflag :initarg :oflag :accessor termios-oflag
:documentation "Output modes.")
(cflag :initarg :cflag :accessor sb-posix:termios-cflag
(cflag :initarg :cflag :accessor termios-cflag
:documentation "Control modes.")
(lflag :initarg :lflag :accessor sb-posix:termios-lflag
(lflag :initarg :lflag :accessor termios-lflag
:documentation "Local modes.")
(cc :initarg :cc :accessor sb-posix:termios-cc :array-length nccs
(cc :initarg :cc :accessor termios-cc :array-length nccs
:documentation "Control characters."))
(:documentation
"Instances of this class represent I/O characteristics of the terminal."))
@ -1020,7 +1074,7 @@ not supported."
(defun syslog (priority format &rest args)
"Send a message to the syslog facility, with severity level
PRIORITY. The message will be formatted as by CL:FORMAT (rather
than C's printf) with format string FORMAT and arguments ARGS."
than C's `printf`) with format string FORMAT and arguments ARGS."
(flet ((syslog1 (priority message)
(alien-funcall (extern-alien
"syslog" (function void int

View file

@ -5,7 +5,7 @@
Note that native namestring syntax is distinct from Lisp namestring syntax:
\(pathname \"/foo*/bar\")
(pathname \"/foo*/bar\")
is a wild pathname with a pattern-matching directory component.
SB-EXT:PARSE-NATIVE-NAMESTRING may be used to construct Lisp pathnames that
@ -15,16 +15,16 @@ namestring syntax.
Note also that POSIX filename syntax does not distinguish the names of files
from the names of directories: in order to parse the name of a directory in
POSIX filename syntax into a pathname MY-DEFAULTS for which
POSIX filename syntax into a pathname `MY-DEFAULTS` for which
\(merge-pathnames (make-pathname :name \"FOO\" :case :common)
my-defaults)
(merge-pathnames (make-pathname :name \"FOO\" :case :common)
my-defaults)
returns a pathname that denotes a file in the directory, supply a true
:AS-DIRECTORY argument to SB-EXT:PARSE-NATIVE-NAMESTRING. Likewise, to supply
the name of a directory to a POSIX function in non-directory syntax, supply a
true :AS-FILE argument to SB-EXT:NATIVE-NAMESTRING."
"Designator for a FILENAME: a STRING designating itself, or a
"Designator for a [FILENAME][type]: a STRING designating itself, or a
designator for a PATHNAME designating the corresponding native namestring."
"Converts FILENAME-DESIGNATOR into a FILENAME.")
(pathname
@ -43,8 +43,8 @@ native file descriptor.
Note that mixing I/O operations on a FILE-STREAM with operations directly on its
descriptor may produce unexpected results if the stream is buffered."
"Designator for a FILE-DESCRIPTOR: either a fixnum designating itself, or
a FILE-STREAM designating the underlying file-descriptor."
"Designator for a [FILE-DESCRIPTOR][type]: either a fixnum designating
itself, or a FILE-STREAM designating the underlying file-descriptor."
"Converts FILE-DESCRIPTOR-DESIGNATOR into a FILE-DESCRIPTOR.")
(file-stream
(sb-sys:fd-stream-fd file-descriptor))

Some files were not shown because too many files have changed in this diff Show more