SlideShare une entreprise Scribd logo
1  sur  39
Télécharger pour lire hors ligne
Java 7 invokedynamic の概要

@miyakawa_taku
2012-02-22
JJUG Night Seminar
1



発表者
• 名前: 宮川 拓
• 職業: SI 屋で Hadooper
• オレオレ JVM 言語 Kink を開発中
 – Its’ fun!
2



invokedynamic とは?
• Java 6 までの JVM
  = Java のための仮想マシン
• Java 7 の JVM
  = Java + Java 以外の言語のための仮想マシン
• invokedynamic は Java 以外の言語のために
  追加された新しいメソッド呼び出し命令
3



論点
• Java 6 までの呼び出し命令
  – JVM 命令は Java のために作られていた
• Java 以外の言語
  – 既存の命令セットでは Java 以外の言語処理系が
    効率的に実装できない
• invokedynamic
  – 新しい命令で Java 以外の言語も効率的になる
4



論点
• Java 6 までの呼び出し命令
• Java 以外の言語
• invokedynamic
5



Java 6 までの呼び出し命令
• 4 種類
• Java のメソッド呼び出しはこれで全部 OK

    invokestatic static メソッドを呼び出す
  invokespecial コンストラクタ、 private メソッド等を呼び出す
   invokevirtual クラスに属するメソッドを呼び出す (非 private)
invokeinterface インタフェースに属するメソッドを呼び出す
6



invokestatic
• static メソッドの呼び出し → invokestatic

             StringUtils.rjust("VOXXX", 10, '.');
                                    javac
   ldc "VOXXX"      // "VOXXX” をスタックに積む
   bipush 10       // 10 をスタックに積む
   bipush 46       // '.' = 46 をスタックに積む
   invokestatic StringUtils#rjust(String,int,char):String
7



invokestatic
• invokestatic 命令は与えられたメソッドをその
  まま呼び出す

                         class StringUtils
                 bang!   static String rjust(String,int,char)
  invokestatic              iload_1
                            aload_0
                            ...
8



invokespecial
• private なインスタンスメソッド、コンストラクタ、
  super メソッドの呼び出し → invokespecial

              this.checkIndex(index);
                            javac
    aload_0 // this (レシーバ) をスタックに積む
    iload_1 // index をスタックに積む
    invokespecial MyList#checkIndex(int):void
9



invokespecial
• invokespecial 命令は与えられたメソッドをその
  まま呼び出す (invokestatic とほぼ同じ)

                          class MyList
                  bang!   private void checkIndex(int)
  invokespecial            iconst_0
                           iload_1
                           ...
10



invokevirtual
• とある GUI ツールキットのクラス階層
                   Widget
                   Rect getRect()

                    Button
                    void push()

    CheckBox                      OKButton
    void push()                   void push()
    boolean isPushed()
11



invokevirtual
• レシーバの型がクラスであるインスタンスメ
  ソッド呼び出し (除 private) → invokevirtual

                Button button;
                button.push();
                           javac
        aload_0
        invokevirtual Button#push():void
12



invokevirtual
• invokevirtual 命令はレシーバのクラスが持つ
  メソッドのルックアップテーブル (vtable) を見
  て呼び出すメソッドを決める
                Button    CheckBox   OKButton
                getRect   getRect    getRect
invokevirtual   push      push       push
 Button クラスの              isPushed
 2 番目のメソッド
 を呼ぶ!
                 メソッドへのポインタが
                   格納されている
13



invokeinterface
• 再び GUI ツールキットのクラス階層
    intf Movable       intf Resizable
    void move(Point)   void resize(Size)



    class Icon         class Frame
    void move(Point)   void resize(Size)
                       void move(Point)
14



invokeinterface
• レシーバの型がインタフェースであるインスタ
  ンスメソッド呼び出し → invokeinterface
          Movable window;
          Point point;
          window.move(new Point(0, 0));
                           javac
     aload_0
     aload_1
     invokeinterface Movable#move(Point):void
