16.8 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 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 or a
byte-code object. If it is a lambda expression, disassemble
compiles
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 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
|
Ce document a été généré par Eric Reinbold le 13 Octobre 2007 en utilisant texi2html 1.78.