Successfully reported this slideshow.

Indy(Invokedynamic) and Bytecode DSL and Brainf*ck

3

Share

Loading in …3
×
1 of 28
1 of 28

Indy(Invokedynamic) and Bytecode DSL and Brainf*ck

3

Share

Download to read offline

Description

implement Brainf*ck compiler using Indy with BytecodeDSL.

Transcript

  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日金曜日

Description

implement Brainf*ck compiler using Indy with BytecodeDSL.

Transcript

  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日金曜日

More Related Content

Related Books

Free with a 30 day trial from Scribd

See all

×