Previous: Byte-Code Objects, Up: Byte Compilation [Contents][Index]
人はバイトコードを記述しません。それはバイトコンパイラーの仕事です。しかし、好奇心を満たすために、わたしたちはディスアセンブラを提供しています。ディスアセンブラは、バイトコードを人間が読めるフォームに変換します。
バイトコードインタープリターは、シンプルなスタックマシンとして実装されています。これは値を自身のスタックにpushして、計算で使用するためにそれらをpopして取り出し、おの結果を再びそのスタックにpushして戻します。バイトコード関数がリターンするときは、スタックから値をpopして取り出し、その関数の値としてリターンします。
それに加えてスタックとバイトコード関数は、値を変数とスタックの間で転送することにより、普通のLisp変数を使用したり、バインドおよびセットすることができます。
このコマンドは、objectにたいするディスアセンブルされたコードを表示します。インタラクティブに使用した場合、またはbuffer-or-nameがnil
か省略された場合は、*Disassemble*という名前のバッファーに出力します。buffer-or-nameが非nil
の場合は、バッファーもしくは既存のバッファーの名前でなければなりません。その場合は、そのバッファーのポイント位置に出力され、ポイントは出力の前に残りされます。
引数objectには関数名、ラムダ式(Lambda Expressionsを参照)、またはバイトコードオブジェクト(Byte-Code Objectsを参照)を指定できます。ラムダ式の場合、disassemble
はそれをコンパイルしてから、そのコンパイル済みコードをディスアセンブルします。
以下にdisassemble
関数を使用した例を2つ示します。バイトコードとLispソースを関連付ける助けとなるように、説明的なコメントを追加してあります。これらのコメントは、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 ; integer
の値を取得して
; それをスタック上にpushする。
1 constant 1 ; スタック上に1をpushする。
2 eqlsign ; 2つの値をスタックからpopして取り出し、 ; それらを比較して結果をスタック上にpushする。
3 goto-if-nil 1 ; スタックのトップをpopしてテストする。
; nil
なら1へ、それ以外はcontinue。
6 constant 1 ; スタックのトップに1をpushする。
7 return ; スタックのトップの要素をリターンする。
8:1 varref integer ;integer
の値をスタック上にpushする。 9 constant factorial ;factorial
をスタック上にpushする。 10 varref integer ;integer
の値をスタック上にpushする。 11 sub1 ;integer
をpopして値をデクリメントする。 ; スタック上に新しい値をpushする。 12 call 1 ; スタックの最初(トップ)の要素を引数として ; 関数factorial
を呼び出す。 ; リターン値をスタック上にpushする。
13 mult ; スタックのトップ2要素をpopして取り出し乗じ ; 結果をスタック上にpushする。 14 return ; スタックのトップ要素をリターンする。
silly-loop
は幾分複雑です:
(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 ; current-time-string
を
; スタック上のトップにpushする。
1 call 0 ; 引数なしでcurrent-time-string
を呼び出し
; 結果をスタック上にpushする。
2 varbind t1 ; スタックをpopしてt1
にpopされた値をバインドする。
3:1 varref n ; 環境からn
の値を取得して
; その値をスタック上にpushする。
4 sub1 ; スタックのトップから1を減ずる。
5 dup ; スタックのトップを複製する。 ; たとえばスタックのトップをコピーしてスタック上にpushする。 6 varset n ; スタックのトップをpopして ;n
をその値にバインドする。 ;; (要はシーケンスdup varset
はpopせずに ;; スタックのトップをn
の値にコピーする。)
7 constant 0 ; スタック上に0をpushする。 8 gtr ; スタックのトップ2値をpopして取り出し ; nが0より大かテストし ; 結果をスタック上にpushする。
9 goto-if-not-nil 1 ; n
> 0なら1へ
; (これはwhile-loopを継続する)
; それ以外はcontinue。
12 varref t1 ;t1
の値をスタック上にpushする。 13 constant current-time-string ;current-time-string
を ; スタックのトップにpushする。 14 call 0 ; 再度current-time-string
を呼び出す。
15 unbind 1 ; ローカル環境のt1
をアンバインドする。
16 list2 ; スタックのトップ2要素をpopして取り出し
; それらのリストを作りスタック上にpushする。
17 return ; スタックのトップの値をリターンする。
Previous: Byte-Code Objects, Up: Byte Compilation [Contents][Index]