-
Notifications
You must be signed in to change notification settings - Fork 10
Bootstrap from C
Attila Lendvai edited this page Feb 12, 2014
·
2 revisions
Aaron,
> What is the purpose of the decode(...) function? I see that it is
> doing a substitution of symbols for Fixed and Subr where
> appropriate; why is this not be handled in subr_eval_symbol(...)?
encode, en(code)list, etc., try to increase performance by finding
which binding a name refers to at function definition time, removing
the need to traverse a long association list for every variable access
during evaluation. For globals they replace a name with a direct
reference to its binding's value location. For locals they simulate
the stack of local contexts that will be created at run time and
encode variable accesses as nesting level (number of contexts to
'pop') plus offset (into the context you arrived at).
For globals that refer to primitives or functions there is the
opportunity to short-circuit the call to its final destination without
ever indirecting through the binding at runtime. This changes the
usual semantics of define and set, in which changing the value of a
definition during execution normally changes the value seen by all
references to it. When functions are short-circuited, all references
to a function that were made in function definitions completed before
changing the value with 'set' will continue to refer to the original
value. Neither semantic is obviously more correct than the other.
The former is 'classic' Lisp and the latter has some appealing
encapsulation properties.
The contexts and bindings that are created during this process are
never used for execution.
> Is decode(...) preparing something for eval(...) that would be hard
> to do from within eval(...)?
It is preparing direct references to associations for globals and to
level+offset bindings for locals in LIFO contexts, removing (in most
cases) the need for eval to traverse an alist during execution.
> Continuing, we see that decode(...) must make accommodations for
> special forms like lambda and let. In both cases it prepends
> bindings to the environment that are set to nil. Presumably the
> bindings are intended for the recursion that comes from enlist(...);
> at which point the same process repeats for each element of the
> lambda/let. Why are these bindings relevant to the recursive call?
This is tracking the nesting of contexts that are created by let and
by the parameter list of lambda so that encode can convert names that
refer to local variables into their level+offset location at runtime.
> This is with respect to the minimal maru available in the google
> code repository; although maru-2.4 appears to have a very similar
> but more developed decode(...) mechanism.
The latest version of Maru removes the mechanism entirely because
adding a small runtime cache of symbol-to-binding mappings to the
association list lookup is far simpler and performs in almost all
cases just as well as the complicated pre-encoded version.
Hope that helps.
Regards,
Ian