Next: Modular arithmetic, Previous: Slot access, Up: Efficiency
SBCL has limited support for performing allocation on the stack when a
variable is declared dynamic-extent. The dynamic-extent
declarations are not verified, but are simply trusted as long as
sb-ext:*stack-allocate-dynamic-extent* is true.
If dynamic extent constraints specified in the Common Lisp standard are violated, the best that can happen is for the program to have garbage in variables and return values; more commonly, the system will crash.
If true (the default), the compiler respects
dynamic-extentdeclarations and stack allocates otherwise inaccessible parts of the object whenever possible. Potentially long (over one page in size) vectors are, however, not stack allocated except in zerosafetycode, as such a vector could overflow the stack without triggering overflow protection.
There are many cases when dynamic-extent declarations could be
useful. At present, SBCL implements stack allocation for
&rest lists, when these are declared dynamic-extent.
cons, list, list*, and vector when the
result is bound to a variable declared dynamic-extent.
make-array, whose result is bound to a variable
declared dynamic-extent: stack allocation is possible only if
the resulting array is known to be both simple and one-dimensional,
and has a constant :element-type.
Note: stack space is limited, so allocation of a large vector
may cause stack overflow. For this reason potentially large vectors,
which might circumvent stack overflow detection, are stack allocated
only in zero safety policies.
flet or labels, with a bound
dynamic-extent declaration. Closed-over variables, which are
assigned to (either inside or outside the closure) are still allocated
on the heap. Blocks and tags are also allocated on the heap, unless
all non-local control transfers to them are compiled with zero
safety.
defstruct has been declared inline and the result of the
call to the constructor is bound to a variable declared
dynamic-extent.
Note: structures with “raw” slots can currently be stack-allocated only on x86 and x86-64.
Examples:
;;; Declaiming a structure constructor inline before definition makes
;;; stack allocation possible.
(declaim (inline make-thing))
(defstruct thing obj next)
;;; Stack allocation of various objects bound to DYNAMIC-EXTENT
;;; variables.
(let* ((list (list 1 2 3))
(nested (cons (list 1 2) (list* 3 4 (list 5))))
(vector (make-array 3 :element-type 'single-float))
(thing (make-thing :obj list
:next (make-thing :obj (make-array 3)))))
(declare (dynamic-extent list nested vector thing))
...)
;;; Stack allocation of arguments to a local function is equivalent
;;; to stack allocation of local variable values.
(flet ((f (x)
(declare (dynamic-extent x))
...))
...
(f (list 1 2 3))
(f (cons (cons 1 2) (cons 3 4)))
...)
;;; Stack allocation of &REST lists
(defun foo (&rest args)
(declare (dynamic-extent args))
...)
Future plans include
dynamic-extent;
&rest list, even when this is not declared
dynamic-extent;
dynamic-extent.