Calls to (null? x)
usually appear as the predicate to
a conditional. We can specialize the conditional. Instead of
[if [primitive-null?-argument0] [quote 69] [quote 420]]
We create a new S-code construct, if-null?-argument0
, and
construct the conditional as
[if-null?-argument0 [quote 69] [quote 420]]
We avoid a recursive call and generating a ’T or ’NIL value and testing it, we just test for null and jump to the appropriate branch, just like the compiled code would have done.
Multiple arguments
We can further specialize the conditional based on the types of the
consequent and alternative. In this case, they are both quoted
values, so we can specialize the conditional to
[if-null?-argument0-q-q 69 420]
. (Where the name of
the S-code type is derived from the type of the consequent and
alternative.)
if-null?-argument0-q-q
is an esoteric S-code type that
codes a test of the first argument for null, and if it is null,
returns the first quoted value, otherwise the second quoted value.
This S-code type runs just as fast as compiled code. Indeed the
machine instructions for evaluating this S-code are the same as what
the compiler would have generated for the original Lisp form.
But there is a problem
Why not continue in this vein specializing up the S-code tree? Wouldn’t our interpreter be as fast as compiled code? Well it would, but there is a problem. Every time we add a new S-code type, we add new opportunities for specialization to the containing nodes. The number of ways to specialize a node is the product of the number of ways to specialize its children, so the number of ways to specialize the S-code tree grows exponentially with the number of S-code types. The few specializations I’ve just mentioned end up producing hundreds of specialized S-code types. Many of these specialized S-code types are quite esoteric and apply at most to only one or two nodes in the S-code tree for the entire program and runtime system. Performing another round of inlining and specialization would produce thousands of specialized S-code types — too many to author by hand, and most of which would be too esoteric to ever be actually used.
The solution, of course, is to automate the specialization process. We only generate a specialized S-code type when it is actually used by a program. The number of specialized S-code types will be limited by the number of ways programs are written, which is linear in the size of the program.
But specializing the code when we first encounter it is just JIT compiling the code. We’ve just reinvented the compiler. We might as well skip the multi-level specialization of the S-code tree and write a simple JIT compiler.
No comments:
Post a Comment