15



invokeinterface
• invokeinterface 命令はレシーバのクラスがイ
  ンタフェース毎に持つルックアップテーブル
  (itable) を見て呼び出すメソッドを決める
                   class Icon       class Frame

                   Movable      Movable    Resizable
invokeinterface    move         move       resize
Movable インタフェースの
1 番目のメソッドを呼ぶ!       メソッドへのポインタが
                      格納されている
16



Java 6 までの呼び出し命令 (rep)
• 4 つの呼び出し命令で Java のメソッド呼び出
  しをカバー
• Java に特化した仕組み
 – メソッドが再定義されることはない
 – 単一継承
 – 名前と型の組み合わせによるメソッドの特定
 – レシーバのクラスによる単一ディスパッチ
17



論点
• Java 6 までの呼び出し命令
• Java 以外の言語
• invokedynamic
18



古い革袋と新しい酒

                Scheme
              JS       Python
            Groovy Ruby
                        Scala
   Java           Java
   JVM            JVM

  むかし             最近
19



古い革袋と新しい酒
• JVM は Java のために作られたので、それ以外
  の言語を動かすのには工夫が必要
• 例: Ruby ではメソッドが再定義できるので、既
  存の呼び出し命令で直接呼び出せない
• 他にも
 – method-missing
 – 多重継承
 – mix-in
20

Java 6 までは呼び出すために
処理系が間に挟まる必要があった
    array.join
バイトコード
  生成
              invoke          invoke
    CAFE 0000 virtual         virtual def join
    3939 5151          処理系             ...
    ......                             ...
                      検索
                 size   Func@42
                 join   Func@123
21



本当はこうしたい!
    array.join
バイトコード
  生成
    CAFE 0000            bang!         def join
    3939 5151                           ...
    ......                              ...


                 余計な処理がなく、JIT コンパイラに
                  よる最適化が掛けやすくなる
22



新しい呼び出し命令が欲しい
• Java 以外の言語のメソッドを JVM の命令で直
  接呼び出したい
• しかも
 – 実行される処理を独自のルールで検索したい
 – メソッドを実行時に繋ぎ変えたい
 – JIT でカリカリに最適化してほしい
23



論点
• Java 6 までの呼び出し命令
• Java 以外の言語
• invokedynamic
24



invokedynamic
• invokedynamic による呼び出しが実現すること
 – 呼び出す処理の選択をプログラムによって制御で
   きる
 – 呼び出す処理を実行時に繋ぎ変えられる
 – カリカリに最適化して実行する
25



invokedynamic の基本コンセプト
• やりたいこと
 – 命令ごとに関数ポインタを登録、これが指し示す
   先の処理を呼び出す
 – 別の関数ポインタを登録しなおすことも可能
   invokedynamic

      関数           bang!   対象の
     ポインタ                  処理

  あとから
 貼り替えられる
26



invokedynamic の道具立て
• 仔細に道具立てを見ると下図の通り

        初回実行時に           invokedynamic
        呼び出し
bootstrap   <<create>>
                            CallSite
 メソッド


 任意の         MH の           Method     bang!   対象の
 処理          再登録            Handle             処理
27



MethodHandle
• まずは MethodHandle

         初回実行時に           invokedynamic
         呼び出し
 bootstrap   <<create>>
                             CallSite
  メソッド


  任意の         MH の           Method     bang!   対象の
  処理          再登録            Handle             処理
28



MethodHandle
• MethodHandle は型付き関数ポインタ
• 決まった型・数の引数をスタックから取り、結
  果をスタックに置く処理を指し示す
プリミティブな MethodHandle の作成
Lookup#findVirtual     • インスタンスメソッドを呼び出す
                         MH
Lookup#findConstructor • インスタンスを生成する MH
Lookup#findGetter      • フィールドの値を返す MH
MethodHandles#constant • 定数値を返す MH
29



MethodHandle
• MethodHandle は合成したり、引数の順序を
  入れ替えたり、部分適用したりして新しい
  MethodHandle を生成できる
