Dynamic-extent allocation - SBCL 1.0.31 User Manual
Description: SBCL 1.0.31 User Manual

Next: Modular arithmetic, Previous: Slot access, Up: Efficiency

### 6.2 Dynamic-extent allocation

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.

— Variable: sb-ext:*stack-allocate-dynamic-extent*

> 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 zero `safety` 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`.
- simple forms of `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.

- closures defined with `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`.
- user-defined structures when the structure constructor defined using `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.

- all of the above when they appear as initial parts of another stack-allocated object.

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

- Stack allocation of assigned-to closed-over variables, where these are declared `dynamic-extent`;
- Automatic detection of the common idiom of applying a function to some defaults and a `&rest` list, even when this is not declared `dynamic-extent`;
- Automatic detection of the common idiom of calling quantifiers with a closure, even when the closure is not declared `dynamic-extent`.