SBCL has limited support for performing allocation on the stack when a
variable is declared
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 zero
safetycode, 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
&restlists, when these are declared
vectorwhen the result is bound to a variable declared
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
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
labels, with a bound
dynamic-extentdeclaration. 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
defstructhas been declared
inlineand the result of the call to the constructor is bound to a variable declared
Note: structures with “raw” slots can currently be stack-allocated only on x86 and x86-64.
;;; 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
&restlist, even when this is not declared