複合的な MethodHandle の作成
MethodHandles  • (if test then target else fallback) を行う
#guardWithTest   MH
MethodHandles        • 本処理の戻り値に後処理を加える MH
#filterReturnValue
MethodHandle         • 先頭の引数の値を固定した MH
#bindTo
30



CallSite
• ついで CallSite

         初回実行時に           invokedynamic
         呼び出し
 bootstrap   <<create>>
                             CallSite
  メソッド


  任意の         MH の           Method     bang!   対象の
  処理          再登録            Handle             処理
31



CallSite
• 1 つの invokedynamic 命令に紐付いて「呼び
  出し元」を表す
• MethodHandle の参照を保持する
CallSite の具象クラス
ConstantCallSite •   MH が書き換えられない
                 •   private final MethodHandle mh
MutableCallSite  •   MH が書き換えられる
                 •   private MethodHandle mh
VolatileCallSite   • MH が書き換えられる
                   • private volatile MethodHandle mh
32



bootstrap メソッド
• 最後に bootstrap メソッド

        初回実行時に            invokedynamic
        呼び出し
 bootstrap   <<create>>
                             CallSite
  メソッド


  任意の         MH の           Method     bang!   対象の
  処理          再登録            Handle             処理
33



bootstrap メソッド
• 各 invokedynamic 命令は bootstrap という
  static メソッドへの参照を持っている
• invokedynamic 命令が最初に実行される時に
  bootstrap メソッドが呼ばれて
  – 命令に CallSite オブジェクトを紐付ける
  – MethodHandle の初期値を CallSite に紐付ける
34



bootstrap メソッド
• 例: 戻り値の型が int の場合、強制的に値を
  42 にする
 static CallSite bsm(Lookup lu, String name, MethodType mt)
 throws Exception {
   MethodType vmt = mt.dropParameterTypes(0, 1);
   MethodHandle vmh = lu.findVirtual(mt.parameterType(0), name, vmt);
   if (vmt.returnType() == int.class)
      return new ConstantCallSite(filterReturnValue(vmh,
        dropArguments(constant(int.class, 42), 0, int.class)));
   else
      return new ConstantCallSite(vmh);
 }
35



bootstrap メソッド
• 例: 「メソッド名」を文字列として戻す
  – indy での「メソッド名」は bootstrap に渡す引数に
    過ぎない

 static CallSite bsm(Lookup lu, String name, MethodType mt) {
   return new ConstantCallSite(dropArguments(
      constant(String.class, name), 0, mt.parameterType(0)));
 }



              MethodType が引数なし
             戻り値 String でないとエラー
36



invokedynamic (rep)
• bootstrap メソッドにより、命令に紐付く処理を
  言語処理系独自のやり方で選択できる
• CallSite に新しい MethodHandle を登録するこ
  とにより、命令に紐付く処理を実行時に変更
  できる
• これらの仕組みを JVM のレベルでサポートす
  るため、賢く使うと効率的な言語処理系が実
  装できる
37



蛇足
• MethodHandle は処理をオブジェクトとして
  様々に操作できるから面白い!
• たとえば MethodHandle ベースの AOP フレー
  ムワークが作れるかも
38



参考
• Da Vinci Machine Project (mlvm)
   – http://openjdk.java.net/projects/mlvm/
• JSR 292 Cookbook
   – http://cr.openjdk.java.net/~jrose/pres/200906-Cookbook.htm
• John Rose’ weblog at Oracle: dynamic invocation in the VM
   – https://blogs.oracle.com/jrose/entry/dynamic_invocation_in_the_vm
• Optimizing invokedynamic
   – http://dl.acm.org/citation.cfm?id=1852763
• HotSpot Internals for OpenJDK: CallingSequences
   – https://wikis.oracle.com/display/HotSpotInternals/CallingSequences

Contenu connexe

Tendances

