A basic interpreter works by walking down the AST and evaluating nodes recursively: when the interpreter encounters an expression, it dispatches on the type of expression to decide how to perform the evaluation. Here’s the key insight to get a massive speed bump with very little effort:that dispatch is expensive and can be performed ahead-of-time. We can walk through the codeonceand precompute all the dispatching work.
This is not a new idea. The first description that I’m aware of comes from Feeley and Lapalme [1]. A name for this technique is making athreaded interpreter. It’s nowhere near as fast as a native code compiler, but interpreters are easy to write, and this is a very simple way to get a very big boost in performance.
This paper describes a new approach to compiling which is based on the extensive use of closures. In this method, a compiled expression is embodied by a closure whose application performs the evaluation of the given expression. For each primitive construct contained in the expression to compile, a closure is generated. As a whole, the compiled expression consists of a network of these closures. In a way, ‘code generation’ is replaced by ‘closure generation’. This method, combined with an efficient closure implementation, produces compiled code which compares favorably (in execution time) with its interpreted counter-part. It can also be used to implement compilers for embedded languages and as it has been implemented in Scheme, it yields a straightforward metacircular compiler for Scheme.