mirror of
git://git.code.sf.net/p/sbcl/sbcl
synced 2026-09-10 07:26:40 -04:00
0.8.6.1:
* clean.sh: Allow recursive includes in src/runtime/Config * doc/*: Convert from SGML format and processing to XML Currently, catalogs are in place for Debian and RedHat which allow automated use of local files instead of the tools downloading DTDs and XSLs from their canonical URLs. I'm glad to help setup catalogs for other operating systems.
This commit is contained in:
parent
1462adfb42
commit
3c5c2c2656
6
clean.sh
6
clean.sh
|
|
@ -22,6 +22,10 @@ rm -rf obj/* output/* doc/user-manual \
|
|||
# distribution, we automatically clean up after it here in the
|
||||
# standard clean.sh file.)
|
||||
|
||||
# Ensure we know GNUMAKE
|
||||
. find-gnumake.sh
|
||||
find_gnumake
|
||||
|
||||
# Ask some other directories to clean themselves up.
|
||||
original_pwd=`pwd`
|
||||
for d in tools-for-build; do
|
||||
|
|
@ -31,7 +35,7 @@ for d in tools-for-build; do
|
|||
# this script is just the operations done by these make's, which
|
||||
# is misleading when this script does lotso other operations too.
|
||||
# -- WHN
|
||||
make -s clean
|
||||
$GNUMAKE -I ../src/runtime -s clean
|
||||
cd $original_pwd > /dev/null
|
||||
done
|
||||
|
||||
|
|
|
|||
113
doc/Makefile
Normal file
113
doc/Makefile
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
DOCFILE_BASE_DEFAULT:=user-manual
|
||||
DOCFILE_EXT_DEFAULT:=xml
|
||||
|
||||
|
||||
# Standard docfile processing
|
||||
|
||||
DEBIAN=$(shell expr "`cat /etc/issue`" : '.*Debian.*')
|
||||
SUSE=$(shell expr "`cat /etc/issue`" : '.*SuSE.*')
|
||||
REDHAT=$(shell expr "`cat /etc/issue`" : '.*RedHat.*')
|
||||
|
||||
|
||||
ifneq (${DEBIAN},0)
|
||||
OS:=debian
|
||||
else
|
||||
ifneq (${SUSE},0)
|
||||
OS=suse
|
||||
else
|
||||
ifneq (${REDHAT},0)
|
||||
OS=redhat
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifndef DOCFILE_BASE
|
||||
DOCFILE_BASE=${DOCFILE_BASE_DEFAULT}
|
||||
endif
|
||||
|
||||
ifndef DOCFILE_EXT
|
||||
DOCFILE_EXT=${DOCFILE_EXT_DEFAULT}
|
||||
endif
|
||||
|
||||
DOCFILE:=${DOCFILE_BASE}.${DOCFILE_EXT}
|
||||
FOFILE:=${DOCFILE_BASE}.fo
|
||||
PDFFILE:=${DOCFILE_BASE}.pdf
|
||||
PSFILE:=${DOCFILE_BASE}.ps
|
||||
DVIFILE:=${DOCFILE_BASE}.dvi
|
||||
TXTFILE:=${DOCFILE_BASE}.txt
|
||||
HTMLFILE:=${DOCFILE_BASE}.html
|
||||
TMPFILES:=${DOCFILE_BASE}.aux ${DOCFILE_BASE}.out ${DOCFILE_BASE}.log
|
||||
DOCFILES:=$(shell echo *.xml *.xsl)
|
||||
|
||||
ifeq ($(XSLTPROC),)
|
||||
XSLTPROC:=xsltproc
|
||||
endif
|
||||
|
||||
CATALOG:=`pwd`/catalog-${OS}.xml
|
||||
CHECK:=XML_CATALOG_FILES="$(CATALOG)" xmllint --noout --xinclude --postvalid $(DOCFILE) || exit 1
|
||||
|
||||
.PHONY: all
|
||||
all: html pdf
|
||||
|
||||
.PHONY: dist
|
||||
dist: html pdf
|
||||
|
||||
.PHONY: doc
|
||||
doc: html pdf
|
||||
|
||||
.PHONY: check
|
||||
check:
|
||||
@echo "Operating system detected: ${OS}"
|
||||
@$(CHECK)
|
||||
|
||||
.PHONY: html
|
||||
html: html-stamp
|
||||
|
||||
html-stamp: $(DOCFILES) Makefile
|
||||
@rm -rf html
|
||||
@mkdir html
|
||||
@XML_CATALOG_FILES="$(CATALOG)" $(XSLTPROC) --stringparam chunker.output.encoding ISO-8859-1 \
|
||||
--xinclude --output html/ html_chunk.xsl $(DOCFILE)
|
||||
touch html-stamp
|
||||
|
||||
.PHONY: fo
|
||||
fo: ${FOFILE}
|
||||
|
||||
${FOFILE}: $(DOCFILES) Makefile
|
||||
@XML_CATALOG_FILES="$(CATALOG)" $(XSLTPROC) --xinclude --output $(FOFILE) fo.xsl $(DOCFILE)
|
||||
|
||||
.PHONY: pdf
|
||||
pdf: ${PDFFILE}
|
||||
|
||||
${PDFFILE}: ${DOCFILES} Makefile
|
||||
@$(MAKE) fo
|
||||
@fop $(FOFILE) -pdf $(PDFFILE) > /dev/null
|
||||
|
||||
.PHONY: dvi
|
||||
dvi: ${DVIFILE}
|
||||
|
||||
.PHONY: ps
|
||||
ps: ${PSFILE}
|
||||
|
||||
${PSFILE}: ${DOCFILES} Makefile
|
||||
@$(MAKE) fo
|
||||
@fop $(FOFILE) -ps $(PSFILE) > /dev/null
|
||||
|
||||
|
||||
.PHONY: txt
|
||||
txt: ${TXTFILE}
|
||||
|
||||
${TXTFILE}: ${FOFILE}
|
||||
@XML_CATALOG_FILES="$(CATALOG)" $(XSLTPROC) --xinclude --output ${HTMLFILE} html.xsl $(DOCFILE)
|
||||
lynx -dump ${HTMLFILE} > ${TXTFILE}
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -f *~ *.bak *.orig \#*\# .\#* texput.log
|
||||
@rm -rf html ${PSFILE} ${HTMLFILE} html-stamp
|
||||
@rm -f ${TMPFILES} ${FOFILE}
|
||||
@rm -f ${DVIFILE} ${TXTFILE}
|
||||
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
|
|
@ -1,5 +1,11 @@
|
|||
<!-- -*- mode: SGML; sgml-parent-document: ("user-manual.sgml" "BOOK") -*- -->
|
||||
<chapter id="beyond-ansi"><title>Beyond The &ANSI; Standard</>
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "entities.inc">
|
||||
%myents;
|
||||
]>
|
||||
|
||||
<chapter id="beyond-ansi"><title>Beyond The &ANSI; Standard</title>
|
||||
|
||||
<para>&SBCL; is mostly an implementation of the &ANSI; standard for
|
||||
Common Lisp. However, there's some important behavior which extends
|
||||
|
|
@ -7,21 +13,21 @@ or clarifies the standard, and various behavior which outright
|
|||
violates the standard.
|
||||
</para>
|
||||
|
||||
<sect1 id="non-conformance"><title>Non-Conformance With The &ANSI; Standard</>
|
||||
<sect1 id="non-conformance"><title>Non-Conformance With The &ANSI; Standard</title>
|
||||
|
||||
<para>
|
||||
Essentially every type of non-conformance is considered a bug.
|
||||
(The exceptions involve internal inconsistencies in the standard.)
|
||||
In &SBCL; 0.7.6, the master record of known bugs is in
|
||||
the <filename>BUGS</> file in the distribution.
|
||||
Some highlight information about bugs may also be found in the
|
||||
manual page. The recommended way to report bugs is through the sbcl-help or
|
||||
sbcl-devel mailings lists.
|
||||
Essentially every type of non-conformance is considered a bug.
|
||||
(The exceptions involve internal inconsistencies in the standard.)
|
||||
In &SBCL; 0.7.6, the master record of known bugs is in
|
||||
the <filename>BUGS</filename> file in the distribution.
|
||||
Some highlight information about bugs may also be found in the
|
||||
manual page. The recommended way to report bugs is through the sbcl-help or
|
||||
sbcl-devel mailings lists.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="idiosyncrasies"><title>Idiosyncrasies</>
|
||||
<sect1 id="idiosyncrasies"><title>Idiosyncrasies</title>
|
||||
|
||||
<para>The information in this section describes some of the ways
|
||||
that &SBCL; deals with choices that the &ANSI; standard
|
||||
|
|
@ -34,24 +40,24 @@ compiler from quite satisfying this principle, are discussed in the
|
|||
|
||||
<para>&SBCL; is essentially a compiler-only implementation of
|
||||
&CommonLisp;. That is, for all but a few special cases,
|
||||
<function>eval</> creates a
|
||||
lambda expression, calls <function>compile</> on the lambda
|
||||
<function>eval</function> creates a
|
||||
lambda expression, calls <function>compile</function> on the lambda
|
||||
expression to create a compiled function, and then calls
|
||||
<function>funcall</> on the resulting function object. This
|
||||
<function>funcall</function> on the resulting function object. This
|
||||
is explicitly allowed by the &ANSI; standard, but leads to some
|
||||
oddities, e.g. collapsing <function>functionp</> and
|
||||
<function>compiled-function-p</> into the same predicate.</para>
|
||||
oddities, e.g. collapsing <function>functionp</function> and
|
||||
<function>compiled-function-p</function> into the same predicate.</para>
|
||||
|
||||
<para>&SBCL; is quite strict about ANSI's definition of
|
||||
<function>defconstant</>. ANSI says that doing <function>defconstant</>
|
||||
<function>defconstant</function>. ANSI says that doing <function>defconstant</function>
|
||||
of the same symbol more than once is undefined unless the new value
|
||||
is <function>eql</> to the old value. Conforming to this specification
|
||||
is <function>eql</function> to the old value. Conforming to this specification
|
||||
is a nuisance when the "constant" value is only constant under some
|
||||
weaker test like <function>string=</> or <function>equal</>. It's
|
||||
especially annoying because, in &SBCL;, <function>defconstant</> takes effect
|
||||
weaker test like <function>string=</function> or <function>equal</function>. It's
|
||||
especially annoying because, in &SBCL;, <function>defconstant</function> takes effect
|
||||
not only at load time but also at compile time, so that just
|
||||
compiling and loading reasonable code like
|
||||
<programlisting>(defconstant +foobyte+ '(1 4))</>
|
||||
<programlisting>(defconstant +foobyte+ '(1 4))</programlisting>
|
||||
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
|
||||
|
|
@ -60,9 +66,9 @@ 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
|
||||
<function>defconstant</> either with <function>defparameter</> or
|
||||
<function>defconstant</function> either with <function>defparameter</function> or
|
||||
with a customized macro which does the right thing, possibly along the
|
||||
lines of the <function>defconstant-eqx</> macro used internally in the
|
||||
lines of the <function>defconstant-eqx</function> macro used internally in the
|
||||
implementation of &SBCL; itself. In circumstances where this is not
|
||||
appropriate, the programmer can handle the condition type
|
||||
<errortype>sb-ext:defconstant-uneql</errortype>, and choose either the
|
||||
|
|
@ -72,17 +78,17 @@ appropriate.</para>
|
|||
<para>&SBCL; gives style warnings about various kinds of perfectly
|
||||
legal code, e.g.
|
||||
<itemizedlist>
|
||||
<listitem><para><function>defmethod</> without
|
||||
<function>defgeneric</></para></listitem>
|
||||
<listitem><para>multiple <function>defun</>s of the same
|
||||
symbol</para></listitem>
|
||||
<listitem><para><function>defmethod</function> without
|
||||
<function>defgeneric</function></para></listitem>
|
||||
<listitem><para>multiple <function>defun</function>s of the same
|
||||
symbol</para></listitem>
|
||||
<listitem><para>special variables not named in the conventional
|
||||
<varname>*foo*</> style, and lexical variables unconventionally named
|
||||
in the <varname>*foo*</> style</para></listitem>
|
||||
<varname>*foo*</varname> style, and lexical variables unconventionally named
|
||||
in the <varname>*foo*</varname> style</para></listitem>
|
||||
</itemizedlist>
|
||||
This causes friction with people
|
||||
who point out that other ways of organizing code (especially
|
||||
avoiding the use of <function>defgeneric</>)
|
||||
avoiding the use of <function>defgeneric</function>)
|
||||
are just as aesthetically stylish.
|
||||
However, these warnings should be read not
|
||||
as "warning, bad aesthetics detected, you have no style" but
|
||||
|
|
@ -92,20 +98,20 @@ 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 <function>defun</>s is pointlessly annoying when you compile
|
||||
and then load a function containing <function>defun</> wrapped
|
||||
in <function>eval-when</>, and ideally should be suppressed in
|
||||
multiple <function>defun</function>s is pointlessly annoying when you compile
|
||||
and then load a function containing <function>defun</function> wrapped
|
||||
in <function>eval-when</function>, and ideally should be suppressed in
|
||||
that case, but still isn't as of &SBCL; 0.7.6.)</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="extensions"><title>Extensions</>
|
||||
<sect1 id="extensions"><title>Extensions</title>
|
||||
|
||||
<para>&SBCL; is derived from &CMUCL;, which implements many extensions
|
||||
to the &ANSI; standard. &SBCL; doesn't support as many extensions as
|
||||
&CMUCL;, but it still has quite a few.</para>
|
||||
|
||||
<sect2><title>Things Which Might Be In The Next &ANSI; Standard</>
|
||||
<sect2><title>Things Which Might Be In The Next &ANSI; Standard</title>
|
||||
|
||||
<para>&SBCL; provides extensive support for
|
||||
calling external C code, described
|
||||
|
|
@ -119,7 +125,7 @@ GCed.</para> <!-- FIXME: Actually documenting these would be good.:-| -->
|
|||
|
||||
<para>&SBCL; supports Gray streams, user-overloadable CLOS classes
|
||||
whose instances can be used as Lisp streams (e.g. passed as the
|
||||
first argument to <function>format</>). Additionally, the
|
||||
first argument to <function>format</function>). Additionally, the
|
||||
bundled contrib module <interface>sb-simple-streams</interface>
|
||||
implements a subset of the Franz Allegro simple-streams proposal.</para>
|
||||
|
||||
|
|
@ -127,23 +133,23 @@ implements a subset of the Franz Allegro simple-streams proposal.</para>
|
|||
compatible with &AMOP;; present exceptions to this (as distinct from
|
||||
current bugs) are:</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>the abstract <classname>metaobject</> class is not
|
||||
present in the class hierarchy;</para></listitem>
|
||||
<listitem><para>the <classname>standard-object</> and
|
||||
<classname>funcallable-standard-object</> classes are
|
||||
disjoint;</para></listitem>
|
||||
<listitem><para><function>compute-effective-method</> only returns
|
||||
one value, not two;</para></listitem>
|
||||
<listitem><para>the system-supplied <property>:around</> method for
|
||||
<function>compute-slots</> specialized on
|
||||
<classname>funcallable-standard-class</> does not respect the
|
||||
requested order from a user-supplied primary method.</para>
|
||||
</listitem>
|
||||
<listitem><para>the abstract <classname>metaobject</classname> class is not
|
||||
present in the class hierarchy;</para></listitem>
|
||||
<listitem><para>the <classname>standard-object</classname> and
|
||||
<classname>funcallable-standard-object</classname> classes are
|
||||
disjoint;</para></listitem>
|
||||
<listitem><para><function>compute-effective-method</function> only returns
|
||||
one value, not two;</para></listitem>
|
||||
<listitem><para>the system-supplied <property>:around</property> method for
|
||||
<function>compute-slots</function> specialized on
|
||||
<classname>funcallable-standard-class</classname> does not respect the
|
||||
requested order from a user-supplied primary method.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Threading (a.k.a Multiprocessing)</>
|
||||
<sect2><title>Threading (a.k.a Multiprocessing)</title>
|
||||
|
||||
<para>&SBCL; (as of version 0.8.3, on Linux x86 only) supports a
|
||||
fairly low-level threading interface that maps onto the host operating
|
||||
|
|
@ -187,15 +193,15 @@ start a new thread in its own `session'.
|
|||
<para>Mutexes and condition variables are available for
|
||||
managing access to shared data: see
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<programlisting>(apropos "mutex" :sb-thread)</programlisting>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<programlisting>(apropos "condition" :sb-thread)</programlisting>
|
||||
</listitem>
|
||||
<listitem> <para>and the <structname>waitqueue</structname> structure
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<programlisting>(apropos "mutex" :sb-thread)</programlisting>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<programlisting>(apropos "condition" :sb-thread)</programlisting>
|
||||
</listitem>
|
||||
<listitem> <para>and the <structname>waitqueue</structname> structure
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
and poke around in their documentation strings.</para>
|
||||
</sect3>
|
||||
|
|
@ -270,13 +276,13 @@ found to be embarrassing.
|
|||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Support For Unix</>
|
||||
<sect2><title>Support For Unix</title>
|
||||
|
||||
<para>The UNIX command line can be read from the variable
|
||||
<varname>sb-ext:*posix-argv*</>. The UNIX environment can be queried with the
|
||||
<function>sb-ext:posix-getenv</> function.</para>
|
||||
<varname>sb-ext:*posix-argv*</varname>. The UNIX environment can be queried with the
|
||||
<function>sb-ext:posix-getenv</function> function.</para>
|
||||
|
||||
<para>The &SBCL; system can be terminated with <function>sb-ext:quit</>,
|
||||
<para>The &SBCL; system can be terminated with <function>sb-ext:quit</function>,
|
||||
optionally returning a specified numeric value to the calling Unix
|
||||
process. The normal Unix idiom of terminating on end of file on input
|
||||
is also supported.</para>
|
||||
|
|
@ -301,22 +307,22 @@ don't currently remember how -->
|
|||
<sect2><title>Tools To Help Developers</title>
|
||||
|
||||
<para>&SBCL; provides a profiler and other extensions to the &ANSI;
|
||||
<function>trace</> facility. See the online function documentation for
|
||||
<function>trace</> for more information.</para>
|
||||
<function>trace</function> facility. See the online function documentation for
|
||||
<function>trace</function> for more information.</para>
|
||||
|
||||
<para>The debugger supports a number of options. Its documentation is
|
||||
accessed by typing <userinput>help</> at the debugger prompt.</para>
|
||||
accessed by typing <userinput>help</userinput> at the debugger prompt.</para>
|
||||
<!-- FIXME:
|
||||
A true debugger section in the manual would be good. Start
|
||||
with CMU CL's debugger section, but remember:
|
||||
* no QUIT command (TOPLEVEL restart instead)
|
||||
* no GO command (CONTINUE restart instead)
|
||||
* Limitations of the x86 port of the debugger should be
|
||||
documented or fixed where possible.
|
||||
* Discuss TRACE and its unification with PROFILE. -->
|
||||
* no QUIT command (TOPLEVEL restart instead)
|
||||
* no GO command (CONTINUE restart instead)
|
||||
* Limitations of the x86 port of the debugger should be
|
||||
documented or fixed where possible.
|
||||
* Discuss TRACE and its unification with PROFILE. -->
|
||||
|
||||
<para>Documentation for <function>inspect</> is accessed by typing
|
||||
<userinput>help</> at the <function>inspect</> prompt.</para>
|
||||
<para>Documentation for <function>inspect</function> is accessed by typing
|
||||
<userinput>help</userinput> at the <function>inspect</function> prompt.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
|
|
@ -325,7 +331,7 @@ accessed by typing <userinput>help</> at the debugger prompt.</para>
|
|||
<para>&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 See the
|
||||
documentation for <function>sb-ext:save-lisp-and-die</> for more
|
||||
documentation for <function>sb-ext:save-lisp-and-die</function> for more
|
||||
information.</para>
|
||||
|
||||
<note><para>&SBCL; has inherited from &CMUCL; various hooks to allow
|
||||
|
|
@ -336,7 +342,7 @@ up. If you have urgent need of them, look at the code in
|
|||
developers' mailing list.</para></note>
|
||||
|
||||
<note><para>&SBCL; has various hooks inherited from &CMUCL;, like
|
||||
<function>sb-ext:float-denormalized-p</>, to allow a program to take
|
||||
<function>sb-ext:float-denormalized-p</function>, to allow a program to take
|
||||
advantage of &IEEE; floating point arithmetic properties which aren't
|
||||
conveniently or efficiently expressible using the &ANSI; standard. These
|
||||
look good, and their interface looks good, but &IEEE; support is
|
||||
|
|
@ -361,23 +367,23 @@ fixed addresses, a precondition for using copy-on-write to share code
|
|||
between multiple Lisp processes. is less important with modern
|
||||
generational garbage collectors. </para>
|
||||
|
||||
<para>The <function>sb-ext:truly-the</> declares the type of the
|
||||
<para>The <function>sb-ext:truly-the</function> declares the type of the
|
||||
result of the operations, producing its argument; the declaration is
|
||||
not checked. In short: don't use it.</para>
|
||||
|
||||
<para>The <function>sb-ext:freeze-type</> declaration declares that a
|
||||
<para>The <function>sb-ext:freeze-type</function> declaration declares that a
|
||||
type will never change, which can make type testing
|
||||
(<function>typep</>, etc.) more efficient for structure types.</para>
|
||||
(<function>typep</function>, etc.) more efficient for structure types.</para>
|
||||
|
||||
<para>The <function>sb-ext:constant-function</> declaration specifies
|
||||
<para>The <function>sb-ext:constant-function</function> declaration specifies
|
||||
that a function will always return the same value for the same
|
||||
arguments, which may allow the compiler to optimize calls
|
||||
to it. This is appropriate for functions like <function>sqrt</>, but
|
||||
is <emphasis>not</> appropriate for functions like <function>aref</>,
|
||||
to it. This is appropriate for functions like <function>sqrt</function>, but
|
||||
is <emphasis>not</emphasis> appropriate for functions like <function>aref</function>,
|
||||
which can change their return values when the underlying data are
|
||||
changed.</para>
|
||||
<!-- FIXME: This declaration does not seem to be supported in the --
|
||||
-- current compiler. -->
|
||||
<!-- FIXME: This declaration does not seem to be supported in the
|
||||
current compiler. -->
|
||||
|
||||
</sect2>
|
||||
|
||||
43
doc/catalog-debian.xml
Normal file
43
doc/catalog-debian.xml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE catalog
|
||||
PUBLIC "-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN"
|
||||
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
|
||||
|
||||
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
|
||||
|
||||
<!-- The directory DTD and stylesheet files are installed under -->
|
||||
<group xml:base="file:///usr/share/sgml/docbook/" >
|
||||
|
||||
<!-- Resolve DTD URL system ID to local file -->
|
||||
<rewriteSystem
|
||||
systemIdStartString="http://www.oasis-open.org/docbook/xml/4.2/"
|
||||
rewritePrefix="dtd/xml/4.2/" />
|
||||
<!-- Resolve stylesheet URL to local file -->
|
||||
<rewriteURI
|
||||
uriStartString="http://docbook.sourceforge.net/release/xsl/current/"
|
||||
rewritePrefix="stylesheet/xsl/nwalsh/" />
|
||||
|
||||
<!-- Resolve DTD PUBLIC identifiers -->
|
||||
<nextCatalog catalog="dtd/xml/4.2/catalog.xml" />
|
||||
|
||||
<!-- To resolve simple DTD SYSTEM identifiers. -->
|
||||
<!-- Note: this does not work with Java resolver -->
|
||||
<!-- classes in Saxon or Xalan -->
|
||||
<system
|
||||
systemId="docbook.dtd"
|
||||
uri="dtd/xml/4.2/xml/docbookx.dtd" />
|
||||
|
||||
<!-- To resolve short stylesheet references -->
|
||||
<uri
|
||||
name="docbook_html.xsl"
|
||||
uri="stylesheet/xsl/nwalsh/xhtml/docbook.xsl" />
|
||||
<uri
|
||||
name="docbook_chunk.xsl"
|
||||
uri="stylesheet/xsl/nwalsh/xhtml/chunk.xsl" />
|
||||
<uri
|
||||
name="docbook_fo.xsl"
|
||||
uri="stylesheet/xsl/nwalsh/fo/docbook.xsl" />
|
||||
|
||||
</group>
|
||||
|
||||
</catalog>
|
||||
43
doc/catalog-suse.xml
Normal file
43
doc/catalog-suse.xml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE catalog
|
||||
PUBLIC "-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN"
|
||||
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
|
||||
|
||||
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
|
||||
|
||||
<!-- The directory DTD and stylesheet files are installed under -->
|
||||
<group xml:base="file:///usr/share/sgml/" >
|
||||
|
||||
<!-- Resolve DTD URL system ID to local file -->
|
||||
<rewriteSystem
|
||||
systemIdStartString="http://www.oasis-open.org/docbook/xml/4.2/"
|
||||
rewritePrefix="db42xml/" />
|
||||
<!-- Resolve stylesheet URL to local file -->
|
||||
<rewriteURI
|
||||
uriStartString="http://docbook.sourceforge.net/release/xsl/current/"
|
||||
rewritePrefix="docbook/docbook-xsl/" />
|
||||
|
||||
<!-- Resolve DTD PUBLIC identifiers -->
|
||||
<nextCatalog catalog="db42xml/catalog.xml" />
|
||||
|
||||
<!-- To resolve simple DTD SYSTEM identifiers. -->
|
||||
<!-- Note: this does not work with Java resolver -->
|
||||
<!-- classes in Saxon or Xalan -->
|
||||
<system
|
||||
systemId="docbook.dtd"
|
||||
uri="db42xml/docbookx.dtd" />
|
||||
|
||||
<!-- To resolve short stylesheet references -->
|
||||
<uri
|
||||
name="docbook_html.xsl"
|
||||
uri="docbook/docbook-xsl/xhtml/docbook.xsl" />
|
||||
<uri
|
||||
name="docbook_chunk.xsl"
|
||||
uri="docbook/docbook-xsl/xhtml/chunk.xsl" />
|
||||
<uri
|
||||
name="docbook_fo.xsl"
|
||||
uri="docbook/docbook-xsl/fo/docbook.xsl" />
|
||||
|
||||
</group>
|
||||
|
||||
</catalog>
|
||||
|
|
@ -1,933 +0,0 @@
|
|||
<chapter id="compiler"><title>The Compiler</>
|
||||
|
||||
<para>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 <link linkend="efficiency">their own
|
||||
chapter</link>.</para>
|
||||
|
||||
<sect1><title>Error Messages</>
|
||||
<!--INDEX {error messages}{compiler}-->
|
||||
<!--INDEX {compiler error messages}-->
|
||||
|
||||
<para>The compiler supplies a large amount of source location
|
||||
information in error messages. The error messages contain a lot of
|
||||
detail in a terse format, so they may be confusing at first. Error
|
||||
messages will be illustrated using this example program:
|
||||
<programlisting>(defmacro zoq (x)
|
||||
`(roq (ploq (+ ,x 3))))
|
||||
|
||||
(defun foo (y)
|
||||
(declare (symbol y))
|
||||
(zoq y))</programlisting>
|
||||
The main problem with this program is that it is trying to add
|
||||
<literal>3</> to a symbol. Note also that the functions
|
||||
<function>roq</> and <function>ploq</> aren't defined anywhere.
|
||||
</para>
|
||||
|
||||
<sect2><title>The Parts of the Error Message</>
|
||||
|
||||
<para>When processing this program, the compiler will produce this warning:
|
||||
<screen>file: /tmp/foo.lisp
|
||||
|
||||
in: DEFUN FOO
|
||||
(ZOQ Y)
|
||||
--> ROQ PLOQ +
|
||||
==>
|
||||
Y
|
||||
caught WARNING:
|
||||
Result is a SYMBOL, not a NUMBER.</screen>
|
||||
In this example we see each of the six possible parts of a compiler error
|
||||
message:
|
||||
<orderedlist>
|
||||
<listitem><para><computeroutput>File: /tmp/foo.lisp</>
|
||||
This 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
|
||||
<function>with-compilation-unit</> is used to delay undefined
|
||||
warnings.</para></listitem>
|
||||
<listitem><para><computeroutput>in: DEFUN FOO</> This is the
|
||||
definition top level form responsible for the error. It is
|
||||
obtained by taking the first two elements of the enclosing form
|
||||
whose first element is a symbol beginning with <quote><literal>def</></>.
|
||||
If there is no such enclosing <quote><literal>def</></> form, then the
|
||||
outermost form is used. If there are multiple <literal>def</>
|
||||
forms, then they are all printed from the outside in, separated by
|
||||
<literal>=></>'s. In this example, the problem was in the
|
||||
<function>defun</> for <function>foo</>.</para></listitem>
|
||||
<listitem><para><computeroutput>(ZOQ Y)</> This is the
|
||||
<emphasis>original source</> form responsible for the error.
|
||||
Original source means that the form directly appeared in the
|
||||
original input to the compiler, i.e. in the lambda passed to
|
||||
<function>compile</> or in the top level form read from the
|
||||
source file. In this example, the expansion of the <function>zoq</>
|
||||
macro was responsible for the error.</para></listitem>
|
||||
<listitem><para><computeroutput>--> ROQ PLOQ +</> This is the
|
||||
<emphasis>processing path</> that the compiler used to produce
|
||||
the errorful code. 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 <function>roq</>, <function>ploq</> and
|
||||
<function>+</>. These calls resulted from the expansion of
|
||||
the <function>zoq</> macro.</para></listitem>
|
||||
<listitem><para><computeroutput>==> Y</> This is the
|
||||
<emphasis>actual source</> responsible for the error. 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 <varname>y</>.</para></listitem>
|
||||
<listitem><para>
|
||||
<computeroutput>caught WARNING: Result is a SYMBOL, not a NUMBER.</>
|
||||
This is the <emphasis>explanation</> of the problem. In this
|
||||
example, the problem is that <varname>y</> evaluates to a symbol,
|
||||
but is in a context where a number is required (the argument
|
||||
to <function>+</>).</para></listitem>
|
||||
</orderedlist>
|
||||
|
||||
Note that each part of the error message is distinctively marked:
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para> <computeroutput>file:</> and <computeroutput>in:</>
|
||||
mark the file and definition, respectively.</para></listitem>
|
||||
<listitem><para> The original source is an indented form with no
|
||||
prefix.</para></listitem>
|
||||
<listitem><para> Each line of the processing path is prefixed with
|
||||
<computeroutput>--></computeroutput></para></listitem>
|
||||
<listitem><para> The actual source form is indented like the original
|
||||
source, but is marked by a preceding <computeroutput>==></> line.
|
||||
</para></listitem>
|
||||
<listitem><para> The explanation is prefixed with the error
|
||||
severity, which can be <computeroutput>caught ERROR:</>,
|
||||
<computeroutput>caught WARNING:</>,
|
||||
<computeroutput>caught STYLE-WARNING:</>, or
|
||||
<computeroutput>note:</>. </para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>Each part of the error message is more specific than the preceding
|
||||
one. If consecutive error messages are for nearby locations, then the
|
||||
front part of the error 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:
|
||||
<screen>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</screen>
|
||||
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:
|
||||
<computeroutput>[Last message occurs <replaceable>repeats</> times]</>
|
||||
where <replaceable>repeats</> is the number of times the message
|
||||
was given.</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>The Original and Actual Source</>
|
||||
|
||||
<para>The <emphasis>original source</> displayed will almost always be
|
||||
a list. If the actual source for an error 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.)</para>
|
||||
|
||||
<para>When the <emphasis>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.</para>
|
||||
|
||||
<para>Keep in mind that when the compiler displays a source form
|
||||
in an error message, it always displays the most specific (innermost)
|
||||
responsible form. For example, compiling this function
|
||||
<programlisting>(defun bar (x)
|
||||
(let (a)
|
||||
(declare (fixnum a))
|
||||
(setq a (foo x))
|
||||
a))</programlisting>
|
||||
gives this error message
|
||||
<screen>in: DEFUN BAR
|
||||
(LET (A) (DECLARE (FIXNUM A)) (SETQ A (FOO X)) A)
|
||||
caught WARNING: The binding of A is not a FIXNUM:
|
||||
NIL</screen>
|
||||
This error message is not saying <quote>there is a problem somewhere in
|
||||
this <function>let</></quote> — it is saying that there is a
|
||||
problem with the <function>let</> itself. In this example, the problem
|
||||
is that <varname>a</>'s <literal>nil</> initial value is not a
|
||||
<type>fixnum</>.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>The Processing Path</>
|
||||
<!--INDEX processing path-->
|
||||
<!--INDEX macroexpansion-->
|
||||
<!--INDEX source-to-source transformation-->
|
||||
|
||||
<para>The processing path is mainly useful for debugging macros, so if
|
||||
you don't write macros, you can probably ignore it. Consider this
|
||||
example:
|
||||
|
||||
<programlisting>(defun foo (n)
|
||||
(dotimes (i n *undefined*)))
|
||||
</programlisting>
|
||||
|
||||
Compiling results in this error message:
|
||||
|
||||
<screen>in: DEFUN FOO
|
||||
(DOTIMES (I N *UNDEFINED*))
|
||||
--> DO BLOCK LET TAGBODY RETURN-FROM
|
||||
==>
|
||||
(PROGN *UNDEFINED*)
|
||||
caught STYLE-WARNING:
|
||||
undefined variable: *UNDEFINED*</screen>
|
||||
|
||||
Note that <function>do</> appears in the processing path. This is because
|
||||
<function>dotimes</> expands into:
|
||||
|
||||
<programlisting>(do ((i 0 (1+ i)) (#:g1 n))
|
||||
((>= i #:g1) *undefined*)
|
||||
(declare (type unsigned-byte i)))</programlisting>
|
||||
|
||||
The rest of the processing path results from the expansion
|
||||
of <function>do</>:
|
||||
|
||||
<programlisting>
|
||||
(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*)))))
|
||||
</programlisting>
|
||||
|
||||
In this example, the compiler descended into the <function>block</>,
|
||||
<function>let</>, <function>tagbody</> and <function>return-from</> to
|
||||
reach the <function>progn</> printed as the actual source. This is a
|
||||
place where the <quote>actual source appears in explanation</> rule
|
||||
was applied. The innermost actual source form was the symbol
|
||||
<varname>*undefined*</> itself, but that also appeared in the
|
||||
explanation, so the compiler backed out one level.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Error Severity</>
|
||||
<!--INDEX severity of compiler errors -->
|
||||
<!--INDEX compiler error severity -->
|
||||
|
||||
<para>There are four levels of compiler error severity:
|
||||
<wordasword>error</>, <wordasword>warning</>, <wordasword>style
|
||||
warning</>, and <wordasword>note</>. The first three levels correspond
|
||||
to condition classes which are defined in the &ANSI; standard for
|
||||
&CommonLisp; and which have special significance to the
|
||||
<function>compile</> and <function>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, <wordasword>note</>, is used for problems which are too mild
|
||||
for the standard condition classes, typically hints about how
|
||||
efficiency might be improved.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Errors During Macroexpansion</>
|
||||
<!--INDEX {macroexpansion}{errors during}-->
|
||||
|
||||
<para>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 <varname>*break-on-signals*</> to
|
||||
<literal>error</>. For example, this definition:
|
||||
|
||||
<programlisting>(defun foo (e l)
|
||||
(do ((current l (cdr current))
|
||||
((atom current) nil))
|
||||
(when (eq (car current) e) (return current))))</programlisting>
|
||||
|
||||
gives this error:
|
||||
|
||||
<screen>in: DEFUN FOO
|
||||
(DO ((CURRENT L #) (# NIL)) (WHEN (EQ # 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)</screen>
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Read Errors</>
|
||||
<!--INDEX {read errors}{compiler}-->
|
||||
|
||||
<para>&SBCL;'s compiler (unlike &CMUCL;'s) 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.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<!-- 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{defvar}{}{error-print-length}
|
||||
_ \defvarx{error-print-level}
|
||||
_
|
||||
_ These variables are the print level and print length used in
|
||||
_ printing error messages. The default values are \code{5} and
|
||||
_ \code{3}. If null, the global values of \code{*print-level*} and
|
||||
_ \code{*print-length*} are used.
|
||||
_ \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}
|
||||
_
|
||||
_ -->
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1><title>The Compiler's Handling of Types</>
|
||||
|
||||
<para>The most unusual features of the &SBCL; compiler (which is
|
||||
very similar to the original &CMUCL; compiler, also known as
|
||||
&Python;) is its unusually sophisticated understanding of the
|
||||
&CommonLisp; type system and its unusually 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 <link
|
||||
linkend="efficiency">in the chapter on performance</>, the use of
|
||||
appropriate type declarations can be very important for performance as
|
||||
well.)</para>
|
||||
|
||||
<para>The &SBCL; compiler, like the related compiler in &CMUCL;,
|
||||
treats type declarations much differently than other Lisp compilers.
|
||||
By default (<emphasis>i.e.</>, at ordinary levels of the
|
||||
<parameter>safety</> compiler optimization parameter), the compiler
|
||||
doesn't blindly believe most type declarations; it considers them
|
||||
assertions about the program that should be checked.</para>
|
||||
|
||||
<para>The &SBCL; compiler also has a greater knowledge of the
|
||||
&CommonLisp; type system than other compilers. Support is incomplete
|
||||
only for the <type>not</>, <type>and</> and <type>satisfies</>
|
||||
types.
|
||||
<!-- FIXME: See also sections \ref{advanced-type-stuff}
|
||||
and \ref{type-inference}, once we snarf them from the
|
||||
CMU CL manual. -->
|
||||
</para>
|
||||
|
||||
<sect2 id=compiler-impl-limitations><title>Implementation Limitations</>
|
||||
|
||||
<para>
|
||||
Ideally, the compiler would consider <emphasis>all</> type declarations to
|
||||
be assertions, so that adding type declarations to a program, no
|
||||
matter how incorrect they might be, would <emphasis>never</> cause
|
||||
undefined behavior. As of &SBCL; version 0.8.1, the compiler is known to
|
||||
fall short of this goal in two areas:
|
||||
<itemizedlist>
|
||||
<listitem><para><function>Proclaim</>ed constraints on argument and
|
||||
result types of a function are supposed to be checked by the
|
||||
function. If the function type is proclaimed before function
|
||||
definition, type checks are inserted by the compiler, but the
|
||||
standard allows the reversed order, in which case the compiler
|
||||
will trust the declaration.</para></listitem>
|
||||
<listitem><para>The compiler cannot check types of an unknown number
|
||||
of values; if the number of generated values is unknown, but the
|
||||
number of consumed is known, only consumed values are
|
||||
checked.</para></listitem>
|
||||
<listitem><para>There are a few poorly characterized but apparently
|
||||
very uncommon situations where a type declaration in an unexpected
|
||||
location will be trusted and never checked by the
|
||||
compiler.</para></listitem>
|
||||
</itemizedlist></para>
|
||||
|
||||
<para>These are important bugs, but are not necessarily easy to fix,
|
||||
so they may, alas, remain in the system for a while.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Type Errors at Compile Time</>
|
||||
<!--INDEX compile time type errors-->
|
||||
<!--INDEX type checking}{at compile time}-->
|
||||
|
||||
<para>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:
|
||||
|
||||
<programlisting>(defun raz (foo)
|
||||
(let ((x (case foo
|
||||
(:this 13)
|
||||
(:that 9)
|
||||
(:the-other 42))))
|
||||
(declare (fixnum x))
|
||||
(foo x)))
|
||||
</programlisting>
|
||||
|
||||
Compilation produces this warning:
|
||||
|
||||
<screen>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</screen>
|
||||
|
||||
In this case, the warning means that if <varname>foo</> isn't any of
|
||||
<literal>:this</>, <literal>:that</> or <literal>:the-other</>, then
|
||||
<varname>x</> will be initialized to <literal>nil</>, which the
|
||||
<type>fixnum</> declaration makes illegal. The warning will go away if
|
||||
<function>ecase</> is used instead of <function>case</>, or if
|
||||
<literal>:the-other</> is changed to <literal>t</>.</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>
|
||||
Type warnings are inhibited when the
|
||||
<parameter>sb-ext:inhibit-warnings</> optimization quality is
|
||||
<literal>3</>. (See <link linkend="compiler-policy">the section
|
||||
on compiler policy</>.) This can be used in a local declaration
|
||||
to inhibit type warnings in a code fragment that has spurious
|
||||
warnings.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="precisetypechecking"><title>Precise Type Checking</>
|
||||
<!--INDEX precise type checking-->
|
||||
<!--INDEX {type checking}{precise}-->
|
||||
|
||||
<para>With the default compilation policy, all type declarations are
|
||||
precisely checked, except in a few situations where they are simply
|
||||
ignored instead. Precise checking means that the check is done as
|
||||
though <function>typep</> had been called with the exact type
|
||||
specifier that appeared in the declaration. In &SBCL;, adding type
|
||||
declarations makes code safer. (Except that as noted <link
|
||||
linkend="compiler-impl-limitations">elsewhere</link>, remaining bugs
|
||||
in the compiler's handling of types unfortunately provide some
|
||||
exceptions to this rule.)</para>
|
||||
|
||||
<para>If a variable is declared to be
|
||||
<type>(integer 3 17)</> then its value must always be an integer
|
||||
between <literal>3</> and <literal>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 <type>and</> type specifier.</para>
|
||||
|
||||
<para>Argument and result type declarations are automatically
|
||||
enforced. If you declare the type of a function argument, a type check
|
||||
will be done when that function is called. In a function call, the
|
||||
called function does the argument type checking.</para>
|
||||
|
||||
<para>The types of structure slots are also checked. The value of a
|
||||
structure slot must always be of the type indicated in any
|
||||
<literal>:type</> slot option. </para>
|
||||
|
||||
<para>In traditional &CommonLisp; compilers, not all type assertions
|
||||
are checked, and type checks are not precise. Traditional compilers
|
||||
blindly trust explicit type declarations, but may check the argument
|
||||
type assertions for built-in functions. Type checking is not precise,
|
||||
since the argument type checks will be for the most general type legal
|
||||
for that argument. In many systems, type declarations suppress what
|
||||
little type checking is being done, so adding type declarations makes
|
||||
code unsafe. This is a problem since it discourages writing type
|
||||
declarations during initial coding. In addition to being more error
|
||||
prone, adding type declarations during tuning also loses all the
|
||||
benefits of debugging with checked type assertions.</para>
|
||||
|
||||
<para>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
|
||||
<type>or</>, <type>member</>, and other list-style type specifiers.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="weakened-type-checking"><title>Weakened Type Checking</>
|
||||
<!--INDEX weakened type checking-->
|
||||
<!--INDEX {type checking}{weakened}-->
|
||||
|
||||
<para>At one time, &CMUCL; supported another level of type checking,
|
||||
<quote>weakened type checking</>, when the value for the
|
||||
<parameter>speed</> optimization quality is greater than
|
||||
<parameter>safety</>, and <parameter>safety</> is not <literal>0</>.
|
||||
The &CMUCL; manual still has a description of it, but even the CMU CL
|
||||
code no longer corresponds to the manual. Some of this partial safety
|
||||
checking lingers on in SBCL, but it's not a supported feature, and
|
||||
should not be relied on. If you ask the compiler to optimize
|
||||
<parameter>speed</> to a higher level than <parameter>safety</>,
|
||||
your program is performing without a safety net, because &SBCL; may
|
||||
at its option believe any or all type declarations with either partial
|
||||
or nonexistent runtime checking.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Getting Existing Programs to Run</>
|
||||
<!--INDEX {existing programs}{to run}-->
|
||||
<!--INDEX {types}{portability}-->
|
||||
<!--INDEX {compatibility with other Lisps}
|
||||
(should also have an entry in the non-&ANSI;-isms section)-->
|
||||
|
||||
<para>Since &SBCL;'s compiler, like &CMUCL;'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.</para>
|
||||
|
||||
<para>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 <parameter>safety</> optimization) and
|
||||
then test this safe version. After the checking version has been
|
||||
tested, then you can consider weakening or eliminating type checks.
|
||||
<emphasis>This applies even to previously debugged
|
||||
programs,</emphasis> because the &SBCL; compiler does much more type
|
||||
inference than other &CommonLisp; compilers, so an incorrect
|
||||
declaration can do more damage.</para>
|
||||
|
||||
<para>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:
|
||||
|
||||
<programlisting>(prog (foo)
|
||||
(declare (fixnum foo))
|
||||
(setq foo ...)
|
||||
...)</programlisting>
|
||||
|
||||
Here <varname>foo</> is given an initial value of <literal>nil</>, but
|
||||
is declared to be a <type>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
|
||||
|
||||
<programlisting>(prog (foo)
|
||||
(declare (type (or fixnum null) foo))
|
||||
(setq foo ...)
|
||||
...)</programlisting>
|
||||
|
||||
or change the initial value
|
||||
|
||||
<programlisting>(prog ((foo 0))
|
||||
(declare (fixnum foo))
|
||||
(setq foo ...)
|
||||
...)</programlisting>
|
||||
|
||||
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.</para>
|
||||
|
||||
<para>Another declaration problem occasionally encountered is
|
||||
incorrect declarations on <function>defmacro</> arguments. This can happen
|
||||
when a function is converted into a macro. Consider this macro:
|
||||
|
||||
<programlisting>(defmacro my-1+ (x)
|
||||
(declare (fixnum x))
|
||||
`(the fixnum (1+ ,x)))</programlisting>
|
||||
|
||||
Although legal and well-defined &CommonLisp; code, this meaning of
|
||||
this definition is almost certainly not what the writer intended. For
|
||||
example, this call is illegal:
|
||||
|
||||
<programlisting>(my-1+ (+ 4 5))</>
|
||||
|
||||
This call is illegal because the argument to the macro is
|
||||
<literal>(+ 4 5)</>, which is a <type>list</>, not a
|
||||
<type>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
|
||||
<function>the</> in the expansion:
|
||||
|
||||
<programlisting>(defmacro my-1+ (x)
|
||||
`(the fixnum (1+ (the fixnum ,x))))</programlisting>
|
||||
|
||||
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.-->
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Some more subtle problems are caused by incorrect declarations that
|
||||
can't be detected at compile time. Consider this code:
|
||||
|
||||
<programlisting>(do ((pos 0 (position #\a string :start (1+ pos))))
|
||||
((null pos))
|
||||
(declare (fixnum pos))
|
||||
...)</programlisting>
|
||||
|
||||
Although <varname>pos</> is almost always a <varname>fixnum</>, it is
|
||||
<literal>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
|
||||
<function>position</> will complain because <literal>(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 <varname>pos</> is always a <type>fixnum</>, it
|
||||
believes that <varname>pos</> is never <literal>nil</>, so
|
||||
<literal>(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.</para>
|
||||
|
||||
<para>In this case, the fix is to weaken the type declaration to
|
||||
<type>(or fixnum null)</>.
|
||||
<footnote><para>Actually, this declaration is
|
||||
unnecessary in &SBCL;, since it already knows that <function>position</>
|
||||
returns a non-negative <type>fixnum</> or <literal>nil</>.
|
||||
</para></footnote>
|
||||
|
||||
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 <type>fixnum</>, since <literal>nil</>
|
||||
is not a legal numeric argument. Another possible fix would be to say:
|
||||
|
||||
<programlisting>(do ((pos 0 (position #\a string :start (1+ pos))))
|
||||
((null pos))
|
||||
(let ((pos pos))
|
||||
(declare (fixnum pos))
|
||||
...))</programlisting>
|
||||
|
||||
This would be preferable in some circumstances, since it would allow a
|
||||
non-standard representation to be used for the local <varname>pos</>
|
||||
variable in the loop body.
|
||||
<!-- FIXME: <xref>ND-variables</>, once we crib the text from the
|
||||
CMU CL manual. -->
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="compiler-policy"><title>Compiler Policy</>
|
||||
|
||||
<para>As of version 0.6.4, &SBCL; still uses most of the &CMUCL; code
|
||||
for compiler policy. The &CMUCL; code has many features and high-quality
|
||||
documentation, but the two unfortunately do not match. So this area of
|
||||
the compiler and its interface needs to be cleaned up. Meanwhile, here
|
||||
is some rudimentary documentation on the current behavior of the
|
||||
system.</para>
|
||||
|
||||
<para>Compiler policy is controlled by the <parameter>optimize</>
|
||||
declaration. The compiler supports the &ANSI; optimization qualities,
|
||||
and also an extension <parameter>sb-ext:inhibit-warnings</>.</para>
|
||||
|
||||
<para>Ordinarily, when the <parameter>speed</> quality is high, the
|
||||
compiler emits notes to notify the programmer about its inability to
|
||||
apply various optimizations. Setting
|
||||
<parameter>sb-ext:inhibit-warnings</> to a value at least as large as
|
||||
the <parameter>speed</> quality inhibits this notification. This can
|
||||
be useful to suppress notes about code which is known to be
|
||||
unavoidably inefficient. (For example, the compiler issues notes about
|
||||
having to use generic arithmetic instead of fixnum arithmetic, which
|
||||
is not helpful for code which by design supports arbitrary-sized
|
||||
integers instead of being limited to fixnums.)</para>
|
||||
|
||||
<note><para>The basic functionality of the <parameter>optimize
|
||||
inhibit-warnings</> extension will probably be supported in all future
|
||||
versions of the system, but it will probably be renamed when the
|
||||
compiler and its interface are cleaned up. The current name is
|
||||
misleading, because it mostly inhibits optimization notes, not
|
||||
warnings. And making it an optimization quality is misleading, because
|
||||
it shouldn't affect the resulting code at all. It may become a
|
||||
declaration identifier with a name like
|
||||
<parameter>sb-ext:inhibit-notes</>, so that what's currently written
|
||||
|
||||
<programlisting>(declaim (optimize (sb-ext:inhibit-warnings 2)))</>
|
||||
|
||||
would become something like
|
||||
|
||||
<programlisting>(declaim (sb-ext:inhibit-notes 2))</>
|
||||
|
||||
</para></note>
|
||||
|
||||
<para> (In early versions of SBCL, a <parameter>speed</> value of zero
|
||||
was used to enable byte compilation, but since version 0.7.0, SBCL
|
||||
only supports native compilation.)</para>
|
||||
|
||||
<para>When <parameter>safety</> is zero, almost all runtime checking
|
||||
of types, array bounds, and so forth is suppressed.</para>
|
||||
|
||||
<para>When <parameter>safety</> is less than <parameter>speed</>, any
|
||||
and all type checks may be suppressed. At some point in the past,
|
||||
&CMUCL; had <link linkend="weakened-type-checking">a more nuanced
|
||||
interpretation of this</link>. However, &SBCL; doesn't support that
|
||||
interpretation, and setting <parameter>safety</> less than
|
||||
<parameter>speed</> may have roughly the same effect as setting
|
||||
<parameter>safety</> to zero.</para>
|
||||
|
||||
<para>The value of <parameter>space</> mostly influences the
|
||||
compiler's decision whether to inline operations, which tend to
|
||||
increase the size of programs. Use the value <literal>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 swapping.</para>
|
||||
|
||||
<!-- 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</>
|
||||
_ INDEX {policy}{compiler}
|
||||
_ INDEX compiler policy
|
||||
_
|
||||
_<para>The policy is what tells the compiler <emphasis>how</> 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</> declaration; other declarations and variables
|
||||
_control more specific aspects of compilation.</para>
|
||||
_
|
||||
_\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.
|
||||
_
|
||||
_\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)
|
||||
_-->
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Open Coding and Inline Expansion</>
|
||||
<!--INDEX open-coding-->
|
||||
<!--INDEX inline expansion-->
|
||||
<!--INDEX static functions-->
|
||||
|
||||
<para>Since &CommonLisp; 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:
|
||||
<itemizedlist>
|
||||
<listitem><para> 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 <function>trace</> macro. Special-casing
|
||||
of standard functions can be inhibited using the
|
||||
<parameter>notinline</> declaration.</para></listitem>
|
||||
<listitem><para> 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 <link linkend="compiler-policy">compiler policy</link>.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>When a function call is <emphasis>open coded</>, inline code whose
|
||||
effect is equivalent to the function call is substituted for that
|
||||
function call. When a function call is <emphasis>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
|
||||
<function>nthcdr</> were to be open coded, then
|
||||
|
||||
<programlisting>(nthcdr 4 foobar)</programlisting>
|
||||
|
||||
might turn into
|
||||
|
||||
<programlisting>(cdr (cdr (cdr (cdr foobar))))</>
|
||||
|
||||
or even
|
||||
|
||||
<programlisting>(do ((i 0 (1+ i))
|
||||
(list foobar (cdr foobar)))
|
||||
((= i 4) list))</programlisting>
|
||||
|
||||
If <function>nth</> is closed coded, then
|
||||
|
||||
<programlisting>
|
||||
(nth x l)
|
||||
</programlisting>
|
||||
|
||||
might stay the same, or turn into something like
|
||||
|
||||
<programlisting>
|
||||
(car (nthcdr x l))
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>In general, open coding sacrifices space for speed, but some
|
||||
functions (such as <function>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 <emphasis>static call</>. Static function call
|
||||
uses a more efficient calling convention that forbids
|
||||
redefinition.</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
942
doc/compiler.xml
Normal file
942
doc/compiler.xml
Normal file
|
|
@ -0,0 +1,942 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "entities.inc">
|
||||
%myents;
|
||||
]>
|
||||
|
||||
<chapter id="compiler"><title>The Compiler</title>
|
||||
|
||||
<para>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 <link linkend="efficiency">their own
|
||||
chapter</link>.</para>
|
||||
|
||||
<sect1 id="error-messages"><title>Error Messages</title>
|
||||
<!--INDEX {error messages}{compiler}-->
|
||||
<!--INDEX {compiler error messages}-->
|
||||
|
||||
<para>The compiler supplies a large amount of source location
|
||||
information in error messages. The error messages contain a lot of
|
||||
detail in a terse format, so they may be confusing at first. Error
|
||||
messages will be illustrated using this example program:
|
||||
<programlisting>(defmacro zoq (x)
|
||||
`(roq (ploq (+ ,x 3))))
|
||||
|
||||
(defun foo (y)
|
||||
(declare (symbol y))
|
||||
(zoq y))</programlisting>
|
||||
The main problem with this program is that it is trying to add
|
||||
<literal>3</literal> to a symbol. Note also that the functions
|
||||
<function>roq</function> and <function>ploq</function> aren't defined anywhere.
|
||||
</para>
|
||||
|
||||
<sect2><title>The Parts of the Error Message</title>
|
||||
|
||||
<para>When processing this program, the compiler will produce this
|
||||
warning:
|
||||
|
||||
<screen>file: /tmp/foo.lisp
|
||||
|
||||
in: DEFUN FOO
|
||||
(ZOQ Y)
|
||||
--> ROQ PLOQ +
|
||||
==>
|
||||
Y
|
||||
caught WARNING:
|
||||
Result is a SYMBOL, not a NUMBER.</screen>
|
||||
In this example we see each of the six possible parts of a compiler error
|
||||
message:
|
||||
<orderedlist>
|
||||
<listitem><para><computeroutput>File: /tmp/foo.lisp</computeroutput>
|
||||
This 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
|
||||
<function>with-compilation-unit</function> is used to delay
|
||||
undefined warnings.</para></listitem>
|
||||
<listitem><para><computeroutput>in: DEFUN FOO</computeroutput> This is the
|
||||
definition top level form responsible for the error. It is
|
||||
obtained by taking the first two elements of the enclosing form
|
||||
whose first element is a symbol beginning with <quote><literal>def</literal></quote>.
|
||||
If there is no such enclosing <quote><literal>def</literal></quote> form, then the
|
||||
outermost form is used. If there are multiple <literal>def</literal>
|
||||
forms, then they are all printed from the outside in, separated by
|
||||
<literal>=></literal>'s. In this example, the problem was in the
|
||||
<function>defun</function> for <function>foo</function>.</para></listitem>
|
||||
<listitem><para><computeroutput>(ZOQ Y)</computeroutput> This is the
|
||||
<emphasis>original source</emphasis> form responsible for the error.
|
||||
Original source means that the form directly appeared in the
|
||||
original input to the compiler, i.e. in the lambda passed to
|
||||
<function>compile</function> or in the top level form read from the
|
||||
source file. In this example, the expansion of the <function>zoq</function>
|
||||
macro was responsible for the error.</para></listitem>
|
||||
<listitem><para><computeroutput>--> ROQ PLOQ +</computeroutput> This is the
|
||||
<emphasis>processing path</emphasis> that the compiler used to produce
|
||||
the errorful code. 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 <function>roq</function>, <function>ploq</function> and
|
||||
<function>+</function>. These calls resulted from the expansion of
|
||||
the <function>zoq</function> macro.</para></listitem>
|
||||
<listitem><para><computeroutput>==> Y</computeroutput> This is the
|
||||
<emphasis>actual source</emphasis> responsible for the error. 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 <varname>y</varname>.</para></listitem>
|
||||
<listitem><para>
|
||||
<computeroutput>caught WARNING: Result is a SYMBOL, not a NUMBER.</computeroutput>
|
||||
This is the <emphasis>explanation</emphasis> of the problem. In this
|
||||
example, the problem is that <varname>y</varname> evaluates to a symbol,
|
||||
but is in a context where a number is required (the argument
|
||||
to <function>+</function>).</para></listitem>
|
||||
</orderedlist>
|
||||
|
||||
Note that each part of the error message is distinctively marked:
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para> <computeroutput>file:</computeroutput> and <computeroutput>in:</computeroutput>
|
||||
mark the file and definition, respectively.</para></listitem>
|
||||
<listitem><para> The original source is an indented form with no
|
||||
prefix.</para></listitem>
|
||||
<listitem><para> Each line of the processing path is prefixed with
|
||||
<computeroutput>--></computeroutput></para></listitem>
|
||||
<listitem><para> The actual source form is indented like the original
|
||||
source, but is marked by a preceding <computeroutput>==></computeroutput> line.
|
||||
</para></listitem>
|
||||
<listitem><para> The explanation is prefixed with the error
|
||||
severity, which can be <computeroutput>caught ERROR:</computeroutput>,
|
||||
<computeroutput>caught WARNING:</computeroutput>,
|
||||
<computeroutput>caught STYLE-WARNING:</computeroutput>, or
|
||||
<computeroutput>note:</computeroutput>. </para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>Each part of the error message is more specific than the preceding
|
||||
one. If consecutive error messages are for nearby locations, then the
|
||||
front part of the error 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:
|
||||
<screen>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</screen>
|
||||
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:
|
||||
<computeroutput>[Last message occurs <replaceable>repeats</replaceable> times]</computeroutput>
|
||||
where <replaceable>repeats</replaceable> is the number of times the message
|
||||
was given.</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>The Original and Actual Source</title>
|
||||
|
||||
<para>The <emphasis>original source</emphasis> displayed will almost always be
|
||||
a list. If the actual source for an error 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.)</para>
|
||||
|
||||
<para>When the <emphasis>actual source</emphasis> 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.</para>
|
||||
|
||||
<para>Keep in mind that when the compiler displays a source form
|
||||
in an error message, it always displays the most specific (innermost)
|
||||
responsible form. For example, compiling this function
|
||||
<programlisting>(defun bar (x)
|
||||
(let (a)
|
||||
(declare (fixnum a))
|
||||
(setq a (foo x))
|
||||
a))</programlisting>
|
||||
gives this error message
|
||||
<screen>in: DEFUN BAR
|
||||
(LET (A) (DECLARE (FIXNUM A)) (SETQ A (FOO X)) A)
|
||||
caught WARNING: The binding of A is not a FIXNUM:
|
||||
NIL</screen>
|
||||
This error message is not saying <quote>there is a problem somewhere in
|
||||
this <function>let</function></quote> — it is saying that there is a
|
||||
problem with the <function>let</function> itself. In this example, the problem
|
||||
is that <varname>a</varname>'s <literal>nil</literal> initial value is not a
|
||||
<type>fixnum</type>.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>The Processing Path</title>
|
||||
<!--INDEX processing path-->
|
||||
<!--INDEX macroexpansion-->
|
||||
<!--INDEX source-to-source transformation-->
|
||||
|
||||
<para>The processing path is mainly useful for debugging macros, so if
|
||||
you don't write macros, you can probably ignore it. Consider this
|
||||
example:
|
||||
|
||||
<programlisting>(defun foo (n)
|
||||
(dotimes (i n *undefined*)))
|
||||
</programlisting>
|
||||
|
||||
Compiling results in this error message:
|
||||
|
||||
<screen>in: DEFUN FOO
|
||||
(DOTIMES (I N *UNDEFINED*))
|
||||
--> DO BLOCK LET TAGBODY RETURN-FROM
|
||||
==>
|
||||
(PROGN *UNDEFINED*)
|
||||
caught STYLE-WARNING:
|
||||
undefined variable: *UNDEFINED*</screen>
|
||||
|
||||
Note that <function>do</function> appears in the processing path. This is because
|
||||
<function>dotimes</function> expands into:
|
||||
|
||||
<programlisting>(do ((i 0 (1+ i)) (#:g1 n))
|
||||
((>= i #:g1) *undefined*)
|
||||
(declare (type unsigned-byte i)))</programlisting>
|
||||
|
||||
The rest of the processing path results from the expansion
|
||||
of <function>do</function>:
|
||||
|
||||
<programlisting>
|
||||
(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*)))))
|
||||
</programlisting>
|
||||
|
||||
In this example, the compiler descended into the <function>block</function>,
|
||||
<function>let</function>, <function>tagbody</function> and <function>return-from</function> to
|
||||
reach the <function>progn</function> printed as the actual source. This is a
|
||||
place where the <quote>actual source appears in explanation</quote> rule
|
||||
was applied. The innermost actual source form was the symbol
|
||||
<varname>*undefined*</varname> itself, but that also appeared in the
|
||||
explanation, so the compiler backed out one level.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Error Severity</title>
|
||||
<!--INDEX severity of compiler errors -->
|
||||
<!--INDEX compiler error severity -->
|
||||
|
||||
<para>There are four levels of compiler error severity:
|
||||
<wordasword>error</wordasword>, <wordasword>warning</wordasword>, <wordasword>style
|
||||
warning</wordasword>, and <wordasword>note</wordasword>. The first three levels correspond
|
||||
to condition classes which are defined in the &ANSI; standard for
|
||||
&CommonLisp; and which have special significance to the
|
||||
<function>compile</function> and <function>compile-file</function> functions. These
|
||||
levels of compiler error severity occur when the compiler handles
|
||||
conditions of these classes. The fourth level of compiler error
|
||||
severity, <wordasword>note</wordasword>, is used for problems which are too mild
|
||||
for the standard condition classes, typically hints about how
|
||||
efficiency might be improved.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Errors During Macroexpansion</title>
|
||||
<!--INDEX {macroexpansion}{errors during}-->
|
||||
|
||||
<para>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 <varname>*break-on-signals*</varname> to
|
||||
<literal>error</literal>. For example, this definition:
|
||||
|
||||
<programlisting>(defun foo (e l)
|
||||
(do ((current l (cdr current))
|
||||
((atom current) nil))
|
||||
(when (eq (car current) e) (return current))))</programlisting>
|
||||
|
||||
gives this error:
|
||||
|
||||
<screen>in: DEFUN FOO
|
||||
(DO ((CURRENT L #) (# NIL)) (WHEN (EQ # 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)</screen>
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Read Errors</title>
|
||||
<!--INDEX {read errors}{compiler}-->
|
||||
|
||||
<para>&SBCL;'s compiler (unlike &CMUCL;'s) 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.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<!-- 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{defvar}{}{error-print-length}
|
||||
_ \defvarx{error-print-level}
|
||||
_
|
||||
_ These variables are the print level and print length used in
|
||||
_ printing error messages. The default values are \code{5} and
|
||||
_ \code{3}. If null, the global values of \code{*print-level*} and
|
||||
_ \code{*print-length*} are used.
|
||||
_ \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}
|
||||
_
|
||||
_ -->
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="compiler-types"><title>The Compiler's Handling of Types</title>
|
||||
|
||||
<para>The most unusual features of the &SBCL; compiler (which is
|
||||
very similar to the original &CMUCL; compiler, also known as
|
||||
&Python;) is its unusually sophisticated understanding of the
|
||||
&CommonLisp; type system and its unusually 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 <link
|
||||
linkend="efficiency">in the chapter on performance</link>, the use of
|
||||
appropriate type declarations can be very important for performance as
|
||||
well.)</para>
|
||||
|
||||
<para>The &SBCL; compiler, like the related compiler in &CMUCL;,
|
||||
treats type declarations much differently than other Lisp compilers.
|
||||
By default (<emphasis>i.e.</emphasis>, at ordinary levels of the
|
||||
<parameter>safety</parameter> compiler optimization parameter), the compiler
|
||||
doesn't blindly believe most type declarations; it considers them
|
||||
assertions about the program that should be checked.</para>
|
||||
|
||||
<para>The &SBCL; compiler also has a greater knowledge of the
|
||||
&CommonLisp; type system than other compilers. Support is incomplete
|
||||
only for the <type>not</type>, <type>and</type> and <type>satisfies</type>
|
||||
types.
|
||||
<!-- FIXME: See also sections \ref{advanced-type-stuff}
|
||||
and \ref{type-inference}, once we snarf them from the
|
||||
CMU CL manual. -->
|
||||
</para>
|
||||
|
||||
<sect2 id="compiler-impl-limitations"><title>Implementation Limitations</title>
|
||||
|
||||
<para>
|
||||
Ideally, the compiler would consider <emphasis>all</emphasis> type declarations to
|
||||
be assertions, so that adding type declarations to a program, no
|
||||
matter how incorrect they might be, would <emphasis>never</emphasis> cause
|
||||
undefined behavior. As of &SBCL; version 0.8.1, the compiler is known to
|
||||
fall short of this goal in two areas:
|
||||
<itemizedlist>
|
||||
<listitem><para><function>Proclaim</function>ed constraints on argument and
|
||||
result types of a function are supposed to be checked by the
|
||||
function. If the function type is proclaimed before function
|
||||
definition, type checks are inserted by the compiler, but the
|
||||
standard allows the reversed order, in which case the compiler
|
||||
will trust the declaration.</para></listitem>
|
||||
<listitem><para>The compiler cannot check types of an unknown number
|
||||
of values; if the number of generated values is unknown, but the
|
||||
number of consumed is known, only consumed values are
|
||||
checked.</para></listitem>
|
||||
<listitem><para>There are a few poorly characterized but apparently
|
||||
very uncommon situations where a type declaration in an unexpected
|
||||
location will be trusted and never checked by the
|
||||
compiler.</para></listitem>
|
||||
</itemizedlist></para>
|
||||
|
||||
<para>These are important bugs, but are not necessarily easy to fix,
|
||||
so they may, alas, remain in the system for a while.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Type Errors at Compile Time</title>
|
||||
<!--INDEX compile time type errors-->
|
||||
<!--INDEX type checking}{at compile time}-->
|
||||
|
||||
<para>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:
|
||||
|
||||
<programlisting>(defun raz (foo)
|
||||
(let ((x (case foo
|
||||
(:this 13)
|
||||
(:that 9)
|
||||
(:the-other 42))))
|
||||
(declare (fixnum x))
|
||||
(foo x)))
|
||||
</programlisting>
|
||||
|
||||
Compilation produces this warning:
|
||||
|
||||
<screen>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</screen>
|
||||
|
||||
In this case, the warning means that if <varname>foo</varname> isn't any of
|
||||
<literal>:this</literal>, <literal>:that</literal> or <literal>:the-other</literal>, then
|
||||
<varname>x</varname> will be initialized to <literal>nil</literal>, which the
|
||||
<type>fixnum</type> declaration makes illegal. The warning will go away if
|
||||
<function>ecase</function> is used instead of <function>case</function>, or if
|
||||
<literal>:the-other</literal> is changed to <literal>t</literal>.</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>
|
||||
Type warnings are inhibited when the
|
||||
<parameter>sb-ext:inhibit-warnings</parameter> optimization quality is
|
||||
<literal>3</literal>. (See <link linkend="compiler-policy">the section
|
||||
on compiler policy</link>.) This can be used in a local declaration
|
||||
to inhibit type warnings in a code fragment that has spurious
|
||||
warnings.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="precisetypechecking"><title>Precise Type Checking</title>
|
||||
<!--INDEX precise type checking-->
|
||||
<!--INDEX {type checking}{precise}-->
|
||||
|
||||
<para>With the default compilation policy, all type declarations are
|
||||
precisely checked, except in a few situations where they are simply
|
||||
ignored instead. Precise checking means that the check is done as
|
||||
though <function>typep</function> had been called with the exact type
|
||||
specifier that appeared in the declaration. In &SBCL;, adding type
|
||||
declarations makes code safer. (Except that as noted <link
|
||||
linkend="compiler-impl-limitations">elsewhere</link>, remaining bugs
|
||||
in the compiler's handling of types unfortunately provide some
|
||||
exceptions to this rule.)</para>
|
||||
|
||||
<para>If a variable is declared to be
|
||||
<type>(integer 3 17)</type> then its value must always be an integer
|
||||
between <literal>3</literal> and <literal>17</literal>. 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 <type>and</type> type specifier.</para>
|
||||
|
||||
<para>Argument and result type declarations are automatically
|
||||
enforced. If you declare the type of a function argument, a type check
|
||||
will be done when that function is called. In a function call, the
|
||||
called function does the argument type checking.</para>
|
||||
|
||||
<para>The types of structure slots are also checked. The value of a
|
||||
structure slot must always be of the type indicated in any
|
||||
<literal>:type</literal> slot option. </para>
|
||||
|
||||
<para>In traditional &CommonLisp; compilers, not all type assertions
|
||||
are checked, and type checks are not precise. Traditional compilers
|
||||
blindly trust explicit type declarations, but may check the argument
|
||||
type assertions for built-in functions. Type checking is not precise,
|
||||
since the argument type checks will be for the most general type legal
|
||||
for that argument. In many systems, type declarations suppress what
|
||||
little type checking is being done, so adding type declarations makes
|
||||
code unsafe. This is a problem since it discourages writing type
|
||||
declarations during initial coding. In addition to being more error
|
||||
prone, adding type declarations during tuning also loses all the
|
||||
benefits of debugging with checked type assertions.</para>
|
||||
|
||||
<para>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
|
||||
<type>or</type>, <type>member</type>, and other list-style type specifiers.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="weakened-type-checking"><title>Weakened Type Checking</title>
|
||||
<!--INDEX weakened type checking-->
|
||||
<!--INDEX {type checking}{weakened}-->
|
||||
|
||||
<para>At one time, &CMUCL; supported another level of type checking,
|
||||
<quote>weakened type checking</quote>, when the value for the
|
||||
<parameter>speed</parameter> optimization quality is greater than
|
||||
<parameter>safety</parameter>, and <parameter>safety</parameter> is not <literal>0</literal>.
|
||||
The &CMUCL; manual still has a description of it, but even the CMU CL
|
||||
code no longer corresponds to the manual. Some of this partial safety
|
||||
checking lingers on in SBCL, but it's not a supported feature, and
|
||||
should not be relied on. If you ask the compiler to optimize
|
||||
<parameter>speed</parameter> to a higher level than <parameter>safety</parameter>,
|
||||
your program is performing without a safety net, because &SBCL; may
|
||||
at its option believe any or all type declarations with either partial
|
||||
or nonexistent runtime checking.</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Getting Existing Programs to Run</title>
|
||||
<!--INDEX {existing programs}{to run}-->
|
||||
<!--INDEX {types}{portability}-->
|
||||
<!--INDEX {compatibility with other Lisps}
|
||||
(should also have an entry in the non-&ANSI;-isms section)-->
|
||||
|
||||
<para>Since &SBCL;'s compiler, like &CMUCL;'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.</para>
|
||||
|
||||
<para>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 <parameter>safety</parameter> optimization) and
|
||||
then test this safe version. After the checking version has been
|
||||
tested, then you can consider weakening or eliminating type checks.
|
||||
<emphasis>This applies even to previously debugged
|
||||
programs,</emphasis> because the &SBCL; compiler does much more type
|
||||
inference than other &CommonLisp; compilers, so an incorrect
|
||||
declaration can do more damage.</para>
|
||||
|
||||
<para>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:
|
||||
|
||||
<programlisting>(prog (foo)
|
||||
(declare (fixnum foo))
|
||||
(setq foo ...)
|
||||
...)</programlisting>
|
||||
|
||||
Here <varname>foo</varname> is given an initial value of <literal>nil</literal>, but
|
||||
is declared to be a <type>fixnum</type>. 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
|
||||
|
||||
<programlisting>(prog (foo)
|
||||
(declare (type (or fixnum null) foo))
|
||||
(setq foo ...)
|
||||
...)</programlisting>
|
||||
|
||||
or change the initial value
|
||||
|
||||
<programlisting>(prog ((foo 0))
|
||||
(declare (fixnum foo))
|
||||
(setq foo ...)
|
||||
...)</programlisting>
|
||||
|
||||
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.</para>
|
||||
|
||||
<para>Another declaration problem occasionally encountered is
|
||||
incorrect declarations on <function>defmacro</function> arguments. This can happen
|
||||
when a function is converted into a macro. Consider this macro:
|
||||
|
||||
<programlisting>(defmacro my-1+ (x)
|
||||
(declare (fixnum x))
|
||||
`(the fixnum (1+ ,x)))</programlisting>
|
||||
|
||||
Although legal and well-defined &CommonLisp; code, this meaning of
|
||||
this definition is almost certainly not what the writer intended. For
|
||||
example, this call is illegal:
|
||||
|
||||
<programlisting>(my-1+ (+ 4 5))</programlisting>
|
||||
|
||||
This call is illegal because the argument to the macro is
|
||||
<literal>(+ 4 5)</literal>, which is a <type>list</type>, not a
|
||||
<type>fixnum</type>. 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
|
||||
<function>the</function> in the expansion:
|
||||
|
||||
<programlisting>(defmacro my-1+ (x)
|
||||
`(the fixnum (1+ (the fixnum ,x))))</programlisting>
|
||||
|
||||
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.-->
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Some more subtle problems are caused by incorrect declarations that
|
||||
can't be detected at compile time. Consider this code:
|
||||
|
||||
<programlisting>(do ((pos 0 (position #\a string :start (1+ pos))))
|
||||
((null pos))
|
||||
(declare (fixnum pos))
|
||||
...)</programlisting>
|
||||
|
||||
Although <varname>pos</varname> is almost always a <varname>fixnum</varname>, it is
|
||||
<literal>nil</literal> 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
|
||||
<function>position</function> will complain because <literal>(1+ nil)</literal> 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 <varname>pos</varname> is always a <type>fixnum</type>, it
|
||||
believes that <varname>pos</varname> is never <literal>nil</literal>, so
|
||||
<literal>(null pos)</literal> 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.</para>
|
||||
|
||||
<para>In this case, the fix is to weaken the type declaration to
|
||||
<type>(or fixnum null)</type>.
|
||||
<footnote><para>Actually, this declaration is
|
||||
unnecessary in &SBCL;, since it already knows that <function>position</function>
|
||||
returns a non-negative <type>fixnum</type> or <literal>nil</literal>.
|
||||
</para></footnote>
|
||||
|
||||
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 <type>fixnum</type>, since <literal>nil</literal>
|
||||
is not a legal numeric argument. Another possible fix would be to say:
|
||||
|
||||
<programlisting>(do ((pos 0 (position #\a string :start (1+ pos))))
|
||||
((null pos))
|
||||
(let ((pos pos))
|
||||
(declare (fixnum pos))
|
||||
...))</programlisting>
|
||||
|
||||
This would be preferable in some circumstances, since it would allow a
|
||||
non-standard representation to be used for the local <varname>pos</varname>
|
||||
variable in the loop body.
|
||||
<!-- FIXME: <xref>ND-variables, once we crib the text from the
|
||||
CMU CL manual. -->
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="compiler-policy"><title>Compiler Policy</title>
|
||||
|
||||
<para>As of version 0.6.4, &SBCL; still uses most of the &CMUCL; code
|
||||
for compiler policy. The &CMUCL; code has many features and high-quality
|
||||
documentation, but the two unfortunately do not match. So this area of
|
||||
the compiler and its interface needs to be cleaned up. Meanwhile, here
|
||||
is some rudimentary documentation on the current behavior of the
|
||||
system.</para>
|
||||
|
||||
<para>Compiler policy is controlled by the <parameter>optimize</parameter>
|
||||
declaration. The compiler supports the &ANSI; optimization qualities,
|
||||
and also an extension <parameter>sb-ext:inhibit-warnings</parameter>.</para>
|
||||
|
||||
<para>Ordinarily, when the <parameter>speed</parameter> quality is high, the
|
||||
compiler emits notes to notify the programmer about its inability to
|
||||
apply various optimizations. Setting
|
||||
<parameter>sb-ext:inhibit-warnings</parameter> to a value at least as large as
|
||||
the <parameter>speed</parameter> quality inhibits this notification. This can
|
||||
be useful to suppress notes about code which is known to be
|
||||
unavoidably inefficient. (For example, the compiler issues notes about
|
||||
having to use generic arithmetic instead of fixnum arithmetic, which
|
||||
is not helpful for code which by design supports arbitrary-sized
|
||||
integers instead of being limited to fixnums.)</para>
|
||||
|
||||
<note><para>The basic functionality of the <parameter>optimize
|
||||
inhibit-warnings</parameter> extension will probably be supported in all future
|
||||
versions of the system, but it will probably be renamed when the
|
||||
compiler and its interface are cleaned up. The current name is
|
||||
misleading, because it mostly inhibits optimization notes, not
|
||||
warnings. And making it an optimization quality is misleading, because
|
||||
it shouldn't affect the resulting code at all. It may become a
|
||||
declaration identifier with a name like
|
||||
<parameter>sb-ext:inhibit-notes</parameter>, so that what's currently written
|
||||
|
||||
<programlisting>(declaim (optimize (sb-ext:inhibit-warnings 2)))</programlisting>
|
||||
|
||||
would become something like
|
||||
|
||||
<programlisting>(declaim (sb-ext:inhibit-notes 2))</programlisting>
|
||||
|
||||
</para></note>
|
||||
|
||||
<para> (In early versions of SBCL, a <parameter>speed</parameter> value of zero
|
||||
was used to enable byte compilation, but since version 0.7.0, SBCL
|
||||
only supports native compilation.)</para>
|
||||
|
||||
<para>When <parameter>safety</parameter> is zero, almost all runtime checking
|
||||
of types, array bounds, and so forth is suppressed.</para>
|
||||
|
||||
<para>When <parameter>safety</parameter> is less than <parameter>speed</parameter>, any
|
||||
and all type checks may be suppressed. At some point in the past,
|
||||
&CMUCL; had <link linkend="weakened-type-checking">a more nuanced
|
||||
interpretation of this</link>. However, &SBCL; doesn't support that
|
||||
interpretation, and setting <parameter>safety</parameter> less than
|
||||
<parameter>speed</parameter> may have roughly the same effect as setting
|
||||
<parameter>safety</parameter> to zero.</para>
|
||||
|
||||
<para>The value of <parameter>space</parameter> mostly influences the
|
||||
compiler's decision whether to inline operations, which tend to
|
||||
increase the size of programs. Use the value <literal>0</literal> 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 swapping.</para>
|
||||
|
||||
<!-- 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.</para>
|
||||
_
|
||||
_\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.
|
||||
_
|
||||
_\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)
|
||||
_-->
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="open-coding"><title>Open Coding and Inline Expansion</title>
|
||||
<!--INDEX open-coding-->
|
||||
<!--INDEX inline expansion-->
|
||||
<!--INDEX static functions-->
|
||||
|
||||
<para>Since &CommonLisp; 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:
|
||||
<itemizedlist>
|
||||
<listitem><para> 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 <function>trace</function> macro. Special-casing
|
||||
of standard functions can be inhibited using the
|
||||
<parameter>notinline</parameter> declaration.</para></listitem>
|
||||
<listitem><para> 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 <link linkend="compiler-policy">compiler policy</link>.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>When a function call is <emphasis>open coded</emphasis>, inline code whose
|
||||
effect is equivalent to the function call is substituted for that
|
||||
function call. When a function call is <emphasis>closed coded</emphasis>, 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
|
||||
<function>nthcdr</function> were to be open coded, then
|
||||
|
||||
<programlisting>(nthcdr 4 foobar)</programlisting>
|
||||
|
||||
might turn into
|
||||
|
||||
<programlisting>(cdr (cdr (cdr (cdr foobar))))</programlisting>
|
||||
|
||||
or even
|
||||
|
||||
<programlisting>(do ((i 0 (1+ i))
|
||||
(list foobar (cdr foobar)))
|
||||
((= i 4) list))</programlisting>
|
||||
|
||||
If <function>nth</function> is closed coded, then
|
||||
|
||||
<programlisting>
|
||||
(nth x l)
|
||||
</programlisting>
|
||||
|
||||
might stay the same, or turn into something like
|
||||
|
||||
<programlisting>
|
||||
(car (nthcdr x l))
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>In general, open coding sacrifices space for speed, but some
|
||||
functions (such as <function>car</function>) 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 <emphasis>static call</emphasis>. Static function call
|
||||
uses a more efficient calling convention that forbids
|
||||
redefinition.</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -1,4 +1,11 @@
|
|||
<chapter id="efficiency"><title>Efficiency</>
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "entities.inc">
|
||||
%myents;
|
||||
]>
|
||||
|
||||
<chapter id="efficiency"><title>Efficiency</title>
|
||||
|
||||
<para>FIXME: The material in the &CMUCL; manual about getting good
|
||||
performance from the compiler should be reviewed, reformatted in
|
||||
|
|
@ -7,19 +14,19 @@ manual. In the meantime, the original &CMUCL; manual is still 95+%
|
|||
correct for the &SBCL; version of the &Python; compiler. See the
|
||||
sections
|
||||
<itemizedlist>
|
||||
<listitem><para>Advanced Compiler Use and Efficiency Hints</></>
|
||||
<listitem><para>Advanced Compiler Introduction</></>
|
||||
<listitem><para>More About Types in Python</></>
|
||||
<listitem><para>Type Inference</></>
|
||||
<listitem><para>Source Optimization</></>
|
||||
<listitem><para>Tail Recursion</></>
|
||||
<listitem><para>Local Call</></>
|
||||
<listitem><para>Block Compilation</></>
|
||||
<listitem><para>Inline Expansion</></>
|
||||
<listitem><para>Object Representation</></>
|
||||
<listitem><para>Numbers</></>
|
||||
<listitem><para>General Efficiency Hints</></>
|
||||
<listitem><para>Efficiency Notes</></>
|
||||
<listitem><para>Advanced Compiler Use and Efficiency Hints</para></listitem>
|
||||
<listitem><para>Advanced Compiler Introduction</para></listitem>
|
||||
<listitem><para>More About Types in Python</para></listitem>
|
||||
<listitem><para>Type Inference</para></listitem>
|
||||
<listitem><para>Source Optimization</para></listitem>
|
||||
<listitem><para>Tail Recursion</para></listitem>
|
||||
<listitem><para>Local Call</para></listitem>
|
||||
<listitem><para>Block Compilation</para></listitem>
|
||||
<listitem><para>Inline Expansion</para></listitem>
|
||||
<listitem><para>Object Representation</para></listitem>
|
||||
<listitem><para>Numbers</para></listitem>
|
||||
<listitem><para>General Efficiency Hints</para></listitem>
|
||||
<listitem><para>Efficiency Notes</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
|
|
@ -29,10 +36,10 @@ few other points to keep in mind.
|
|||
<listitem><para>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 <function>let</>,
|
||||
<function>let*</>, inline function call, and so forth. However,
|
||||
about inferring the types of values bound with <function>let</function>,
|
||||
<function>let*</function>, inline function call, and so forth. However,
|
||||
it's much more passive and dumb about inferring the types of
|
||||
values assigned with <function>setq</>, <function>setf</>, and
|
||||
values assigned with <function>setq</function>, <function>setf</function>, 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.
|
||||
|
|
@ -52,8 +59,8 @@ few other points to keep in mind.
|
|||
Perhaps the most important are
|
||||
<itemizedlist>
|
||||
<listitem><para>There is no support for the &ANSI;
|
||||
<parameter>dynamic-extent</> declaration, not even for
|
||||
closures or <parameter>&rest</> lists.</para></listitem>
|
||||
<parameter>dynamic-extent</parameter> declaration, not even for
|
||||
closures or <parameter>&rest</parameter> lists.</para></listitem>
|
||||
<listitem><para>The garbage collector is not particularly
|
||||
efficient.</para></listitem>
|
||||
<listitem><para>Various aspects of the PCL implementation
|
||||
|
|
@ -73,29 +80,29 @@ 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
|
||||
<itemizedlist>
|
||||
<listitem><para><literal>(reduce #'f x)</>
|
||||
where the type of <varname>x</> is known at compile
|
||||
<listitem><para><literal>(reduce #'f x)</literal>
|
||||
where the type of <varname>x</varname> is known at compile
|
||||
time</para></listitem>
|
||||
<listitem><para>various bit vector operations, e.g.
|
||||
<literal>(position 0 some-bit-vector)</></para></listitem>
|
||||
<literal>(position 0 some-bit-vector)</literal></para></listitem>
|
||||
</itemizedlist>
|
||||
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 <quote><function>deftransform</></>
|
||||
search the sources for the string <quote><function>deftransform</function></quote>
|
||||
to find many examples (some straightforward, some less so).</para>
|
||||
|
||||
<sect1 id="modular-arithmetic"><title>Modular arithmetic</>
|
||||
<sect1 id="modular-arithmetic"><title>Modular arithmetic</title>
|
||||
<para>
|
||||
Some numeric functions have a property: <varname>N</> lower bits of
|
||||
the result depend only on <varname>N</> lower bits of (all or some)
|
||||
Some numeric functions have a property: <varname>N</varname> lower bits of
|
||||
the result depend only on <varname>N</varname> lower bits of (all or some)
|
||||
arguments. If the compiler sees an expression of form <literal>(logand
|
||||
exp mask)</>, where <varname>exp</> is a tree of such "good" functions
|
||||
and <varname>mask</> is known to be of type <type>(unsigned-byte
|
||||
w)</>, where <varname>w</> is a "good" width, all intermediate results
|
||||
will be cut to <varname>w</> bits (but it is not done for variables
|
||||
exp mask)</literal>, where <varname>exp</varname> is a tree of such "good" functions
|
||||
and <varname>mask</varname> is known to be of type <type>(unsigned-byte
|
||||
w)</type>, where <varname>w</varname> is a "good" width, all intermediate results
|
||||
will be cut to <varname>w</varname> bits (but it is not done for variables
|
||||
and constants!). This often results in an ability to use simple
|
||||
machine instructions for the functions.
|
||||
</para>
|
||||
|
|
@ -107,21 +114,21 @@ Consider an example.
|
|||
(declare (type (unsigned-byte 32) x y))
|
||||
(ldb (byte 32 0) (logxor x (lognot y))))
|
||||
</programlisting>
|
||||
The result of <literal>(lognot y)</> will be negative and of
|
||||
type <type>(signed-byte 33)</>, so a naive implementation on a 32-bit
|
||||
The result of <literal>(lognot y)</literal> will be negative and of
|
||||
type <type>(signed-byte 33)</type>, 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 <function>logxor</>
|
||||
and <function>lognot</> with versions cutting results to 32 bits, and
|
||||
because terminals (here---expressions <literal>x</> and <literal>y</>)
|
||||
are also of type <type>(unsigned-byte 32)</>, 32-bit machine
|
||||
to 32 bits, the compiler will replace <function>logxor</function>
|
||||
and <function>lognot</function> with versions cutting results to 32 bits, and
|
||||
because terminals (here---expressions <literal>x</literal> and <literal>y</literal>)
|
||||
are also of type <type>(unsigned-byte 32)</type>, 32-bit machine
|
||||
arithmetic can be used.
|
||||
</para>
|
||||
|
||||
<note><para> As of &SBCL; 0.8.5 "good" functions
|
||||
are <function>+</>, <function>-</>; <function>logand</>, <function>logior</>,
|
||||
<function>logxor</>, <function>lognot</> and their combinations;
|
||||
and <function>ash</> with the positive second argument. "Good" widths
|
||||
are <function>+</function>, <function>-</function>; <function>logand</function>, <function>logior</function>,
|
||||
<function>logxor</function>, <function>lognot</function> and their combinations;
|
||||
and <function>ash</function> with the positive second argument. "Good" widths
|
||||
are 32 on HPPA, MIPS, PPC, Sparc and X86 and 64 on Alpha. While it is
|
||||
possible to support smaller widths as well, currently it is not
|
||||
implemented.
|
||||
16
doc/entities.inc
Normal file
16
doc/entities.inc
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<!-- markup for common expressions -->
|
||||
<!ENTITY AMOP "<acronym>AMOP</acronym>">
|
||||
<!ENTITY ANSI "<acronym>ANSI</acronym>">
|
||||
<!ENTITY CMUCL "<application>CMU CL</application>">
|
||||
<!ENTITY IEEE "<acronym>IEEE</acronym>">
|
||||
<!ENTITY Python "<application>Python</application>">
|
||||
<!ENTITY SBCL "<application>SBCL</application>">
|
||||
|
||||
<!-- common expressions I haven't figured out how to mark up -->
|
||||
<!-- KLUDGE: There doesn't seem to be any DocBook tag for names of
|
||||
programming languages. Typesetting Common Lisp as an
|
||||
<application> looks funny. Is there a better way?
|
||||
WHN 20000505 -->
|
||||
<!ENTITY CommonLisp "Common Lisp">
|
||||
<!ENTITY Lisp "Lisp">
|
||||
|
||||
File diff suppressed because it is too large
Load diff
8
doc/fo.xsl
Normal file
8
doc/fo.xsl
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version='1.0'?>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0">
|
||||
|
||||
<xsl:import href="docbook_fo.xsl"/>
|
||||
<xsl:param name="fop.extensions" select="1"/>
|
||||
</xsl:stylesheet>
|
||||
|
||||
10
doc/html.xsl
Normal file
10
doc/html.xsl
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version='1.0'?>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0">
|
||||
|
||||
<xsl:import href="docbook_html.xsl"/>
|
||||
<xsl:param name="use.id.as.filename" select="1"/>
|
||||
<xsl:output encoding="ISO-8859-1" method="html" />
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
||||
9
doc/html_chunk.xsl
Normal file
9
doc/html_chunk.xsl
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version='1.0'?>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0">
|
||||
|
||||
<xsl:import href="docbook_chunk.xsl"/>
|
||||
<xsl:param name="use.id.as.filename" select="1"/>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
||||
209
doc/intro.sgml
209
doc/intro.sgml
|
|
@ -1,209 +0,0 @@
|
|||
<chapter id="intro"><title>Introduction</>
|
||||
|
||||
<para>&SBCL; is a mostly-conforming implementation of the &ANSI;
|
||||
&CommonLisp; standard. This manual focuses on behavior which is
|
||||
specific to &SBCL;, not on behavior which is common to all
|
||||
implementations of &ANSI; &CommonLisp;.</para>
|
||||
|
||||
<sect1 id="more-cl-info">
|
||||
<title>Where To Go For More Information about &CommonLisp; in General</title>
|
||||
|
||||
<para>Regardless of your ability level, two very useful resources
|
||||
for working with any implementation of
|
||||
&CommonLisp; are the
|
||||
<ulink url="http://ilisp.cons.org"><application>ILISP</></ulink>
|
||||
package for <application>Emacs</> and
|
||||
<ulink url="http://www.harlequin.com/books/HyperSpec">the &CommonLisp;
|
||||
HyperSpec</>.</para>
|
||||
|
||||
<para>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 can't decide, try checking the Usenet
|
||||
comp.lang.lisp FAQ for recent recommendations.</para>
|
||||
|
||||
<para>If you are an experienced programmer in other languages
|
||||
but need to learn about Lisp, three books stand out.
|
||||
<itemizedlist>
|
||||
<listitem><para><emphasis>ANSI Common Lisp</>, by Paul Graham,
|
||||
will teach you about most of the language. (And later it might
|
||||
also be worth checking out <emphasis>On Lisp</>, by the same
|
||||
author.)</para></listitem>
|
||||
<listitem><para><emphasis>Paradigms Of Artificial Intelligence
|
||||
Programming</>, by Peter Norvig, also has some good information
|
||||
on general &CommonLisp; programming, and many nontrivial examples.
|
||||
Whether or not your work is AI, it's a very good book to look
|
||||
at.</para></listitem>
|
||||
<listitem><para>
|
||||
Neither of the books above emphasizes CLOS, but
|
||||
<emphasis>Object-Oriented Programming In Common Lisp</> by Sonya Keene
|
||||
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 &CommonLisp;. 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.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Where To Go For More Information About &SBCL;</title>
|
||||
|
||||
<para>Before you read this user manual, you should probably read
|
||||
two other things.
|
||||
<itemizedlist>
|
||||
<listitem><para>You should know how to program in &CommonLisp;.
|
||||
If you don't already know how, you should probably read a
|
||||
<link linkend="more-cl-info">book on it</>.</para></listitem>
|
||||
<listitem><para>The Unix <quote>man page</> for &SBCL; will tell you
|
||||
how to start the &SBCL; environment, so you can get to the
|
||||
classic <quote>hello, world</quote> level of knowledge. It's the file
|
||||
called <filename>sbcl.1</> in the &SBCL; distribution. If &SBCL; is
|
||||
installed on your system, you can read a formatted copy by
|
||||
executing the command <command>man sbcl</>.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>Besides this user manual and the Unix man page, some
|
||||
other &SBCL;-specific information is available:
|
||||
<itemizedlist>
|
||||
<listitem><para>The <ulink url="http://sbcl.sourceforge.net/">
|
||||
&SBCL; home page</ulink> has some general
|
||||
information, plus links to mailing lists devoted to &SBCL;,
|
||||
and to archives of these mailing lists.</para></listitem>
|
||||
<listitem><para>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 <function>inspect</>)
|
||||
are documented in text available by typing <userinput>help</>
|
||||
at their command prompts. The extensions for functions which
|
||||
don't have their own command prompt (like <function>trace</>
|
||||
does) are described in their documentation strings,
|
||||
unless your &SBCL; was compiled with an option not
|
||||
to include documentation strings, in which case the doc strings
|
||||
are only readable in the source code.</para></listitem>
|
||||
<listitem><para>Some low-level information describing the
|
||||
programming details of the conversion from &CMUCL; to &SBCL;
|
||||
is available in the <filename>doc/FOR-CMUCL-DEVELOPERS</>
|
||||
file in the &SBCL; distribution.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="implementation">
|
||||
<title>Overview Of SBCL, How It Works And Where It Came From</>
|
||||
|
||||
<para>You can work productively with SBCL without knowing anything
|
||||
understanding anything about where it came from, how it is implemented,
|
||||
or how it extends the &ANSI; &CommonLisp; 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. </para>
|
||||
|
||||
<para>&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. Design decisions from that
|
||||
time are still reflected in the current implementation:
|
||||
<itemizedlist>
|
||||
<listitem><para>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.</para></listitem>
|
||||
<listitem><para>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 ends up using too much of the allocated storage.</para></listitem>
|
||||
<listitem><para>A word is a 32-bit quantity. The system has been
|
||||
ported to many processor architectures without altering this
|
||||
basic principle. Some hacks allow the system to run on the Alpha
|
||||
chip (a 64-bit architecture) but even there 32-bit words are
|
||||
used. The assumption that a word is
|
||||
32 bits wide is implicit in hundreds of places in the
|
||||
system.</para></listitem>
|
||||
<listitem><para>The system is implemented as a C program which is
|
||||
responsible for supplying low-level services and loading a
|
||||
Lisp <quote>.core</quote> file.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>&SBCL; also inherited some newer architectural features from
|
||||
&CMUCL;. The most important is that it has a generational garbage
|
||||
collector (<quote>GC</>), which has various implications (mostly good)
|
||||
for performance. These are discussed in <link linkend="efficiency">
|
||||
another chapter</link>.</para>
|
||||
|
||||
<para>&SBCL; has diverged from &CMUCL; in that &SBCL; is now
|
||||
essentially a <quote>compiler-only implementation</quote> of
|
||||
&CommonLisp;. A &CommonLisp; implementation is permitted to implement
|
||||
both a compiler and an interpreter, and there's some special support
|
||||
in the standard (e.g. the distinction between <function>functionp</>
|
||||
and <function>compiled-function-p</>) to help support that. But &SBCL;
|
||||
has only a vestigial, rudimentary true interpreter. In &SBCL;, the
|
||||
<function>eval</> function only truly <quote>interprets</quote> a few
|
||||
special classes of forms, such as symbols which are
|
||||
<function>boundp</>. More complicated forms are evaluated by calling
|
||||
<function>compile</> and then calling <function>funcall</> on the
|
||||
returned result.
|
||||
</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>On the x86, &SBCL; like the X86 port of &CMUCL;, uses a
|
||||
<emphasis>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 garbage collectors work reasonably well, not getting
|
||||
anywhere near the worst case. But they can occasionally cause
|
||||
odd patterns of memory usage.</para>
|
||||
|
||||
<para>The fork from &CMUCL; was based on a major rewrite of the system
|
||||
bootstrap process. &CMUCL; has for many years tolerated a very unusual
|
||||
<quote>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
|
||||
<quote>build</> a &CMUCL; system containing characteristics not
|
||||
reflected in the current version of the source code.</para>
|
||||
|
||||
<para>Other major changes since the fork from &CMUCL; include
|
||||
<itemizedlist>
|
||||
<listitem><para>&SBCL; has dropped support for many &CMUCL; extensions,
|
||||
(e.g. IP networking, remote procedure call, Unix system interface, and X11
|
||||
interface). Some of these are now available as contributed or
|
||||
third-party modules.</para></listitem>
|
||||
<listitem><para>&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), and various block-compilation
|
||||
efficiency-increasing extensions to the language have been
|
||||
deleted or are no longer used in the implementation of &SBCL;
|
||||
itself.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
216
doc/intro.xml
Normal file
216
doc/intro.xml
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "entities.inc">
|
||||
%myents;
|
||||
]>
|
||||
|
||||
<chapter id="intro"><title>Introduction</title>
|
||||
|
||||
<para>&SBCL; is a mostly-conforming implementation of the &ANSI;
|
||||
&CommonLisp; standard. This manual focuses on behavior which is
|
||||
specific to &SBCL;, not on behavior which is common to all
|
||||
implementations of &ANSI; &CommonLisp;.</para>
|
||||
|
||||
<sect1 id="more-cl-info">
|
||||
<title>Where To Go For More Information about &CommonLisp; in General</title>
|
||||
|
||||
<para>Regardless of your ability level, two very useful resources
|
||||
for working with any implementation of
|
||||
&CommonLisp; are the
|
||||
<ulink url="http://ilisp.cons.org"><application>ILISP</application></ulink>
|
||||
package for <application>Emacs</application> and
|
||||
<ulink url="http://www.harlequin.com/books/HyperSpec">the &CommonLisp;
|
||||
HyperSpec</ulink>.</para>
|
||||
|
||||
<para>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 can't decide, try checking the Usenet
|
||||
comp.lang.lisp FAQ for recent recommendations.</para>
|
||||
|
||||
<para>If you are an experienced programmer in other languages
|
||||
but need to learn about Lisp, three books stand out.
|
||||
<itemizedlist>
|
||||
<listitem><para><emphasis>ANSI Common Lisp</emphasis>, by Paul Graham,
|
||||
will teach you about most of the language. (And later it might
|
||||
also be worth checking out <emphasis>On Lisp</emphasis>, by the same
|
||||
author.)</para></listitem>
|
||||
<listitem><para><emphasis>Paradigms Of Artificial Intelligence
|
||||
Programming</emphasis>, by Peter Norvig, also has some good information
|
||||
on general &CommonLisp; programming, and many nontrivial examples.
|
||||
Whether or not your work is AI, it's a very good book to look
|
||||
at.</para></listitem>
|
||||
<listitem><para>
|
||||
Neither of the books above emphasizes CLOS, but
|
||||
<emphasis>Object-Oriented Programming In Common Lisp</emphasis> by Sonya Keene
|
||||
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 &CommonLisp;. 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.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="where-more">
|
||||
<title>Where To Go For More Information About &SBCL;</title>
|
||||
|
||||
<para>Before you read this user manual, you should probably read
|
||||
two other things.
|
||||
<itemizedlist>
|
||||
<listitem><para>You should know how to program in &CommonLisp;.
|
||||
If you don't already know how, you should probably read a
|
||||
<link linkend="more-cl-info">book on it</link>.</para></listitem>
|
||||
<listitem><para>The Unix <quote>man page</quote> for &SBCL; will tell you
|
||||
how to start the &SBCL; environment, so you can get to the
|
||||
classic <quote>hello, world</quote> level of knowledge. It's the file
|
||||
called <filename>sbcl.1</filename> in the &SBCL; distribution. If &SBCL; is
|
||||
installed on your system, you can read a formatted copy by
|
||||
executing the command <command>man sbcl</command>.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>Besides this user manual and the Unix man page, some
|
||||
other &SBCL;-specific information is available:
|
||||
<itemizedlist>
|
||||
<listitem><para>The <ulink url="http://sbcl.sourceforge.net/">
|
||||
&SBCL; home page</ulink> has some general
|
||||
information, plus links to mailing lists devoted to &SBCL;,
|
||||
and to archives of these mailing lists.</para></listitem>
|
||||
<listitem><para>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 <function>inspect</function>)
|
||||
are documented in text available by typing <userinput>help</userinput>
|
||||
at their command prompts. The extensions for functions which
|
||||
don't have their own command prompt (like <function>trace</function>
|
||||
does) are described in their documentation strings,
|
||||
unless your &SBCL; was compiled with an option not
|
||||
to include documentation strings, in which case the doc strings
|
||||
are only readable in the source code.</para></listitem>
|
||||
<listitem><para>Some low-level information describing the
|
||||
programming details of the conversion from &CMUCL; to &SBCL;
|
||||
is available in the <filename>doc/FOR-CMUCL-DEVELOPERS</filename>
|
||||
file in the &SBCL; distribution.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="implementation">
|
||||
<title>Overview Of SBCL, How It Works And Where It Came From</title>
|
||||
|
||||
<para>You can work productively with SBCL without knowing anything
|
||||
understanding anything about where it came from, how it is implemented,
|
||||
or how it extends the &ANSI; &CommonLisp; 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. </para>
|
||||
|
||||
<para>&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. Design decisions from that
|
||||
time are still reflected in the current implementation:
|
||||
<itemizedlist>
|
||||
<listitem><para>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.</para></listitem>
|
||||
<listitem><para>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 ends up using too much of the allocated storage.</para></listitem>
|
||||
<listitem><para>A word is a 32-bit quantity. The system has been
|
||||
ported to many processor architectures without altering this
|
||||
basic principle. Some hacks allow the system to run on the Alpha
|
||||
chip (a 64-bit architecture) but even there 32-bit words are
|
||||
used. The assumption that a word is
|
||||
32 bits wide is implicit in hundreds of places in the
|
||||
system.</para></listitem>
|
||||
<listitem><para>The system is implemented as a C program which is
|
||||
responsible for supplying low-level services and loading a
|
||||
Lisp <quote>.core</quote> file.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>&SBCL; also inherited some newer architectural features from
|
||||
&CMUCL;. The most important is that it has a generational garbage
|
||||
collector (<quote>GC</quote>), which has various implications (mostly good)
|
||||
for performance. These are discussed in <link linkend="efficiency">
|
||||
another chapter</link>.</para>
|
||||
|
||||
<para>&SBCL; has diverged from &CMUCL; in that &SBCL; is now
|
||||
essentially a <quote>compiler-only implementation</quote> of
|
||||
&CommonLisp;. A &CommonLisp; implementation is permitted to implement
|
||||
both a compiler and an interpreter, and there's some special support
|
||||
in the standard (e.g. the distinction between <function>functionp</function>
|
||||
and <function>compiled-function-p</function>) to help support that. But &SBCL;
|
||||
has only a vestigial, rudimentary true interpreter. In &SBCL;, the
|
||||
<function>eval</function> function only truly <quote>interprets</quote> a few
|
||||
special classes of forms, such as symbols which are
|
||||
<function>boundp</function>. More complicated forms are evaluated by calling
|
||||
<function>compile</function> and then calling <function>funcall</function> on the
|
||||
returned result.
|
||||
</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>On the x86, &SBCL; like the X86 port of &CMUCL;, uses a
|
||||
<emphasis>conservative</emphasis> 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 garbage collectors work reasonably well, not getting
|
||||
anywhere near the worst case. But they can occasionally cause
|
||||
odd patterns of memory usage.</para>
|
||||
|
||||
<para>The fork from &CMUCL; was based on a major rewrite of the system
|
||||
bootstrap process. &CMUCL; has for many years tolerated a very unusual
|
||||
<quote>build</quote> 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
|
||||
<quote>build</quote> a &CMUCL; system containing characteristics not
|
||||
reflected in the current version of the source code.</para>
|
||||
|
||||
<para>Other major changes since the fork from &CMUCL; include
|
||||
<itemizedlist>
|
||||
<listitem><para>&SBCL; has dropped support for many &CMUCL; extensions,
|
||||
(e.g. IP networking, remote procedure call, Unix system interface, and X11
|
||||
interface). Some of these are now available as contributed or
|
||||
third-party modules.</para></listitem>
|
||||
<listitem><para>&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), and various block-compilation
|
||||
efficiency-increasing extensions to the language have been
|
||||
deleted or are no longer used in the implementation of &SBCL;
|
||||
itself.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -1,25 +1,20 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Where is Jade? (i.e. James Clark's implementation of DSSSL, or
|
||||
# something offsprung)
|
||||
if [ "" != "$JADE" ]; then
|
||||
. ../find-gnumake.sh
|
||||
find_gnumake
|
||||
|
||||
# Where is xsltproc?
|
||||
if [ "" != "$XSLTPROC" ]; then
|
||||
# The user has told us where to find jade, good.
|
||||
echo using JADE=$JADE
|
||||
elif which openjade > /dev/null; then
|
||||
# OpenJade is the version of Jade which comes with OpenBSD 2.9,
|
||||
echo using XSLTPROC=$XSLTPROC
|
||||
elif which xsltproc > /dev/null; then
|
||||
# Openxsltproc is the version of xsltproc which comes with OpenBSD 2.9,
|
||||
# and I started using it in sbcl-0.pre7.x. -- WHN
|
||||
JADE=openjade
|
||||
elif which jade > /dev/null; then
|
||||
# I used the original Jade until sbcl-0.pre7.x. It might still
|
||||
# work. -- WHN
|
||||
JADE=jade
|
||||
XSLTPROC=xsltproc
|
||||
else
|
||||
echo "can't find Jade, sorry"
|
||||
echo "can't find xsltproc, sorry"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Our hacked sbcl-html.dsl directs HTML output to html/. Make a clean slate.
|
||||
rm -rf html
|
||||
mkdir html
|
||||
|
||||
$JADE -t sgml -ihtml -d sbcl-html.dsl\#html user-manual.sgml
|
||||
export XSLTPROC
|
||||
$GNUMAKE html
|
||||
|
|
|
|||
133
doc/sbcl-asdf-install.1
Normal file
133
doc/sbcl-asdf-install.1
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
.TH SBCL-ASDF-INSTALL 1 "$Date$"
|
||||
.AT 3
|
||||
.SH NAME
|
||||
.BI SBCL-ASDF-INSTALL
|
||||
-- Download and Install ASDF Systems
|
||||
|
||||
.SH SYNOPSIS
|
||||
.BI sbcl-asdf-install
|
||||
[packages ...]
|
||||
|
||||
Each argument may be
|
||||
.TP 3
|
||||
\--
|
||||
The name of a cliki page. asdf-install visits that page and finds
|
||||
the download location from the `:(package)' tag - usually rendered
|
||||
as "Download ASDF package from ..."
|
||||
.TP 3
|
||||
\--
|
||||
A URL, which is downloaded directly
|
||||
.TP 3
|
||||
\--
|
||||
A local tar.gz file, which is installed
|
||||
|
||||
|
||||
.SH DESCRIPTION
|
||||
Downloads and installs an ASDF system or anything else that looks
|
||||
convincingly like one, including updating the ASDF:*CENTRAL-REGISTRY*
|
||||
symlinks for all the toplevel .asd files it contains. Please read
|
||||
this file before use: in particular: this is an automatic tool that
|
||||
downloads and compiles stuff it finds on the 'net. Please look at the
|
||||
SECURITY section and be sure you understand the implications
|
||||
|
||||
|
||||
.SH SECURITY CONCERNS: READ THIS CAREFULLY
|
||||
When you invoke asdf-install, you are asking SBCL to download,
|
||||
compile, and install software from some random site on the web. Given
|
||||
that it's indirected through a page on CLiki, any malicious third party
|
||||
doesn't even need to hack the distribution server to replace the
|
||||
package with something else: he can just edit the link.
|
||||
|
||||
For this reason, we encourage package providers to crypto-sign their
|
||||
packages (see details at the URL in the PACKAGE CREATION section) and
|
||||
users to check the signatures. asdf-install has three levels of
|
||||
automatic signature checking: "on", "off" and "unknown sites", which
|
||||
can be set using the configuration variables described in
|
||||
CUSTOMIZATION below. The default is "unknown sites", which will
|
||||
expect a GPG signature on all downloads except those from
|
||||
presumed-good sites. The current default presumed-good sites are
|
||||
CCLAN nodes, and two web sites run by SBCL maintainers: again, see
|
||||
below for customization details
|
||||
|
||||
|
||||
.SH CUSTOMIZATION
|
||||
|
||||
If the file $HOME/.asdf-install exists, it is loaded. This can be
|
||||
used to override the default values of exported special variables.
|
||||
Presently these are
|
||||
.TP 3
|
||||
\--
|
||||
*PROXY*
|
||||
|
||||
defaults to $http_proxy environment variable
|
||||
.TP 3
|
||||
\--
|
||||
*CCLAN-MIRROR*
|
||||
|
||||
preferred/nearest CCLAN node. See the list at
|
||||
http://ww.telent.net/cclan-choose-mirror
|
||||
.TP 3
|
||||
\--
|
||||
*SBCL-HOME*
|
||||
|
||||
Set from $SBCL_HOME environment variable. This should already be
|
||||
correct for whatever SBCL is running, if it's been installed correctly
|
||||
.TP 3
|
||||
\--
|
||||
*VERIFY-GPG-SIGNATURES*
|
||||
|
||||
Verify GPG signatures for the downloaded packages?
|
||||
|
||||
NIL - no, T - yes, :UNKNOWN-LOCATIONS - only for URLs which aren't in CCLAN and don't begin with one of the prefixes in *SAFE-URL-PREFIXES*
|
||||
.TP 3
|
||||
\--
|
||||
*LOCATIONS*
|
||||
|
||||
Possible places in the filesystem to install packages into. See default
|
||||
value for format
|
||||
.TP 3
|
||||
\--
|
||||
*SAFE-URL-PREFIXES*
|
||||
|
||||
List of locations for which GPG signature checking won't be done when
|
||||
*verify-gpg-signatures* is :unknown-locations
|
||||
|
||||
|
||||
.SH PACKAGE CREATION
|
||||
|
||||
If you want to create your own packages that can be installed using this
|
||||
loader, see the "Making your package downloadable..." section at
|
||||
<http://www.cliki.net/asdf-install>
|
||||
|
||||
|
||||
.SH HACKERS NOTE
|
||||
|
||||
Listen very carefully: I will say this only as often as it appears to
|
||||
be necessary to say it. asdf-install is not a good example of how to
|
||||
write a URL parser, HTTP client, or anything else, really.
|
||||
Well-written extensible and robust URL parsers, HTTP clients, FTP
|
||||
clients, etc would definitely be nice things to have, but it would be
|
||||
nicer to have them in CCLAN where anyone can use them - after having
|
||||
downloaded them with asdf-install - than in SBCL contrib where they're
|
||||
restricted to SBCL users and can only be updated once a month via SBCL
|
||||
developers. This is a bootstrap tool, and as such, will tend to
|
||||
resist changes that make it longer or dependent on more other
|
||||
packages, unless they also add to its usefulness for bootstrapping.
|
||||
|
||||
|
||||
.SH TODO
|
||||
|
||||
.TP 3
|
||||
a)
|
||||
gpg signature checking would be better if it actually checked against
|
||||
a list of "trusted to write Lisp" keys, instead of just "trusted to be
|
||||
who they say they are"
|
||||
.TP 3
|
||||
b)
|
||||
nice to have: resume half-done downloads instead of starting from scratch
|
||||
every time. but right now we're dealing in fairly small packages, this is not
|
||||
an immediate concern
|
||||
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR sbcl (1)
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [
|
||||
|
||||
<!-- markup for common expressions -->
|
||||
<!ENTITY AMOP "<acronym>AMOP</>">
|
||||
<!ENTITY ANSI "<acronym>ANSI</>">
|
||||
<!ENTITY CMUCL "<application>CMU CL</>">
|
||||
<!ENTITY IEEE "<acronym>IEEE</>">
|
||||
<!ENTITY Python "<application>Python</>">
|
||||
<!ENTITY SBCL "<application>SBCL</>">
|
||||
|
||||
<!-- common expressions I haven't figured out how to mark up -->
|
||||
<!-- KLUDGE: There doesn't seem to be any DocBook tag for names of
|
||||
programming languages. Typesetting Common Lisp as an
|
||||
<application> looks funny. Is there a better way?
|
||||
WHN 20000505 -->
|
||||
<!ENTITY CommonLisp "Common Lisp">
|
||||
<!ENTITY Lisp "Lisp">
|
||||
|
||||
<!-- document components -->
|
||||
<!ENTITY ch-intro SYSTEM "intro.sgml">
|
||||
<!ENTITY ch-compiler SYSTEM "compiler.sgml">
|
||||
<!ENTITY ch-efficiency SYSTEM "efficiency.sgml">
|
||||
<!ENTITY ch-beyond-ansi SYSTEM "beyond-ansi.sgml">
|
||||
<!ENTITY ch-ffi SYSTEM "ffi.sgml">
|
||||
|
||||
]>
|
||||
|
||||
<book>
|
||||
|
||||
<bookinfo>
|
||||
<title>&SBCL; User Manual</title>
|
||||
<legalnotice>
|
||||
|
||||
<para>This manual is part of the &SBCL; software system. See the
|
||||
<filename>README</> file for more information.</para>
|
||||
|
||||
<para>This manual is largely derived from the manual for the &CMUCL;
|
||||
system, which was produced at Carnegie Mellon University and
|
||||
later released into the public domain. This manual is in the
|
||||
public domain and is provided with absolutely no warranty. See the
|
||||
<filename>COPYING</> and <filename>CREDITS</> files for more
|
||||
information.</para>
|
||||
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
|
||||
&ch-intro;
|
||||
&ch-compiler;
|
||||
&ch-efficiency;
|
||||
&ch-beyond-ansi;
|
||||
&ch-ffi;
|
||||
|
||||
<colophon>
|
||||
<para>This manual is maintained in SGML/DocBook, and automatically
|
||||
translated into other forms (e.g. HTML or TeX). If you're
|
||||
<emphasis>reading</> this manual in one of these non-DocBook
|
||||
translated forms, that's fine, but if you want to <emphasis>modify</>
|
||||
this manual, you are strongly advised to seek out a DocBook version
|
||||
and modify that instead of modifying a translated version. Even
|
||||
better might be to seek out <emphasis>the</> DocBook version
|
||||
(maintained at the time of this writing as part of
|
||||
<ulink url="http://sbcl.sourceforge.net/">the &SBCL; project</>)
|
||||
and submit a patch.</para>
|
||||
</colophon>
|
||||
|
||||
</book>
|
||||
45
doc/user-manual.xml
Normal file
45
doc/user-manual.xml
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "entities.inc">
|
||||
%myents;
|
||||
]>
|
||||
|
||||
<book lang="en">
|
||||
<bookinfo>
|
||||
<title>&SBCL; User Manual</title>
|
||||
<legalnotice>
|
||||
|
||||
<para>This manual is part of the &SBCL; software system. See the
|
||||
<filename>README</filename> file for more information.</para>
|
||||
|
||||
<para>This manual is largely derived from the manual for the
|
||||
&CMUCL; system, which was produced at Carnegie Mellon University
|
||||
and later released into the public domain. This manual is in the
|
||||
public domain and is provided with absolutely no warranty. See the
|
||||
<filename>COPYING</filename> and <filename>CREDITS</filename>
|
||||
files for more information.</para>
|
||||
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
|
||||
<xi:include href="intro.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="compiler.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="efficiency.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="beyond-ansi.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="ffi.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<colophon id="colophon">
|
||||
<para>This manual is maintained in SGML/DocBook, and automatically
|
||||
translated into other forms (e.g. HTML or TeX). If you're
|
||||
<emphasis>reading</emphasis> this manual in one of these non-DocBook
|
||||
translated forms, that's fine, but if you want to
|
||||
<emphasis>modify</emphasis> this manual, you are strongly advised to
|
||||
seek out a DocBook version and modify that instead of modifying a
|
||||
translated version. Even better might be to seek out
|
||||
<emphasis>the</emphasis> DocBook version (maintained at the time of
|
||||
this writing as part of <ulink url="http://sbcl.sourceforge.net/">the
|
||||
&SBCL; project</ulink>) and submit a patch.</para>
|
||||
</colophon>
|
||||
|
||||
</book>
|
||||
|
|
@ -17,4 +17,4 @@
|
|||
;;; checkins which aren't released. (And occasionally for internal
|
||||
;;; versions, especially for internal versions off the main CVS
|
||||
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
|
||||
"0.8.6"
|
||||
"0.8.6.1"
|
||||
|
|
|
|||
Loading…
Reference in a new issue