Perl 非同期プログラミング
Perl 非同期プログラミングPerl 非同期プログラミング
Perl 非同期プログラミング
lestrrat
 
JVMの中身を可視化してみた
JVMの中身を可視化してみたJVMの中身を可視化してみた
JVMの中身を可視化してみた
Kengo Toda
 
rpscala35-scala2.9.0
rpscala35-scala2.9.0rpscala35-scala2.9.0
rpscala35-scala2.9.0
Kenji Yoshida
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
yoshiaki iwanaga
 
Jvm reading-synchronization
Jvm reading-synchronizationJvm reading-synchronization
Jvm reading-synchronization
Minoru Nakamura
 
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解するそうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
shigeki_ohtsu
 
InvokeDynamic at #shikadriven 2012
InvokeDynamic at #shikadriven 2012InvokeDynamic at #shikadriven 2012
InvokeDynamic at #shikadriven 2012
Go Tanaka
 
DoActionからJava VMバイトコードに変換する話
DoActionからJava VMバイトコードに変換する話DoActionからJava VMバイトコードに変換する話
DoActionからJava VMバイトコードに変換する話
emorins
 

Tendances (20)

Perl 非同期プログラミング
Perl 非同期プログラミングPerl 非同期プログラミング
Perl 非同期プログラミング
 
JVMの中身を可視化してみた
JVMの中身を可視化してみたJVMの中身を可視化してみた
JVMの中身を可視化してみた
 
Elixir入門「第6回:Elixirはtry…catchを書かない~障害対応のパラダイムシフト~」
Elixir入門「第6回:Elixirはtry…catchを書かない~障害対応のパラダイムシフト~」Elixir入門「第6回:Elixirはtry…catchを書かない~障害対応のパラダイムシフト~」
Elixir入門「第6回:Elixirはtry…catchを書かない~障害対応のパラダイムシフト~」
 
rpscala35-scala2.9.0
rpscala35-scala2.9.0rpscala35-scala2.9.0
rpscala35-scala2.9.0
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
 
続・ゲンバのSwift
続・ゲンバのSwift続・ゲンバのSwift
続・ゲンバのSwift
 
Jvm reading-synchronization
Jvm reading-synchronizationJvm reading-synchronization
Jvm reading-synchronization
 
Frege, What a Non-strict Language
Frege, What a Non-strict LanguageFrege, What a Non-strict Language
Frege, What a Non-strict Language
 
コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道
 
JVM-Reading-ParalleGC
JVM-Reading-ParalleGCJVM-Reading-ParalleGC
JVM-Reading-ParalleGC
 
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解するそうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
 
ScalaMatsuri 2016
ScalaMatsuri 2016ScalaMatsuri 2016
ScalaMatsuri 2016
 
InvokeDynamic at #shikadriven 2012
InvokeDynamic at #shikadriven 2012InvokeDynamic at #shikadriven 2012
InvokeDynamic at #shikadriven 2012
 
Rubyの黒魔術
Rubyの黒魔術Rubyの黒魔術
Rubyの黒魔術
 
Phantom Type in Scala
Phantom Type in ScalaPhantom Type in Scala
Phantom Type in Scala
 
DoActionからJava VMバイトコードに変換する話
DoActionからJava VMバイトコードに変換する話DoActionからJava VMバイトコードに変換する話
DoActionからJava VMバイトコードに変換する話
 
なぜリアクティブは重要か #ScalaMatsuri
なぜリアクティブは重要か #ScalaMatsuriなぜリアクティブは重要か #ScalaMatsuri
なぜリアクティブは重要か #ScalaMatsuri
 
Swift2.x を Scala からみる
Swift2.x を Scala からみるSwift2.x を Scala からみる
Swift2.x を Scala からみる
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
 
SmalltalkBoltでUFFI入門
SmalltalkBoltでUFFI入門SmalltalkBoltでUFFI入門
SmalltalkBoltでUFFI入門
 

Similaire à Java 7 invokedynamic の概要 (7)

