Indy(Invokedynamic) and Bytecode DSL and Brainf*ck
-
Upload
junji-uehara -
Category
Technology
-
view
1.536 -
download
1
description
Transcript of Indy(Invokedynamic) and Bytecode DSL and Brainf*ck
3
Bytecode DSL& Indy& Brainf*ckG*Workshop Z 2013/09/20上原潤二(NTTソフトウェア株式会社)
13年9月20日金曜日
JGGUG G*Workshop Z Copyright(C) NTT Software.
自己紹介上原潤二(@uehaj)NTTソフトウェア(株)Grails推進室JGGUG(日本Grails/Groovyユーザグループ)運営委員書籍:
プログラミングGROOVY(技術評論社)Grails徹底入門(翔泳社)
ブログ「Grな日々」GroovyServ, LispBuilder, GVM(JVM written in Groovy)開発者
213年9月20日金曜日
JGGUG G*Workshop Z Copyright(C) NTT Software.
今日の内容Indyの基礎Bytecode DSLBrainf*ckを実装してみたG*Magazine Vol.7の宣伝
313年9月20日金曜日
JGGUG G*Workshop Z Copyright(C) NTT Software.
テーマ:Indyで遊びたいIndy: Java VM上での動的言語の実行を効率化することを目的とした一連の機能拡張(JSR 292)気軽でないASM面倒くさい
ByteCode DSLを使おう!
413年9月20日金曜日
35
Bytecode DSL
13年9月20日金曜日
JGGUG G*Workshop Z Copyright(C) NTT Software.
ByteCode DSLGroovyの内部DSLで実現されたJavaバイトコードのアセンブラASMのラッパーIndy対応! (重要)
6
@groovyx.ast.bytecode.Bytecodeint fib(int i) { iload 1 iconst_2 if_icmpge l1 iload 1 _goto l2 l1 aload 0 iload 1 iconst_2
isub invokevirtual '.fib', '(I)I' aload 0 iload 1 iconst_1 isub invokevirtual '.fib' ,'(I)I' iadd l2 ireturn}
13年9月20日金曜日
JGGUG G*Workshop Z Copyright(C) NTT Software.
BytecodeDSL以下で@Grab可
groovyによる実行
7
@GrabResolver(name="maven-‐repox", root = "https://raw.github.com/uehaj/maven-‐repo/gh-‐pages/snapshot")@Grab('groovyx.ast.bytecode:groovy-‐bytecode-‐ast:0.2.0-‐separate-‐asm')import groovyx.ast.bytecode.Bytecode
$ groovy fib.groovy102334155
13年9月20日金曜日
3
BytecodeDSLでHello Indy!
8
@GrabResolver(name="maven-‐repo", root="https://raw.github.com/uehaj/maven-‐repo/gh-‐pages/snapshot")@Grab("groovyx.ast.bytecode:groovy-‐bytecode-‐ast:0.2.0-‐separate-‐asm")import groovyx.ast.bytecode.Bytecodeimport java.lang.invoke.*import java.lang.invoke.MethodHandles.Lookupimport static org.objectweb.asm.Opcodes.H_INVOKESTATIC
class HelloIndy { public static CallSite bootstrap(Lookup lookup, String methodName, MethodType type) { assert methodName == 'xx' MethodHandle mh = lookup.findVirtual(java.io.PrintStream, "println", MethodType.methodType(void,[String])) return new ConstantCallSite(mh) } @Bytecode static main(args) { getstatic 'java/lang/System.out','Ljava/io/PrintStream;' ldc 'Hello Indy' invokedynamic 'xx', '(Ljava/io/PrintStream;Ljava/lang/String;)V', [H_INVOKESTATIC, 'HelloIndy','bootstrap', [CallSite, Lookup, String, MethodType]] vreturn }}
13年9月20日金曜日
3
実行
9
$ groovy -Dgroovy.target.bytecode=1.7 HelloIndy.groovyHello Indy
13年9月20日金曜日
310
Indy!!
13年9月20日金曜日
JGGUG G*Workshop Z Copyright(C) NTT Software.
IndyIndyの動作は知ってますよね??
1113年9月20日金曜日
3
従来のinvoke系命令のイメージ
バイトコード命令バイトコード命令Invokestatic/virtual/interface命令 メソッド
バイトコード命令return命令
バイトコード命令
(1)Java VMによって解決されて呼び出される
:
13年9月20日金曜日
3
invokedynamic命令のイメージ
バイトコード命令バイトコード命令Invokedynamic命令 メソッド
バイトコード命令return命令
バイトコード命令
(1)Java以外の言語処理系ランタイムによって解決される
:
13年9月20日金曜日
3
invokedynamicのイメージ(2)
バイトコード命令バイトコード命令Invokedynamic命令バイトコード命令
:
?
(2)クラスファイル上はブートストラップメソッドというメソッドに
紐付けられている
Bootstarpメソッド
バイトコード命令return命令
(1)クラスロード時には未定
13年9月20日金曜日
3
invokedynamicのイメージ(3)
バイトコード命令バイトコード命令Invokedynamic命令バイトコード命令
:呼び出し先決定メソッド
バイトコード命令return命令
BootStrapメソッドを指すMH
(2)BootstrapメソッドはCallSiteオブジェクトを返す
CallSite呼び出し先メソッドを参照するMH
(1)BootStrapメソッドを示すMH(MethodHandle)で表現されている
13年9月20日金曜日
3
invokedynamicのイメージ(5)
バイトコード命令バイトコード命令Invokedynamic命令バイトコード命令
:
CallSite
(1)invokedyamic命令にCallSiteが紐付けられる
この結び付きはJVMの実行を通じて以後不可逆、不変なので、以下のようにinvokedynamic
がCallSiteに置き変わると考えても良いかも知れない。 (※CallSiteオブジェクトは複数のinvokedynamic命令でシェアされ得る点でこのイメージは正確ではない。)
バイトコード命令バイトコード命令CallSite
バイトコード命令呼び出し先メソッドを参照するMH
呼び出し先メソッドを参照するMH
13年9月20日金曜日
3
CallSite 呼び出し先メソッドを参照するMH
invokedynamicの最終形
バイトコード命令バイトコード命令
メソッドバイトコード命令return命令
バイトコード命令
MHによるメソッド参照
:
13年9月20日金曜日
3
CallSite 呼び出し先メソッドを参照するMH
(Mutable|Volatile)CallSite
バイトコード命令バイトコード命令
バイトコード命令:
(1)
メソッド1
メソッド2
×
Groovyで言うところのmetaClassの変更のタイミングで実際のメソッドの差し替えを行なうことができるCallSiteもある。(これがキモ)
結局、「ポインタを解した呼び出し先アドレスの間接参照」をオブジェクト指向的に、型安全に行なっている。
13年9月20日金曜日
3
Indyって結局何?メソッド呼び出し先を間接参照を使って書き換えるしくみ他言語メソッドの呼び出しが想定ユースケースだが技術的にはそれに限らない(Java 8 Lambdaとか)他言語だから、環境を持ち回したり引数をラップ・アンラップする処理が必要になる場合があるメソッド呼び出しに伴なう前後処理(MHに対する高階操作:後述)をJVM管理下で構成・実行するしくみがあることがメリット➡最適化(インライン展開)期待➡そういう前後処理が不要な場合、速度メリットがあるかは??※ 「MH呼び出しは速い」は都市伝説
1913年9月20日金曜日
3
MHに対する高階操作
2013年9月20日金曜日
321
Brainf*ck
13年9月20日金曜日
3
Brainf*ckをindyで実装してみた :構成図
22
Brainf*ckソース>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+.[-]++++++++++.
compile.groovy
https://gist.github.com/uehaj/6614136https://gist.github.com/uehaj/6614447
Brainf*ckコンパイラ
生成コード(Bytecode DSL/indyを使用)
groovy
groovy“hello world”JVM
JVM(Java7)
a.groovy
13年9月20日金曜日
3
Brainf*ckとindy静的言語だからIndyの意味ない(MutableCallSite出番なし)invokedynamicの引数文字列から一連のMHを連接させたものをBootStrapメソッドで生成してみる
23
invokedynamic 'dummy', '()V', [H_INVOKESTATIC, 'Brainfuck', 'bootstrap', [CallSite, Lookup, String, MethodType, String]], '>++++++++'
13年9月20日金曜日
3
MHを連接MethodHandles#filterReturnValue(MH target, MH filter)「filter(target())」を表現するMHを返す。targetの戻り値の型がvoid、filterの引数が無しであれば、単にtarget, filterの順にMHを呼び出すfilterReternValueの結果をfilterReturnValueに与えることで任意個数のMHを逐次実行できる
2413年9月20日金曜日
3
CallSite 呼び出し先メソッドを参照するMH
MHを連接
バイトコード命令バイトコード命令
メソッド(+)バイトコード命令return命令
バイトコード命令:
filterReturlValueの結果得られる、2つのMHを呼ぶMH
filterReturlValueの結果得られる、2つのMHを呼ぶMH
メソッド(+)バイトコード命令return命令
メソッド(>)バイトコード命令return命令
13年9月20日金曜日
3
生成コード
26
static void main(String[] args) throws Exception { // Brainfuckからコンバートされたコード invokedynamic 'dummy', '()V', ... '>+++++++++' _GOTO tmp1 lab1: invokedynamic 'dummy', '()V', ... '<++++++++>-‐' tmp1: getstatic '.data','[B' getstatic '.dp','I' baload ifne lab1 invokedynamic 'dummy', '()V', ... '<.>+++++++' _GOTO tmp2 lab2: invokedynamic 'dummy', '()V', .... '<++++>-‐' tmp2: getstatic '.data','[B' getstatic '.dp','I' baload ifne lab2 invokedynamic 'dummy', '()V', .... '<+.+++++++..+++.' _GOTO tmp3 lab3: :
>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.
13年9月20日金曜日
3
実行
27
% cat hello.bf >+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+.[-]++++++++++.
% groovy compile.groovy hello.bf > a.groovy% groovy -Dgroovy.target.bytecode=1.7 a.groovyHello World!
13年9月20日金曜日
3
まとめIndyは面白いG*Magazine Vol7乞う期待!
2813年9月20日金曜日