Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Indy(Invokedynamic) and Bytecode DSL and Brainf*ck

2,599 views

Published on

implement Brainf*ck compiler using Indy with BytecodeDSL.

Published in: Technology
  • Be the first to comment

Indy(Invokedynamic) and Bytecode DSL and Brainf*ck

  1. 1. 3 Bytecode DSL & Indy & Brainf*ck G*Workshop Z 2013/09/20 上原潤二(NTTソフトウェア株式会社) 13年9月20日金曜日
  2. 2. JGGUG G*Workshop Z Copyright(C) NTT Software. 自己紹介 上原潤二(@uehaj) NTTソフトウェア(株)Grails推進室 JGGUG(日本Grails/Groovyユーザグループ)運営委員 書籍: プログラミングGROOVY(技術評論社) Grails徹底入門(翔泳社) ブログ「Grな日々」 GroovyServ, LispBuilder, GVM(JVM written in Groovy)開発者 2 13年9月20日金曜日
  3. 3. JGGUG G*Workshop Z Copyright(C) NTT Software. 今日の内容 Indyの基礎 Bytecode DSL Brainf*ckを実装してみた G*Magazine Vol.7の宣伝 3 13年9月20日金曜日
  4. 4. JGGUG G*Workshop Z Copyright(C) NTT Software. テーマ:Indyで遊びたい Indy: Java VM上での動的言語の実行を効 率化することを目的とした一連の機能拡張 (JSR 292) 気軽でない ASM面倒くさい ByteCode DSLを使おう! 4 13年9月20日金曜日
  5. 5. 35 Bytecode DSL 13年9月20日金曜日
  6. 6. JGGUG G*Workshop Z Copyright(C) NTT Software. ByteCode DSL Groovyの内部DSLで実現されたJava バイトコードのアセンブラ ASMのラッパー Indy対応! (重要) 6 @groovyx.ast.bytecode.Bytecode int  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日金曜日
  7. 7. 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.groovy 102334155 13年9月20日金曜日
  8. 8. 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.Bytecode import  java.lang.invoke.* import  java.lang.invoke.MethodHandles.Lookup import  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日金曜日
  9. 9. 3 実行 9 $ groovy -Dgroovy.target.bytecode=1.7 HelloIndy.groovy Hello Indy 13年9月20日金曜日
  10. 10. 310 Indy!! 13年9月20日金曜日
  11. 11. JGGUG G*Workshop Z Copyright(C) NTT Software. Indy Indyの動作は知ってますよね?? 11 13年9月20日金曜日
  12. 12. 3 従来のinvoke系命令のイメージ バイトコード命令 バイトコード命令 Invokestatic/virtual/interface命令 メソッド バイトコード命令 return命令 バイトコード命令 (1)Java VMによって解決さ れて呼び出される : 13年9月20日金曜日
  13. 13. 3 invokedynamic命令のイメージ バイトコード命令 バイトコード命令 Invokedynamic命令 メソッド バイトコード命令 return命令 バイトコード命令 (1)Java以外の言語処理系 ランタイムによって解決 される : 13年9月20日金曜日
  14. 14. 3 invokedynamicのイメージ(2) バイトコード命令 バイトコード命令 Invokedynamic命令 バイトコード命令 : ? (2)クラスファイル上はブートスト ラップメソッドというメソッドに 紐付けられている Bootstarpメソッド バイトコード命令 return命令 (1)クラスロード時には未定 13年9月20日金曜日
  15. 15. 3 invokedynamicのイメージ(3) バイトコード命令 バイトコード命令 Invokedynamic命令 バイトコード命令 : 呼び出し先決定メソッド バイトコード命令 return命令 BootStrapメソッドを指すMH (2)BootstrapメソッドはCallSiteオブジ ェクトを返す CallSite 呼び出し先メソッ ドを参照するMH (1)BootStrapメソッドを示す MH(MethodHandle)で表現されている 13年9月20日金曜日
  16. 16. 3 invokedynamicのイメージ(5) バイトコード命令 バイトコード命令 Invokedynamic命令 バイトコード命令 : CallSite (1)invokedyamic命令にCallSiteが紐付 けられる この結び付きはJVMの実行を通じて以後不可逆、不変なので、以下のようにinvokedynamic がCallSiteに置き変わると考えても良いかも知れない。 (※CallSiteオブジェクトは複数の invokedynamic命令でシェアされ得る点でこのイメージは正確ではない。) バイトコード命令 バイトコード命令 CallSite バイトコード命令 呼び出し先メソッドを参照するMH 呼び出し先メソッ ドを参照するMH 13年9月20日金曜日
  17. 17. 3 CallSite 呼び出し先メソッドを参照するMH invokedynamicの最終形 バイトコード命令 バイトコード命令 メソッド バイトコード命令 return命令 バイトコード命令 MHによるメソッド参照 : 13年9月20日金曜日
  18. 18. 3 CallSite 呼び出し先メソッドを参照するMH (Mutable¦Volatile)CallSite バイトコード命令 バイトコード命令 バイトコード命令 : (1) メソッド1 メソッド2 × Groovyで言うところのmetaClassの変更のタイミングで実際のメソッドの差し替え を行なうことができるCallSiteもある。(これがキモ) 結局、「ポインタを解した呼び出し先アドレスの間接参照」を オブジェクト指向的に、型安全に行なっている。 13年9月20日金曜日
  19. 19. 3 Indyって結局何? メソッド呼び出し先を間接参照を使って書き換える しくみ 他言語メソッドの呼び出しが想定ユースケースだが技術 的にはそれに限らない(Java 8 Lambdaとか) 他言語だから、環境を持ち回したり引数をラップ・アン ラップする処理が必要になる場合がある メソッド呼び出しに伴なう前後処理(MHに対する高階 操作:後述)をJVM管理下で構成・実行するしくみがあ ることがメリット ➡最適化(インライン展開)期待 ➡そういう前後処理が不要な場合、速度メリットがあるかは?? ※ 「MH呼び出しは速い」は都市伝説 19 13年9月20日金曜日
  20. 20. 3 MHに対する高階操作 20 13年9月20日金曜日
  21. 21. 321 Brainf*ck 13年9月20日金曜日
  22. 22. 3 Brainf*ckをindyで実装してみた : 構成図 22 Brainf*ckソース >+++++++++[<++++ ++++>-]<.>+++++++ [<++++>-]<+.++++++ +..+++.[-]>++++++++ [<++++>-]<.>++++++ +++++[<+++++>-]<.> ++++++++[<+++>-]<. +++.------.--------.[-]>+ +++++++[<++++>-]< +.[-]++++++++++. compile. groovy https://gist.github.com/uehaj/6614136 https://gist.github.com/uehaj/6614447 Brainf*ckコンパイラ 生成コード(Bytecode DSL/indyを使用) groovy groovy “hello world” JVM JVM(Java7) a.groovy 13年9月20日金曜日
  23. 23. 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日金曜日
  24. 24. 3 MHを連接 MethodHandles#filterReturnValu e(MH target, MH filter) 「filter(target())」を表現するMHを返す。 targetの戻り値の型がvoid、 filterの引数が無しであれば、単にtarget, filterの順にMHを呼び出す filterReternValueの結果を filterReturnValueに与えることで任意個数 のMHを逐次実行できる 24 13年9月20日金曜日
  25. 25. 3 CallSite 呼び出し先メソッドを参照するMH MHを連接 バイトコード命令 バイトコード命令 メソッド(+) バイトコード命令 return命令 バイトコード命令 : filterReturlValueの結果得られ る、2つのMHを呼ぶMH filterReturlValueの結果得られ る、2つのMHを呼ぶMH メソッド(+) バイトコード命令 return命令 メソッド(>) バイトコード命令 return命令 13年9月20日金曜日
  26. 26. 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日金曜日
  27. 27. 3 実行 27 % cat hello.bf >+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++. [-]>++++++++[<++++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+ ++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+.[-]+++++ +++++. % groovy compile.groovy hello.bf > a.groovy % groovy -Dgroovy.target.bytecode=1.7 a.groovy Hello World! 13年9月20日金曜日
  28. 28. 3 まとめ Indyは面白い G*Magazine Vol7乞う期待! 28 13年9月20日金曜日

×