GNU Emacs Lisp は、関数を(書かれたままの)テキストから、 (より効率良く実行でき る) バイトコードと呼ばれる(特別な)形式にトランスレートするコンパイラを持ってい ます。このコンパイラは(各々の)関数定義をバイトコードで置き換えます。バイトコー ドファイルをロードすると、 (その)ファイルで定義された関数はバイトインタープリ タで評価されます。
(各々の)関数定義は byte-compile 関数でバイトコンパイルされます。ファイル全体を byte-compile-file でコンパイルすることもできます。複数のファイルを byte- recompile-directory や batch-byte-compule でバイトコンパイルすることもできま す。
バイトコンパイルしたコードは、そのマシンのハードウェアで(直接)実行されるのでは なく、 (コンパイルされたほとんどのコードを実行できる) バイトインタープリタで評 価されるため、バイトコードは、 (再コンパイルしなくても)マシンからマシンに移す ことができます。
バイトコンパイルされた関数は C で書かれた primitive 関数ほど効率的ではありませ んが、インタープリットされるものよりはずっと速く走ります。 (粗く)比較するため には、以下に示した例を参照して下さい。
マクロを用いたコードをバイトコンパイルする場合は注意して下さい。マクロは(全 て)、用いる前に定義されてなくてはいけません。詳細に関してはセクション 11.2 [defmacro]、ページ 93 を参照して下さい。
(defun silly-loop (n) (setq t1 (current-time-string)) (while (> n 0) (setq n (1- n))) (setq t2 (current-time-string)) (list t1 t2))
=> silly-loop
(silly-loop 100000) => ("Thu Oct 8 20:32:21 1987" "Thu Oct 8 20:34:42 1987") ; 2 分 21 秒
(byte-compile 'silly-loop) => [Compiled code not shown]
(silly-loop 100000) => ("Thu Oct 8 20:40:47 1987" "Thu Oct 8 20:41:17 1987") ; 30 秒
この例では、インタープリットされたコードは実行に 2:21 要していますが、バイトコ ンパイルされたコードは 0:30 しか要していません。この結果はバイトコンパイルの効 果をよく示しています。しかし、これは呼ばれる関数によって大きく変化します。
Function: byte-compile symbol
この関数は、 symbol の関数定義をバイトコンパイルし、コンパイルした結果で (前の)定義を置き換えます。 symbol の関数セルは関数に対する(実際の)コードを 含んでなくてはいけません。コンパイラは他のシンボルへの間接は扱いません。
Command: byte-compile-file filename
この関数は、 filename という名前の Lisp コードのファイルをコンパイルし、バ イトコードのファイルを作ります。出力ファイルの名前は filename の後ろに "c" を付けたものになります。
インタラクティブに呼ばれた場合、ファイル名を求め(エコーアリアに)プロンプト を出します。
lewis@slug[3] % ls -l push* -rw-r--r-- 1 lewis 0 791 Oct 5 20:31 push.el
(byte-compile-file "~/emacs/push.el") => t
lewis@slug[3] % ls -l push* -rw-r--r-- 1 lewis 0 791 Oct 5 20:31 push.el -rw-r--r-- 1 lewis 0 638 Oct 8 20:25 push.elc
Command: byte-recompile-directory directory flag
この関数は、 directory 中の (再)コンパイルを必要とする (全) `.el' ファイル を (再)コンパイルします。(`.elc' ファイルが存在している場合も)それが `.el' ファイルより古い場合、(再)コンパイルを必要とします。
`.el' ファイルが存在していて、それに対する `.elc' ファイルが存在しない場 合、 flag を調べ、これが nil の場合、このファイルを無視します。 non-nil の 場合、(ユーザーに対し)このファイルをコンパイルするか否かを尋ねます。
インテラクティブに呼ばれた場合、 directory を求め(エコーエリアに)プロンプ トを出し、 flag は未処理のプレフィックスアーギュメントになります。
Function: batch-byte-compile
この関数は、コマンド行の(残りの)ファイルに対し byte-compile-file を走らせ ます。この関数は終了時に Emacs を kill するため、 (Emacs の)バッチ実行での み用いられます。前のファイルのコンパイルでエラーが生じても、各々のファイル に対し処理を行ないます(もちろん、エラーの生じたファイルに対してはコンパイ ルしたコードは出力しません)。
lewis@slug[6] % emacs -batch -f batch-byte-compile $emacs/ ~/*.el"
Function: byte-code
これは、(実際に)バイトコードをインタープリットする関数です。 (コンパイルさ れた関数に対し) Lisp evaluator から呼ばれます。 (通常) ユーザーコードから 呼ばれることはありません。
Function: disassemble object &optional stream
この関数は、 object を逆アセンブルしたコードを print します。 stream が与 えられた場合、出力はそこに向けられます。与えられない場合、逆アセンブルした コードを標準出力に print します。 object は、関数名、lambda 式、symbol- function の返す(任意の)関数オブジェクトでありえます。
object がまだコンパイルされてない場合、コンパイルは行ないますが、 (再)定義 は行ないません。
(disassemble 'silly-loop) -> byte code for silly-loop: args: (n)
0 constant current-time-string 1 call 0 2 dup 3 varset t1 4 discard 5 varref n 6 constant 0 7 gtr 8 goto-if-nil-else-pop 19 11 varref n 12 sub1 13 dup 14 varset n 15 discard 16 goto 5 19 discard 20 constant current-time-string 21 call 0 22 cup 23 varset t2 24 discard 25 varref t1 26 varred t2
27 list2 28 return
=> nil