Disassembled Byte-Code
======================
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 humanly 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.
- Command: disassemble object &optional stream
This function prints the disassembled code for OBJECT. If STREAM
is supplied, then output goes there. Otherwise, the disassembled
code is printed to the stream `standard-output'. The argument
OBJECT can be a function name or a lambda expression.
As a special exception, if this function is used interactively, it
outputs to a buffer named `*Disassemble*'.
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 `disassemble'. These
examples show unoptimized byte-code. Nowadays byte-code is usually
optimized, but we did not want to rewrite these examples, since they
still serve their purpose.
(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 constant 1 ; Push 1 onto stack.
1 varref integer ; Get value of `integer'
; from the environment
; and push the value
; onto the stack.
2 eqlsign ; Pop top two values off stack,
; compare them,
; and push result onto stack.
3 goto-if-nil 10 ; Pop and test top of stack;
; if `nil', go to 10,
; else continue.
6 constant 1 ; Push 1 onto top of stack.
7 goto 17 ; Go to 17 (in this case, 1 will be
; returned by the function).
10 constant * ; Push symbol `*' onto stack.
11 varref integer ; Push value of `integer' onto stack.
12 constant factorial ; Push `factorial' onto stack.
13 varref integer ; Push value of `integer' onto stack.
14 sub1 ; Pop `integer', decrement value,
; push new value onto stack.
; Stack now contains:
; - decremented value of `integer'
; - `factorial'
; - value of `integer'
; - `*'
15 call 1 ; Call function `factorial' using
; the first (i.e., the top) element
; of the stack as the argument;
; push returned value onto stack.
; Stack now contains:
; - result of recursive
; call to `factorial'
; - value of `integer'
; - `*'
16 call 2 ; Using the first two
; (i.e., the top two)
; elements of the stack
; as arguments,
; call the function `*',
; pushing the result onto the stack.
17 return ; Return the top element
; of the stack.
=> nil
The `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-string'
; with no argument,
; pushing result onto stack.
2 varbind t1 ; Pop stack and bind `t1'
; to popped value.
3 varref n ; Get value of `n' from
; the environment and push
; the value onto the stack.
4 sub1 ; Subtract 1 from top of stack.
5 dup ; Duplicate the top of the stack;
; i.e., copy the top of
; the stack and push the
; copy onto the stack.
6 varset n ; Pop the top of the stack,
; and bind `n' to the value.
; In effect, the sequence `dup varset'
; copies the top of the stack
; into the value of `n'
; without 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-nil-else-pop 17 ; Goto 17 if `n' <= 0
; (this exits the while loop).
; else pop top of stack
; and continue
12 constant nil ; Push `nil' onto stack
; (this is the body of the loop).
13 discard ; Discard result of the body
; of the loop (a while loop
; is always evaluated for
; its side effects).
14 goto 3 ; Jump back to beginning
; of while loop.
17 discard ; Discard result of while loop
; by popping top of stack.
; This result is the value `nil' that
; was not popped by the goto at 9.
18 varref t1 ; Push value of `t1' onto stack.
19 constant current-time-string ; Push
; `current-time-string'
; onto top of stack.
20 call 0 ; Call `current-time-string' again.
21 list2 ; Pop top two elements off stack,
; create a list of them,
; and push list onto stack.
22 unbind 1 ; Unbind `t1' in local environment.
23 return ; Return value of the top of stack.
=> nil