Optimize special variable binding on sb-thread.
[sbcl.git] / doc / internals / specials.texinfo
1 @node Specials
2 @comment  node-name,  next,  previous,  up
3 @chapter Specials
4
5 @menu
6 * Overview::
7 * Binding and unbinding::
8 @end menu
9
10 @node Overview
11 @section Overview
12
13 Unithread SBCL uses a shallow binding scheme: the current value of a
14 symbol is stored directly in its value slot. Accessing specials is
15 pretty fast but it's still a lot slower than accessing lexicals.
16
17 With multithreading it's slightly more complicated. The symbol's value
18 slot contains the global value and each symbol has a @code{TLS-INDEX}
19 slot that - when it's first bound - is set to a unique index of the
20 thread local area reserved for this purpose. The tls index is
21 initially zero and at index zero in the tls @code{NO-TLS-VALUE-MARKER}
22 resides. @code{NO-TLS-VALUE-MARKER} is different from
23 @code{UNBOUND-MARKER} to allow @code{PROGV} to bind a special to no
24 value locally in a thread.
25
26 @node Binding and unbinding
27 @section Binding and unbinding
28
29 Binding goes like this: the binding stack pointer (bsp) is bumped, old
30 value and symbol are stored at bsp - 1, new value is stored in symbol's
31 value slot or the tls. On multithreaded builds, @code{TLS-INDEX} is
32 stored on the binding stack in place of the symbol.
33
34 Unbinding: the symbol's value is restored from bsp - 1, value and
35 symbol at bsp - 1 are set to zero, and finally bsp is decremented.
36
37 The @code{UNBIND-TO-HERE} VOP assists in unwinding the stack. It
38 iterates over the bindings on the binding stack until it reaches the
39 prescribed point. For each binding with a non-zero symbol it does an
40 @code{UNBIND}.
41
42 How can a binding's symbol be zero? @code{BIND} is not pseudo atomic
43 (for performance reasons) and it can be interrupted by a signal. If
44 the signal hits after the bsp is incremented but before the values on
45 the stack are set the symbol is zero because a thread starts with a
46 zeroed tls plus @code{UNBIND} and @code{UNBIND-TO-HERE} both zero the
47 binding being unbound.
48
49 Zeroing the binding's symbol would not be enough as the binding's
50 value can be moved or garbage collected and if the above interrupt
51 initiates gc (or be @code{SIG_STOP_FOR_GC}) it will be greeted by a
52 garbage pointer.
53
54 Furthermore, @code{BIND} must always write the value to the binding
55 stack first and the symbol second because the symbol being non-zero
56 means validity to @code{UNBIND-TO-HERE}. For similar reasons
57 @code{UNBIND} also zeroes the symbol first. But if it is interrupted
58 by a signal that does an async unwind then @code{UNBIND-TO-HERE} can
59 be triggered when the symbol is zeroed but the value is not. In this
60 case @code{UNBIND-TO-HERE} must zero out the value to avoid leaving
61 garbage around that may wreck the ship on the next @code{BIND}.
62
63 In other words, the invariant is that the binding stack above bsp only
64 contains zeros. This makes @code{BIND} safe in face of gc triggered at
65 any point during its execution.
66
67 On platforms with the @code{UNWIND-TO-FRAME-AND-CALL-VOP} feature, it's
68 possible to restart frames in the debugger, unwinding the binding stack.
69 To know how much to unwind, @code{BIND-SENTINEL} in the beginning of a
70 function puts the current frame pointer on the binding stack with
71 @code{UNBOUND-MARKER-WIDETAG} instead of the symbol/tls-index.
72 @code{UNBIND-SENTINEL} removes it before returning. The debugger then
73 search for @code{UNBOUND-MARKER-WIDETAG} with the value being equal to
74 the desired frame, and calls @code{UNBIND-TO-HERE}. Consequently,
75 @code{UNBIND-TO-HERE} treats @code{UNBOUND-MARKER-WIDETAG} the same way
76 as zeros.
77