Kink: invokedynamic on a prototype-based language
Kink: invokedynamic on a prototype-based languageKink: invokedynamic on a prototype-based language
Kink: invokedynamic on a prototype-based language
 
20120327 phpstudy58-phake
20120327 phpstudy58-phake20120327 phpstudy58-phake
20120327 phpstudy58-phake
 
Adaptive optimization of JIT compiler
Adaptive optimization of JIT compilerAdaptive optimization of JIT compiler
Adaptive optimization of JIT compiler
 
Webサーバ勉強会03
Webサーバ勉強会03Webサーバ勉強会03
Webサーバ勉強会03
 
Java SE 7 InvokeDynamic in JRuby
Java SE 7 InvokeDynamic in JRubyJava SE 7 InvokeDynamic in JRuby
Java SE 7 InvokeDynamic in JRuby
 
Spring3.1概要x di
Spring3.1概要x diSpring3.1概要x di
Spring3.1概要x di
 
ソフトウェア工学2023 11 テスト
ソフトウェア工学2023 11 テストソフトウェア工学2023 11 テスト
ソフトウェア工学2023 11 テスト
 

Plus de Taku Miyakawa

Quasar: Actor Model and Light Weight Threads on Java
Quasar: Actor Model and Light Weight Threads on JavaQuasar: Actor Model and Light Weight Threads on Java
Quasar: Actor Model and Light Weight Threads on Java
Taku Miyakawa
 
Summary of "Hacking", 0x351-0x354
Summary of "Hacking", 0x351-0x354Summary of "Hacking", 0x351-0x354
Summary of "Hacking", 0x351-0x354
Taku Miyakawa
 
Kink: プロトタイプベースの俺々 JVM 言語
Kink: プロトタイプベースの俺々 JVM 言語Kink: プロトタイプベースの俺々 JVM 言語
Kink: プロトタイプベースの俺々 JVM 言語
Taku Miyakawa
 

Plus de Taku Miyakawa (17)

Java SE 9の紹介: モジュール・システムを中心に
Java SE 9の紹介: モジュール・システムを中心にJava SE 9の紹介: モジュール・システムを中心に
Java SE 9の紹介: モジュール・システムを中心に
 
Graph Algorithms Part 1
Graph Algorithms Part 1Graph Algorithms Part 1
Graph Algorithms Part 1
 
Matrix Multiplication in Strassen Algorithm
Matrix Multiplication in Strassen AlgorithmMatrix Multiplication in Strassen Algorithm
Matrix Multiplication in Strassen Algorithm
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
 
擬似乱数生成器の評価
擬似乱数生成器の評価擬似乱数生成器の評価
擬似乱数生成器の評価
 
コルーチンの実装について
コルーチンの実装についてコルーチンの実装について
コルーチンの実装について
 
言語設計者が意味論を書くときに考えていたこと
言語設計者が意味論を書くときに考えていたこと言語設計者が意味論を書くときに考えていたこと
言語設計者が意味論を書くときに考えていたこと
 
金勘定のためのBigDecimalそしてMoney and Currency API
金勘定のためのBigDecimalそしてMoney and Currency API金勘定のためのBigDecimalそしてMoney and Currency API
金勘定のためのBigDecimalそしてMoney and Currency API
 
Quasar: Actor Model and Light Weight Threads on Java
Quasar: Actor Model and Light Weight Threads on JavaQuasar: Actor Model and Light Weight Threads on Java
Quasar: Actor Model and Light Weight Threads on Java
 
Kink の宣伝
Kink の宣伝Kink の宣伝
Kink の宣伝
 
Java Quine Golf
Java Quine GolfJava Quine Golf
Java Quine Golf
 
Summary of "Hacking", 0x351-0x354
Summary of "Hacking", 0x351-0x354Summary of "Hacking", 0x351-0x354
Summary of "Hacking", 0x351-0x354
 
Processing LTSV by Apache Pig
Processing LTSV by Apache PigProcessing LTSV by Apache Pig
Processing LTSV by Apache Pig
 
