37.7. Bytecode Design

37.7.1. When to add a new bytecode?
37.7.2. Why JMPTAIL?

This section offers some insight into bytecode design in the form of questions and answers.

37.7.1. When to add a new bytecode?

Question:

Does it make sense to define a new bytecode instruction for RESTART-CASE? Why? Why not?

Answer: Is it speed critical?

RESTART-CASE is a glorified LET binding for SYSTEM::*ACTIVE-RESTARTS* and could well profit from a separate bytecode: it would make it non-consing[3]. (Remember that RESTARTs have dynamic extent and therefore do not really need to be heap allocated.)

The reason HANDLER-BIND has its own bytecodes and RESTART-CASE does not is that HANDLER-BIND can occur in inner computation loops, whereas RESTART-CASE occurs only as part of user-interface programming and therefore not in inner loops where its consing could hurt much.

37.7.2. Why JMPTAIL?

Question:

Consider this function and its disassembly:

(defun foo (x y) (if (or (= x 0) (= y 0)) (+ x y) (foo y (1- x))))
(DISASSEMBLE 'foo)
8     (LOAD&PUSH 1)
9     (LOAD&DEC&PUSH 3)
11    (JMPTAIL 2 5 L0)

Why are the arguments pushed onto the STACK, just to be popped off of it during the JMPTAIL? Why not a sequence of LOAD, STORE and SKIP instructions followed by a JMP?

Answer: This is a shortcut for the most common use

Using JMPTAIL requires 3 instructions, JMP requires more. When JMPTAIL needs to be called, we usually have some stuff close to the top of the STACK which will become the new arguments, and some junk between these new arguments and the closure object. JMPTAIL removes the junk. JMPTAIL is a convenient shortcut which shortens the bytecode - because typically one would really have to clean-up the STACK by hand or make the calculations in src/compiler.lisp more complicated.


These notes document CLISP version 2.49.93+Last modified: 2018-02-19