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-extent
declarations 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 zerosafety
code, 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
.