3.2. Compilation [sec_3-2]

3.2.1. Compiler Terminology sec_3-2-1
3.2.1.1. Just-In-Time Native Compilation
3.2.2. Compilation Semantics sec_3-2-2
3.2.2.1. Compiler Macros sec_3-2-2-1
3.2.2.2. Minimal Compilation sec_3-2-2-2
3.2.2.3. Semantic Constraints sec_3-2-2-3
3.2.3. Definition of Similarity sec_3-2-4-2-2
3.2.4. Exceptional Situations in the Compiler sec_3-2-5

3.2.1. Compiler Terminology [sec_3-2-1]

CLISP compiles to platform-independent bytecode.

3.2.1.1. Just-In-Time Native Compilation

Platform Dependent: Only in CLISP built with GNU lightning

The code compiled to bytecodes with optimization levels

(OR (>= 0 SPACE) (<= 1 SPEED))

(by COMPILE, COMPILE-FILE, or (COMPILE)) will be just-in-time (i.e., on the first execution) compiled to native code using GNU lightning.

3.2.2. Compilation Semantics [sec_3-2-2]

3.2.2.1. Compiler Macros [sec_3-2-2-1]

Compiler macros are expanded in the compiled code only, and ignored by the interpreter.

3.2.2.2. Minimal Compilation [sec_3-2-2-2]

When a DEFUN form is EVALuated, the macros used there are expanded, so they must be already defined, and their (re)definition does not affect functions which are already defined.

This means that even the interpreted code is minimally compiled in CLISP.

3.2.2.3. Semantic Constraints [sec_3-2-2-3]

Non-conforming code that does not follow the rule

Special proclamations for dynamic variables must be made in the compilation environment.

can produce quite unexpected results, e.g., observable differences between compiled and interpreted programs:

(defun adder-c (value) (declare (COMPILE)) (lambda (x) (+ x value)))
⇒ ADDER-Ccompiled function; value is lexical
(defun adder-i (value) (lambda (x) (+ x value)))
⇒ ADDER-Iinterpreted function; value is lexical
(defparameter add-c-10 (adder-c 10))
⇒ ADD-C-10compiled function
(defparameter add-i-10 (adder-i 10))
⇒ ADD-I-10interpreted function
(funcall add-c-10 32)
⇒ 42as expected
(funcall add-i-10 32)
⇒ 42as expected
(defvar value 12)
⇒ VALUEaffects ADDER-I and ADD-I-10 but not ADDER-C and ADD-C-10
(funcall add-c-10 32)
⇒ 42as before
(funcall add-i-10 32)
⇒ 44value is now dynamic!

Non-conformance. The code shown above has a SPECIAL proclamation (by DEFVAR) for the variable value in the execution environment (before the last two FUNCALLs) but not in the compilation environment: at the moment the ADDER-I function is defined, value is not known to be a SPECIAL variable. Therefore the code is not conforming.

Rationale

The function ADD-C-10 was compiled before value was declared SPECIAL, so the symbol value was eliminated from its code and the SPECIAL declaration did not affect the return value (i.e., (funcall add-c-10 32) always returned 42).

On the opposite, function ADDER-I was not compiled, so ADD-I-10 was interpreted. Whenever ADD-I-10 is executed, its definition is interpreted all over again. Before DEFVAR, value is evaluated as a lexical (because it is not declared SPECIAL yet), but after DEFVAR, we see a globally SPECIAL symbol value which can have only a global SYMBOL-VALUE (not a local binding), and thus we are compelled to evaluate it to 12.

This behavior was implemented intentionally to ease interactive development, because usually the ADDER-I above would be followed by a (forgotten) DEFVAR.

When a user compiles a program, the compiler is allowed to remember the information whether a variable was SPECIAL or not, because that allows the compiler to generate more efficient code, but in interpreted code, when the user changes the state of a variable, he does not want to re-evaluate all DEFUNs that use the variable.

[ANSI CL standard] gives the implementation freedom regarding interpreted evaluation, how much it wants to remember / cache, and how much it wants to re-evaluate according the current environment, if it has changed. CLISP implements ad-hoc look-up for variables (but not for macros, see Section 3.2.2.2, “Minimal Compilation sec_3-2-2-2”).

3.2.3. Definition of Similarity [sec_3-2-4-2-2]

Hash tables are externalizable objects.

3.2.4. Exceptional Situations in the Compiler [sec_3-2-5]

Both COMPILE and EVAL may SIGNAL the EXT:SOURCE-PROGRAM-ERROR CONDITION which derives from PROGRAM-ERROR and which contains additional slots with accessors

EXT:SOURCE-PROGRAM-ERROR-FORM
Returns the whole form in which the ERROR was SIGNALed
EXT:SOURCE-PROGRAM-ERROR-DETAIL
Returns the specific (usually small) part of the above which triggered the ERROR

Mixing &OPTIONAL and &KEYIt is a bad design to have both &OPTIONAL and &KEY in the same lambda list, especially if the number of optional arguments is even: the users will often forget to supply optional arguments when supplying keys, e.g., (READ-FROM-STRING string :START 5) instead of (READ-FROM-STRING string t nil :START 5). This is why the CLISP compiler issues a STYLE-WARNING in such cases:

(DEFUN foo (&OPTIONAL a &KEY b) (cons a b))
(COMPILE 'foo)
WARNING: in FOO : Mixing &OPTIONAL and &KEY in lambda list (&OPTIONAL A &KEY B) is bad design
FOO ;
1 ;
NIL

These notes document CLISP version 2.49.93+Last modified: 2018-02-19