Previous: Byte-Code Objects, Up: Byte Compilation


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