elisp: Disassembly

 
 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 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.
 
  -- 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
DONTPRINTYET       (SeeLambda Expressions), or a byte-code object (*noteDONTPRINTYET       (SeeLambda Expressions), or a byte-code object (See
      Byte-Code Objects).  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’.
 
      (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 ‘integer’ and
                                ;   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 ‘integer’ onto stack.
      9   constant factorial    ; Push ‘factorial’ onto stack.
      10  varref   integer      ; Push value of ‘integer’ onto stack.
      11  sub1                  ; Pop ‘integer’, decrement value,
                                ;   push new value onto stack.
      12  call     1            ; Call function ‘factorial’ using 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.
 
    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, push result onto stack.
      2   varbind  t1           ; Pop stack and bind ‘t1’ to popped value.
      3:1 varref   n            ; Get value of ‘n’ from 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 ‘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-not-nil 1     ; Goto 1 if ‘n’ > 0
                                ;   (this continues the while loop)
                                ;   else continue.
      12  varref   t1           ; Push value of ‘t1’ onto stack.
      13  constant current-time-string  ; Push ‘current-time-string’
                                        ;   onto the top of the stack.
      14  call     0            ; Call ‘current-time-string’ again.
      15  unbind   1            ; Unbind ‘t1’ in 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.