Kink: プロトタイプベースの俺々 JVM 言語
Kink: プロトタイプベースの俺々 JVM 言語Kink: プロトタイプベースの俺々 JVM 言語
Kink: プロトタイプベースの俺々 JVM 言語
 
Java オブジェクトの内部構造
Java オブジェクトの内部構造Java オブジェクトの内部構造
Java オブジェクトの内部構造
 
Hadoop jobbuilder
Hadoop jobbuilderHadoop jobbuilder
Hadoop jobbuilder
 
Kink: developing a programming language on the JVM
Kink: developing a programming language on the JVMKink: developing a programming language on the JVM
Kink: developing a programming language on the JVM
 

Dernier

Dernier (10)

Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native Integrations
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
 

Java 7 invokedynamic の概要

  • 1. Java 7 invokedynamic の概要 @miyakawa_taku 2012-02-22 JJUG Night Seminar
  • 2. 1 発表者 • 名前: 宮川 拓 • 職業: SI 屋で Hadooper • オレオレ JVM 言語 Kink を開発中 – Its’ fun!
  • 3. 2 invokedynamic とは? • Java 6 までの JVM = Java のための仮想マシン • Java 7 の JVM = Java + Java 以外の言語のための仮想マシン • invokedynamic は Java 以外の言語のために 追加された新しいメソッド呼び出し命令
  • 4. 3 論点 • Java 6 までの呼び出し命令 – JVM 命令は Java のために作られていた • Java 以外の言語 – 既存の命令セットでは Java 以外の言語処理系が 効率的に実装できない • invokedynamic – 新しい命令で Java 以外の言語も効率的になる
  • 5. 4 論点 • Java 6 までの呼び出し命令 • Java 以外の言語 • invokedynamic
  • 6. 5 Java 6 までの呼び出し命令 • 4 種類 • Java のメソッド呼び出しはこれで全部 OK invokestatic static メソッドを呼び出す invokespecial コンストラクタ、 private メソッド等を呼び出す invokevirtual クラスに属するメソッドを呼び出す (非 private) invokeinterface インタフェースに属するメソッドを呼び出す
  • 7. 6 invokestatic • static メソッドの呼び出し → invokestatic StringUtils.rjust("VOXXX", 10, '.'); javac ldc "VOXXX" // "VOXXX” をスタックに積む bipush 10 // 10 をスタックに積む bipush 46 // '.' = 46 をスタックに積む invokestatic StringUtils#rjust(String,int,char):String
  • 8. 7 invokestatic • invokestatic 命令は与えられたメソッドをその まま呼び出す class StringUtils bang! static String rjust(String,int,char) invokestatic iload_1 aload_0 ...
  • 9. 8 invokespecial • private なインスタンスメソッド、コンストラクタ、 super メソッドの呼び出し → invokespecial this.checkIndex(index); javac aload_0 // this (レシーバ) をスタックに積む iload_1 // index をスタックに積む invokespecial MyList#checkIndex(int):void
  • 10. 9 invokespecial • invokespecial 命令は与えられたメソッドをその まま呼び出す (invokestatic とほぼ同じ) class MyList bang! private void checkIndex(int) invokespecial iconst_0 iload_1 ...
  • 11. 10 invokevirtual • とある GUI ツールキットのクラス階層 Widget Rect getRect() Button void push() CheckBox OKButton void push() void push() boolean isPushed()
  • 12. 11 invokevirtual • レシーバの型がクラスであるインスタンスメ ソッド呼び出し (除 private) → invokevirtual Button button; button.push(); javac aload_0 invokevirtual Button#push():void
  • 13. 12 invokevirtual • invokevirtual 命令はレシーバのクラスが持つ メソッドのルックアップテーブル (vtable) を見 て呼び出すメソッドを決める Button CheckBox OKButton getRect getRect getRect invokevirtual push push push Button クラスの isPushed 2 番目のメソッド を呼ぶ! メソッドへのポインタが 格納されている
  • 14. 13 invokeinterface • 再び GUI ツールキットのクラス階層 intf Movable intf Resizable void move(Point) void resize(Size) class Icon class Frame void move(Point) void resize(Size) void move(Point)
  • 15. 14 invokeinterface • レシーバの型がインタフェースであるインスタ ンスメソッド呼び出し → invokeinterface Movable window; Point point; window.move(new Point(0, 0)); javac aload_0 aload_1 invokeinterface Movable#move(Point):void
  • 16. 15 invokeinterface • invokeinterface 命令はレシーバのクラスがイ ンタフェース毎に持つルックアップテーブル (itable) を見て呼び出すメソッドを決める class Icon class Frame Movable Movable Resizable invokeinterface move move resize Movable インタフェースの 1 番目のメソッドを呼ぶ! メソッドへのポインタが 格納されている
  • 17. 16 Java 6 までの呼び出し命令 (rep) • 4 つの呼び出し命令で Java のメソッド呼び出 しをカバー • Java に特化した仕組み – メソッドが再定義されることはない – 単一継承 – 名前と型の組み合わせによるメソッドの特定 – レシーバのクラスによる単一ディスパッチ
  • 18. 17 論点 • Java 6 までの呼び出し命令 • Java 以外の言語 • invokedynamic
  • 19. 18 古い革袋と新しい酒 Scheme JS Python Groovy Ruby Scala Java Java JVM JVM むかし 最近
  • 20. 19 古い革袋と新しい酒 • JVM は Java のために作られたので、それ以外 の言語を動かすのには工夫が必要 • 例: Ruby ではメソッドが再定義できるので、既 存の呼び出し命令で直接呼び出せない • 他にも – method-missing – 多重継承 – mix-in
  • 21. 20 Java 6 までは呼び出すために 処理系が間に挟まる必要があった array.join バイトコード 生成 invoke invoke CAFE 0000 virtual virtual def join 3939 5151 処理系 ... ...... ... 検索 size Func@42 join Func@123
  • 22. 21 本当はこうしたい! array.join バイトコード 生成 CAFE 0000 bang! def join 3939 5151 ... ...... ... 余計な処理がなく、JIT コンパイラに よる最適化が掛けやすくなる
  • 23. 22 新しい呼び出し命令が欲しい • Java 以外の言語のメソッドを JVM の命令で直 接呼び出したい • しかも – 実行される処理を独自のルールで検索したい – メソッドを実行時に繋ぎ変えたい – JIT でカリカリに最適化してほしい
  • 24. 23 論点 • Java 6 までの呼び出し命令 • Java 以外の言語 • invokedynamic
  • 25. 24 invokedynamic • invokedynamic による呼び出しが実現すること – 呼び出す処理の選択をプログラムによって制御で きる – 呼び出す処理を実行時に繋ぎ変えられる – カリカリに最適化して実行する
  • 26. 25 invokedynamic の基本コンセプト • やりたいこと – 命令ごとに関数ポインタを登録、これが指し示す 先の処理を呼び出す – 別の関数ポインタを登録しなおすことも可能 invokedynamic 関数 bang! 対象の ポインタ 処理 あとから 貼り替えられる
  • 27. 26 invokedynamic の道具立て • 仔細に道具立てを見ると下図の通り 初回実行時に invokedynamic 呼び出し bootstrap <<create>> CallSite メソッド 任意の MH の Method bang! 対象の 処理 再登録 Handle 処理
  • 28. 27 MethodHandle • まずは MethodHandle 初回実行時に invokedynamic 呼び出し bootstrap <<create>> CallSite メソッド 任意の MH の Method bang! 対象の 処理 再登録 Handle 処理
  • 29. 28 MethodHandle • MethodHandle は型付き関数ポインタ • 決まった型・数の引数をスタックから取り、結 果をスタックに置く処理を指し示す プリミティブな MethodHandle の作成 Lookup#findVirtual • インスタンスメソッドを呼び出す MH Lookup#findConstructor • インスタンスを生成する MH Lookup#findGetter • フィールドの値を返す MH MethodHandles#constant • 定数値を返す MH
  • 30. 29 MethodHandle • MethodHandle は合成したり、引数の順序を 入れ替えたり、部分適用したりして新しい MethodHandle を生成できる 複合的な MethodHandle の作成 MethodHandles • (if test then target else fallback) を行う #guardWithTest MH MethodHandles • 本処理の戻り値に後処理を加える MH #filterReturnValue MethodHandle • 先頭の引数の値を固定した MH #bindTo
  • 31. 30 CallSite • ついで CallSite 初回実行時に invokedynamic 呼び出し bootstrap <<create>> CallSite メソッド 任意の MH の Method bang! 対象の 処理 再登録 Handle 処理
  • 32. 31 CallSite • 1 つの invokedynamic 命令に紐付いて「呼び 出し元」を表す • MethodHandle の参照を保持する CallSite の具象クラス ConstantCallSite • MH が書き換えられない • private final MethodHandle mh MutableCallSite • MH が書き換えられる • private MethodHandle mh VolatileCallSite • MH が書き換えられる • private volatile MethodHandle mh
  • 33. 32 bootstrap メソッド • 最後に bootstrap メソッド 初回実行時に invokedynamic 呼び出し bootstrap <<create>> CallSite メソッド 任意の MH の Method bang! 対象の 処理 再登録 Handle 処理
  • 34. 33 bootstrap メソッド • 各 invokedynamic 命令は bootstrap という static メソッドへの参照を持っている • invokedynamic 命令が最初に実行される時に bootstrap メソッドが呼ばれて – 命令に CallSite オブジェクトを紐付ける – MethodHandle の初期値を CallSite に紐付ける
  • 35. 34 bootstrap メソッド • 例: 戻り値の型が int の場合、強制的に値を 42 にする static CallSite bsm(Lookup lu, String name, MethodType mt) throws Exception { MethodType vmt = mt.dropParameterTypes(0, 1); MethodHandle vmh = lu.findVirtual(mt.parameterType(0), name, vmt); if (vmt.returnType() == int.class) return new ConstantCallSite(filterReturnValue(vmh, dropArguments(constant(int.class, 42), 0, int.class))); else return new ConstantCallSite(vmh); }
  • 36. 35 bootstrap メソッド • 例: 「メソッド名」を文字列として戻す – indy での「メソッド名」は bootstrap に渡す引数に 過ぎない static CallSite bsm(Lookup lu, String name, MethodType mt) { return new ConstantCallSite(dropArguments( constant(String.class, name), 0, mt.parameterType(0))); } MethodType が引数なし 戻り値 String でないとエラー
  • 37. 36 invokedynamic (rep) • bootstrap メソッドにより、命令に紐付く処理を 言語処理系独自のやり方で選択できる • CallSite に新しい MethodHandle を登録するこ とにより、命令に紐付く処理を実行時に変更 できる • これらの仕組みを JVM のレベルでサポートす るため、賢く使うと効率的な言語処理系が実 装できる
  • 38. 37 蛇足 • MethodHandle は処理をオブジェクトとして 様々に操作できるから面白い! • たとえば MethodHandle ベースの AOP フレー ムワークが作れるかも
  • 39. 38 参考 • Da Vinci Machine Project (mlvm) – http://openjdk.java.net/projects/mlvm/ • JSR 292 Cookbook – http://cr.openjdk.java.net/~jrose/pres/200906-Cookbook.htm • John Rose’ weblog at Oracle: dynamic invocation in the VM – https://blogs.oracle.com/jrose/entry/dynamic_invocation_in_the_vm • Optimizing invokedynamic – http://dl.acm.org/citation.cfm?id=1852763 • HotSpot Internals for OpenJDK: CallingSequences – https://wikis.oracle.com/display/HotSpotInternals/CallingSequences