Clojureはバイトコードを作成するために ASM というライブラリ(Javaバイトコード操作用フレームワーク)を 利用しているようです。
(JVMの)Clojureを利用できる環境では(たぶん)ASMが利用できる(clojure.asm)ので、 勉強がてらこのライブラリを利用してHelloWorldプログラムを作成してみます。
(import '[clojure.asm ClassWriter Opcodes]) (def target-name "Hello") (def cw (ClassWriter. ClassWriter/COMPUTE_MAXS)) ;; public class Hello extends java.lang.Object { ... (.visit cw Opcodes/V1_5 ; バージョン Opcodes/ACC_PUBLIC ; アクセス修飾子 target-name ; クラス名 nil ; シグネチャ "java/lang/Object" ; 親クラス nil) ; インターフェース名の配列 ;; MethodWriter ;; public static void main(java.lang.String []){ ... (def mw (.visitMethod cw (bit-or Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) ; アクセス修飾子 "main" ; メソッド名 "([Ljava/lang/String;)V" ; ディスクリプタ(引数と戻り値の型) nil ; シグネチャ nil)) ; 例外名の配列 ;; メソッドの内容 (.visitCode mw) (.visitFieldInsn mw Opcodes/GETSTATIC "java/lang/System" "out" "Ljava/io/PrintStream;") (.visitLdcInsn mw "Hello World!") (.visitMethodInsn mw Opcodes/INVOKEVIRTUAL "java/io/PrintStream" "println" "(Ljava/lang/String;)V") (.visitInsn mw Opcodes/RETURN) (.visitMaxs mw 0 0) (.visitEnd mw) (.visitEnd cw) ;; バイトコードを取得 (def bytecode (.toByteArray cw)) ;; classファイルを作成 (with-open [out (java.io.FileOutputStream. (str target-name ".class"))] (.write out bytecode))
上記のコードを実行すると Hello.class という名前でクラスファイルが作成されるので、 javaコマンドで実行してみます。
> java Hello Hello World!
javapコマンドでバイトコードを逆アセンブルしてみると、 Clojureで書いたコードと対応してるように見えます。
javap -c Hello.class public class Hello { public static void main(java.lang.String[]); Code: 0: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #14 // String Hello World! 5: invokevirtual #20 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return }
Clojureのコンパイル時の動作を詳しく知りたい場合、このライブラリを理解しておいたほうが良さそうです。
0 件のコメント:
コメントを投稿