Duane Rettig <duane@franz.com> wrote:
+---------------
| - As I understand it, Corman Lisp (and perhaps other lisps) take
| the approach that a symbol's value is the nth location of the
| thread-specific data, so the association is done with an index
| into thread-specific data.
+---------------
I had a side conversation with Roger after his talk at ILC 2002, and
came away from it with the following understanding [which may be fuzzy
in some of the details, but I think it's approximately correct]:
As Duane says, in Corman Lisp there's a global count of symbols
(or rather, symbols that are ever referenced as variables, rather
than functions), and there's a per-thread table of that size.
But what's in the per-thread table isn't the "symbol's value"
per se, but a *pointer* (or indirection) to the location with
the symbol's value (truly a binding!). Now by default, this points
to the usual global value cell of the interned symbol (that is,
global variables are by default bound to the value cell of the
symbols which name them), but when a special variable is dynamically
bound then the indirection points to a hidden per-thread location
containing the current dynamic binding.
[Note that it's an implemention choice as to whether further nested
dynamic bindings push/pop the dynamic *value* onto some thread-local
per-variable stack or allocate new locations and push/pop the *bindings*
to those location onto the stack -- in either case the user-visible
effect would be the same. Seems to me it would be simpler and more
consistent to do the latter, but...]
So if there is no active dynamic binding current for some variable
in a given thread, references to that variable see the "global" value
which is visible to *all* threads -- well, all threads that have no
active dynamic binding for it. So a (setq foo <whatever>) is seen
by all such threads, but if the thread doing the SETQ has a current
active dynamic binding for "foo" then the modification is seen only
by that thread. Or something like that...
Anyway, the cost of the scheme is (1) a vector "N" long per thread
[where "N" is the number of global variables that the compiler has
ever seen LET-bound or LAMBDA-bound] and (2) one additional level
of indirection when accessing special variables.
[I'm handwaving details about how "N" gets bumped up at run-time
when you dynamically bind a special variable that was never bound
before, and how the per-thread table get grown as needed. (Lazily,
one hopes...)]
-Rob
-----
Rob Warnock, PP-ASEL-IA <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607