[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

16.7 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


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated on May 2, 2002 using texi2html