GVM: GroovyでJavaVMを書いたよ
前置き
さてやっと発売日となりました、私も著者の一人として執筆に参加している「プログラミングGroovy」ですが、ご覧になった方もいらっしゃると思います。
興味がありましたら読んで見てください。Groovy普及の1助になれば幸いです。Javaプログラマであれば読んで損はない本だと思います。
ghello
さて、発売日といえば、昨日は著者の1人である関谷さん(id:ksky)が、#ghelloというイベント(まとめサイト、Googleキャッシュ)を行っていて、これはみんなでGroovyでいろいろな「Hello World表示プログラム」を書いて、Twitterで#ghelloタグつけて発言する、というもので、なかなか盛り上りました。私も及ばずながら2、3個ツィートして見ました。2番目の「ぉうききぐじぐこきぅ」というのがちょっと狂気入ってそうな感じでお気に入りです。
a=[];"doWelr lolH".eachWithIndex{i,j->i.metaClass.getO={[10,4,6,1,2,8,5,3,7,9,0][j]};a.add(i);};println a.sort{it.o}.join()// #ghello
2011-07-06 02:36:18 via web
print new String('ぉうききぐじぐこきぅ'.collect{it.bytes[2]+223} as byte[], 'UTF-8')" // #ghello
2011-07-06 02:14:18 via web
print Class.getResource("/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.class").text[11775..11786]// #ghello next: @orange_clover
2011-07-06 00:47:05 via web
良い企画だったと思います。ただ、Twitterなので140文字(しかもハッシュタグと次の人指名含めて)制限があり、これが予想外に厳しくて、ストレスが溜る溜る。
GVM: JVM Written in Groovy
なので、カッとなって、文字数制限なしで作ってみました*1。方針としてはGroovyでJava VMを書いてその上でHello Worldを表示させるJavaコード(コンパイルしたクラスファイル)を動作させる。
コードはgistに公開しましたのでリンクしておきます。本体は長いのでこのエントリには末尾に貼っておきます。
以下は実行例です。
$ cat Hello.java package sample; public class Hello { public static void main(String[] args){ Hello h = new Hello(); h.hello(); System.out.println(h.plus(1,2)); for (int i=0; i<10; i++) { System.out.print("i="); System.out.println(i); } } void hello() { System.out.println("Hello World"); } int plus(int i, int j) { return i+j; } } $ mkdir classes $ javac -d ./classes Hello.java $ groovy ./gvm.groovy -cp classes sample.Hello Hello World 3 i=0 i=1 i=2 i=3 i=4 i=5 i=6 i=7 i=8 i=9 $ groovy ./gvm.groovy -h usage: groovy gvm.groovy <class FQCN> -cp,--classpath <arg> classpath -demo,--demo demo -h,--help usage -v,--verbose verbose
デモモード(-demo)もあるので、Javaソースを作ったりjavacしなくてもgvm.groovy単体で実行することができます。
クラスファイルの読み込みとクラス構造やバイトコードの保持については、asmにすべて任せて*2さぼっています。asmはGroovyに組みこまれているバイトコード操作用のライブラリです。Groovy自体がasmによるバイトコード生成に依存して動作しています。
機能的には、足し算はできるが掛け算は(サンプルコードに含まれてないので)実装してないとか、読み込めるクラスは1つでディレクトリのみからでjarは対象外とか、そんな極小な感じです。
Java VMは前から一度は実装してみたいなと思ってて、Groovyなら短時間でできるだろうと思ってやってみました。確かにわりと簡単にはできたのですが*3、適当に作りすぎたのであんまり勉強にはならなったorz。
工夫としては、asmのバイトコード命令をあらわすクラス群(*InsnNode)にmetaClassで「.eval()」メソッドを注入しているところで、これによってコード量が劇的に削減され、単純化されてるんじゃないかと思います。一般に、JavaのクラスライブラリやAPIと連携したりカスタマイズしたりして動くコードを書くのは、Groovyの右に出るものは無いわけです。
Groovyの書き易さは、あらためて本当に体感しました。いやこれはほんとに凄い技術です。Javaで書く気には到底ならないなあ。
Groovy Rocks!