People do not write byte-code; that job is left to the byte compiler. But we provide a disassembler to satisfy a cat-like curiosity. The disassembler converts the byte-compiled code into human-readable form.
The byte-code interpreter is implemented as a simple stack machine. It pushes values onto a stack of its own, then pops them off to use them in calculations whose results are themselves pushed back on the stack. When a byte-code function returns, it pops a value off the stack and returns it as the value of the function.
In addition to the stack, byte-code functions can use, bind, and set ordinary Lisp variables, by transferring values between variables and the stack.
disassembleobject &optional buffer-or-name
This command displays the disassembled code for object. In
interactive use, or if buffer-or-name is
nil or omitted,
the output goes in a buffer named *Disassemble*. If
buffer-or-name is non-
nil, it must be a buffer or the
name of an existing buffer. Then the output goes there, at point, and
point is left before the output.
The argument object can be a function name, a lambda expression
(see Lambda Expressions), or a byte-code object (see Byte-Code Objects). If it is a lambda expression,
it and disassembles the resulting compiled code.
Here are two examples of using the
disassemble function. We
have added explanatory comments to help you relate the byte-code to the
Lisp source; these do not appear in the output of
(defun factorial (integer) "Compute factorial of an integer." (if (= 1 integer) 1 (* integer (factorial (1- integer))))) ⇒ factorial
(factorial 4) ⇒ 24
(disassemble 'factorial) -| byte-code for factorial: doc: Compute factorial of an integer. args: (integer)
0 varref integer ; Get the value of
integerand ; push it onto the stack. 1 constant 1 ; Push 1 onto stack.
2 eqlsign ; Pop top two values off stack, compare ; them, and push result onto stack.
3 goto-if-nil 1 ; Pop and test top of stack; ; if
nil, go to 1, else continue. 6 constant 1 ; Push 1 onto top of stack. 7 return ; Return the top element of the stack.
8:1 varref integer ; Push value of
integeronto stack. 9 constant factorial ; Push
factorialonto stack. 10 varref integer ; Push value of
integeronto stack. 11 sub1 ; Pop
integer, decrement value, ; push new value onto stack. 12 call 1 ; Call function
factorialusing first ; (i.e., top) stack element as argument; ; push returned value onto stack.
13 mult ; Pop top two values off stack, multiply ; them, and push result onto stack. 14 return ; Return the top element of the stack.
silly-loop function is somewhat more complex:
(defun silly-loop (n) "Return time before and after N iterations of a loop." (let ((t1 (current-time-string))) (while (> (setq n (1- n)) 0)) (list t1 (current-time-string)))) ⇒ silly-loop
(disassemble 'silly-loop) -| byte-code for silly-loop: doc: Return time before and after N iterations of a loop. args: (n)
0 constant current-time-string ; Push
current-time-string; onto top of stack.
1 call 0 ; Call
current-time-stringwith no ; argument, push result onto stack.
2 varbind t1 ; Pop stack and bind
t1to popped value.
3:1 varref n ; Get value of
nfrom the environment ; and push the value on the stack. 4 sub1 ; Subtract 1 from top of stack.
5 dup ; Duplicate top of stack; i.e., copy the top ; of the stack and push copy onto stack. 6 varset n ; Pop the top of the stack, ; and bind
nto the value. ;; (In effect, the sequence
dup varsetcopies the top of the stack ;; into the value of
nwithout popping it.)
7 constant 0 ; Push 0 onto stack. 8 gtr ; Pop top two values off stack, ; test if n is greater than 0 ; and push result onto stack.
9 goto-if-not-nil 1 ; Goto 1 if
n> 0 ; (this continues the while loop) ; else continue.
12 varref t1 ; Push value of
t1onto stack. 13 constant current-time-string ; Push
current-time-string; onto the top of the stack. 14 call 0 ; Call
15 unbind 1 ; Unbind
t1in local environment. 16 list2 ; Pop top two elements off stack, create a ; list of them, and push it onto stack. 17 return ; Return value of the top of stack.