SlideShare una empresa de Scribd logo
1 de 90
Descargar para leer sin conexión
#jt12_s204



Java SE 7 InvokeDynamic
        in JRuby
      日本JRubyユーザ会 中村浩士
     @nahi nahi@ruby-lang.org
     https://github.com/nahi

http://slidesha.re/JavaOneJpInvokeDynamic
自己紹介

ネットワークセキュリティ関連のシステム開発
 C/C++ (18年)、Java (13年)、Ruby (13年)

余暇のOSS開発
 CRuby (8年) とJRuby (2年) のコミッタ
 soap4r、httpclient他の開発
Java SE 7 InvokeDynamicとは

Java SE 7に追加された新機能

変数に型のない動的型付け言語の性能向上支援

● Java仮想マシン(JVM)のバイトコードに
  invokedynamic命令を追加

● java.lang.invoke.*に関連APIを追加
JRubyとは - http://jruby.org/

最新リリース版は1.6.7
 InvokeDynamic対応は1.7から
 (来月末のJRubyConfでPreviewリリース)

JVM上で動作するRuby(動的型付け言語)

Open Source (CPL, GPL, LGPL)

開発開始から10年
本日のゴール
InvokeDynamic機能について、実例となるソース
コード、バイトコードに基づく理解を得る

JRubyにおける性能向上とコーディングパターンを
学ぶことで、JVMの新たな可能性を見る
Agenda
前半: InvokeDynamic機能解説
 ● Java言語用メソッド呼び出し
 ● 動的型付け言語のメソッド呼び出し
 ● invokedynamic命令と関連API

後半: JRubyにおけるInvokeDynamicの活用
 ● 利用パターン
 ● 性能評価
#jt12_s204




InvokeDynamic機能解説
 Java SE 7 InvokeDynamic in JRuby
JVMとは

Java言語のための仮想マシン
バイトコード命令を逐次実行

必要に応じて最適化(JITコンパイル)
 インライン化、ループ展開、ロック削除、
 デッドコード削除、エスケープ解析
JIT最適化の例: インライン化
 double addAllSqrts(int max) {
     double accum = 0;
     for (int i = 0; i < max; i++) {
         accum = addSqrt(accum, i);
     }
     return accum;
 }
 double addSqrt(double a, int b) {
     return a + Math.sqrt(b);
 }
 public static void main(String[] args) {
     for (int i = 0; i < 100000; ++i) {
         (new Target()).addAllSqrts(10);
     }
 }
JIT最適化の例: インライン化
% java -XX:+PrintCompilation 
       -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining Target

66 1   Target::addAllSqrts (27 bytes)
67 2   Target::addSqrt (8 bytes)
         @ 3    java.lang.Math::sqrt (5 bytes) (intrinsic)
         @ 15     Target::addSqrt (8 bytes) inline (hot)
           @ 3     java.lang.Math::sqrt (5 bytes) (intrinsic)
78 1 % Target::main @ 2 (28 bytes)
         @ 12     Target::<init> (5 bytes) inline (hot)
           @ 1     java.lang.Object::<init> (1 bytes) inline (hot)
         @ 17     Target::addAllSqrts (27 bytes) inline (hot)
           @ 15     Target::addSqrt (8 bytes) inline (hot)
              @ 3    java.lang.Math::sqrt (5 bytes) (intrinsic)
         @ 1    java.lang.Object::<init> (1 bytes) inline (hot)
JIT最適化の例                   double addSqrt(double a, int b) {
                                 return a + Math.sqrt(b);
% java -XX:+PrintCompilation 
                             }
       -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining Target

66 1   Target::addAllSqrts (27 bytes) addSqrtをコンパイル
67 2   Target::addSqrt (8 bytes)
         @ 3    java.lang.Math::sqrt (5 bytes) (intrinsic)
         @ 15     Target::addSqrt (8 bytes) inline (hot)
           @ 3     java.lang.Math::sqrt (5 bytes) (intrinsic)
78 1 % Target::main @ 2 (28 bytes)
         @ 12     Target::<init> (5 bytes) inline (hot)
           @ 1     java.lang.Object::<init> (1 bytes) inline (hot)
         @ 17     Target::addAllSqrts (27 bytes) inline (hot)
           @ 15                   Math.sqrt呼び出しと加算を
                    Target::addSqrt (8 bytes) inline (hot)
              @ 3                 インライン化
                     java.lang.Math::sqrt (5 bytes) (intrinsic)
         @ 1    java.lang.Object::<init> (1 bytes) inline (hot)
double addAllSqrts(int max) {
                         double accum = 0;
                         for (int i = 0; i < max; i++) {
                             accum = addSqrt(accum, i); }}
                     public static void main(String[] args) {
% java -XX:+PrintCompilation 
       -XX:+UnlockDiagnosticVMOptions 0; i < 100000; ++i) Target
                         for (int i = -XX:+PrintInlining {
                             (new Target()).addAllSqrts(10); }}
66 1   Target::addAllSqrts (27 bytes)
67 2   Target::addSqrt (8 bytes)
         @mainをコンパイル
           3                      forの中にあるaddAllSqrtsおよび
                java.lang.Math::sqrt (5 bytes) (intrinsic)
         @ 15                     その中身を全てインライン化
                  Target::addSqrt (8 bytes) inline (hot)
           @ 3     java.lang.Math::sqrt (5 bytes) (intrinsic)
78 1 % Target::main @ 2 (28 bytes)
         @ 12     Target::<init> (5 bytes) inline (hot)
           @ 1     java.lang.Object::<init> (1 bytes) inline (hot)
         @ 17     Target::addAllSqrts (27 bytes) inline (hot)
           @ 15     Target::addSqrt (8 bytes) inline (hot)
              @ 3    java.lang.Math::sqrt (5 bytes) (intrinsic)
         @ 1    java.lang.Object::<init> (1 bytes) inline (hot)
double addAllSqrts(int max) {
                         double accum = 0;
                         for (int i = 0; i < max; i++) {
                             accum = addSqrt(accum, i); }}
 OSR: On-stack       public static void main(String[] args) {
% java -XX:+PrintCompilation 
 replacement
       -XX:+UnlockDiagnosticVMOptions 0; i < 100000; ++i) Target
                         for (int i = -XX:+PrintInlining {
                             (new Target()).addAllSqrts(10); }}
66 1   Target::addAllSqrts (27 bytes)
67 2   Target::addSqrt (8 bytes)
         @mainをコンパイル
           3                      forの中にあるaddAllSqrtsおよび
                java.lang.Math::sqrt (5 bytes) (intrinsic)
         @ 15                     その中身を全てインライン化
                  Target::addSqrt (8 bytes) inline (hot)
           @ 3     java.lang.Math::sqrt (5 bytes) (intrinsic)
78 1 % Target::main @ 2 (28 bytes)
         @ 12     Target::<init> (5 bytes) inline (hot)
           @ 1     java.lang.Object::<init> (1 bytes) inline (hot)
         @ 17     Target::addAllSqrts (27 bytes) inline (hot)
           @ 15     Target::addSqrt (8 bytes) inline (hot)
              @ 3    java.lang.Math::sqrt (5 bytes) (intrinsic)
         @ 1    java.lang.Object::<init> (1 bytes) inline (hot)
JITについてより詳しく
http://www.slideshare.
net/CharlesNutter/redev-2011-jvm-
jit-for-dummies-what-the-jvm-does-
with-your-bytecode-when-youre-not-
looking

by Charles Oliver Nutter (JRuby co-lead)
#jt12_s204


 Java言語用
メソッド呼び出し
InvokeDynamic機能解説
JVMでのメソッド呼び出し
public class Command {
  void processOptions(String[] options) {
    boolean result;
    for (String opt : options) {
      result = process(opt.concat("?!"));
    }
  }
  boolean process(String opt) { ... }
  void run() {
    String[] options = { "yes", "no", "maybe" };
    processOptions(options);
  }
}
JVMでのメソッド呼び出し
public class Command {
  void processOptions(String[] options) {
    boolean result;
    for (String opt : options) {
      result = process(opt.concat("?!"));
    }
  }
  boolean process(String opt) { ... }
  void run() {
    String[] options = { "yes", "no", "maybe" };
    processOptions(options);
  }
}
JVMでのメソッド呼び出し
                                           <Command>
void processOptions(java.lang.String[]);

      process(opt.concat("?!"));

    20:   aload_0          // thisであるCommandをスタックに入れる
    21:   aload         5
    23:   ldc           #2
    25:   invokevirtual #3




    28: invokevirtual #4
JVMでのメソッド呼び出し
                                             "yes"
void processOptions(java.lang.String[]);
                                           <Command>
      process(opt.concat("?!"));

    20:   aload_0          // thisであるCommandをスタックに入れる
    21:   aload         5 // forループ引数optから"yes"を入れる
    23:   ldc           #2
    25:   invokevirtual #3




    28: invokevirtual #4
JVMでのメソッド呼び出し
                                             "?!"
void processOptions(java.lang.String[]);
                                             "yes"
      process(opt.concat("?!"));
                                           <Command>
    20:   aload_0          // thisであるCommandをスタックに入れる
    21:   aload         5 // forループ引数optから"yes"を入れる
    23:   ldc           #2 // 定数"?!"を入れる
    25:   invokevirtual #3




    28: invokevirtual #4
JVMでのメソッド呼び出し
                                                 "?!"
void processOptions(java.lang.String[]);
                                                "yes"
      process(opt.concat("?!"));
                                              <Command>
    20:   aload_0            //   thisであるCommandをスタックに入れる
    21:   aload         5    //   forループ引数optから"yes"を入れる
    23:   ldc           #2   //   定数"?!"を入れる
    25:   invokevirtual #3   //   String.concat
                             //   スタックからループ引数と"?!"を取り出し
                             //   引数としてconcatを呼んで...

    28: invokevirtual #4
JVMでのメソッド呼び出し
                                               "yes?!"
void processOptions(java.lang.String[]);
                                              <Command>
      process(opt.concat("?!"));

    20:   aload_0            //   thisであるCommandをスタックに入れる
    21:   aload         5    //   forループ引数optから"yes"を入れる
    23:   ldc           #2   //   定数"?!"を入れる
    25:   invokevirtual #3   //   String.concat
                             //   スタックからループ引数と"?!"を取り出し
                             //   引数としてconcatを呼んで
                             //   戻り値をスタックに積む
    28: invokevirtual #4
JVMでのメソッド呼び出し
                                           "yes?!"
void processOptions(java.lang.String[]);
                                           <Command>
      process(opt.concat("?!"));

    20:   aload_0        //   thisであるCommandをスタックに入れる
    21:   aload         5//   forループ引数optから"yes"を入れる
    23:   ldc           #2
                         //   定数"?!"を入れる
    25:   invokevirtual #3
                         //   String.concat
                         //   スタックからループ引数と"?!"を取り出し
                         //   引数としてconcatを呼んで
                         //   戻り値をスタックに積む
    28: invokevirtual #4 //   process
                         //   スタックからthisと戻り値文字列を取り出し
                         //   自身であるCommandのprocessを呼ぶ
Call Site
"process"、"concat"等、呼び出す場所

                   this.process


                   String#concat
Call Siteに必要な情報
コンパイル時: 呼び出し先の参照情報
  メソッドが属するクラス:     String
  メソッド名:           "concat"
  メソッド型(引数と戻り値の型): (String;String)String

  [本資料でのメソッド型の表記方法]
    Objectとlongの2引数、Objectが戻り値
    → (Object;long)Object
Call Siteに必要な情報
コンパイル時: 呼び出し先の参照情報
  メソッドが属するクラス:     String
  メソッド名:           "concat"
  メソッド型(引数と戻り値の型): (String;String)String

実行時
  呼び出し先メソッドの実体:     String#concat
  レシーバー / 引数オブジェクト: "yes" / "?!"
  戻り値オブジェクト / 発生例外: "yes?!"
Java言語用メソッド呼び出し命令

参照先メソッドを決定する4種のバイトコード

invokestatic    staticメソッドを直接リンク
invokespecial   private/super/コンストラクタ

invokevirtual   インスタンスメソッド検索
                (virtual解決)
invokeinterface インターフェースメソッド検索
                (interface解決)
invokevirtualのメソッド呼び出し
コンパイル時:                             JComponent
  メソッドが属するクラス:                   +paint()

         JTextComponent
  メソッド名: "getText"                JTextComponent
                                 +paint()
  メソッド型: ()Void                  +getText()


実行時:
                            JTextField        JTextArea
  呼び出し先メソッドの実体:
                          +paint()          +paint()
    JTextField#getText    +getText()        +getText()
                          +getColumns()     +getRows()
                                            +getColumns()
invokevirtualのメソッド呼び出し
コンパイル時:                             JComponent
  メソッドが属するクラス:                   +paint()

         JTextComponent
  メソッド名: "getText"                JTextComponent
                                 +paint()
  メソッド型: ()Void                  +getText()


実行時:
                            JTextField        JTextArea
  呼び出し先メソッドの実体:
                          +paint()          +paint()
    JTextField#getText    +getText()        +getText()
                          +getColumns()     +getRows()
                                            +getColumns()
JVMのメソッド呼び出し命令の特徴

型安全
 存在しないメソッド、フィールドの参照がない

アクセスコントロール
 private、default、protected、final制御
 メソッドの確実なoverride

JVMによる最適化
#jt12_s204


動的型付け言語の
メソッド呼び出し
InvokeDynamic機能解説
動的型付け言語のメソッド呼び出し

   def process_options(options)
     for opt in options
       process(opt.concat("?!"))
     end
   end

   mock = Object.new
   def mock.concat(arg)
     "tested!"
   end
   options = ["yes", "no", mock]
   process_options(options)
動的型付け言語のメソッド呼び出しの特徴

呼び出し先の解決方法が異なる
 レシーバ、型、名前、引数の数などに依存
 デフォルト引数の補完

動的にメソッドが追加される
 再定義されることもある

呼び出し先が存在しない時に呼ぶメソッド
 メタプログラミング用途
例: Java SE 6用のJRuby実装

JRuby独自のCall Site
  (呼び出し先の参照情報を格納)

参照先メソッドの検索も独自実装
Java SE 6用のJRuby生成バイトコード
     process(opt.concat("?!"))
aload_0
invokevirtual main.getCallSite1;         "process"CallSite
   // "process"呼び出し用のCallSiteをスタックに入れる
aload_0
invokevirtual main.getCallSite2;

aload 9
aload_0
invokevirtual main.getString0;

invokevirtual CallSite.call;

invokevirtual CallSite.call;
Java SE 6用のJRuby生成バイトコード
     process(opt.concat("?!"))
aload_0
invokevirtual main.getCallSite1;         "concat"CallSite
   // "process"呼び出し用のCallSiteをスタックに入れる
                                         "process"CallSite
aload_0
invokevirtual main.getCallSite2;
   // "concat"呼び出し用のCallSiteをスタックに入れる
aload 9
aload_0
invokevirtual main.getString0;

invokevirtual CallSite.call;

invokevirtual CallSite.call;
Java SE 6用のJRuby生成バイトコード
     process(opt.concat("?!"))
aload_0
invokevirtual main.getCallSite1;              "yes"
   // "process"呼び出し用のCallSiteをスタックに入れる
                                         "concat"CallSite
aload_0
invokevirtual main.getCallSite2;         "process"CallSite
   // "concat"呼び出し用のCallSiteをスタックに入れる
aload 9 // forループ引数optから"yes"を入れる
aload_0
invokevirtual main.getString0;

invokevirtual CallSite.call;

invokevirtual CallSite.call;
Java SE 6用のJRuby生成バイトコード
      process(opt.concat("?!"))
aload_0
invokevirtual main.getCallSite1;                  "?!"
   // "process"呼び出し用のCallSiteをスタックに入れる
                                                 "yes"
aload_0
invokevirtual main.getCallSite2;             "concat"CallSite
   // "concat"呼び出し用のCallSiteをスタックに入れる       "process"CallSite
aload 9 // forループ引数optから"yes"を入れる
aload_0
invokevirtual main.getString0;   // 引数の"?!"

invokevirtual CallSite.call;

invokevirtual CallSite.call;
Java SE 6用のJRuby生成バイトコード
      process(opt.concat("?!"))
aload_0
invokevirtual main.getCallSite1;                  "?!"
   // "process"呼び出し用のCallSiteをスタックに入れる
                                                 "yes"
aload_0
invokevirtual main.getCallSite2;             "concat"CallSite
   // "concat"呼び出し用のCallSiteをスタックに入れる       "process"CallSite
aload 9 // forループ引数optから"yes"を入れる
aload_0
invokevirtual main.getString0;   // 引数の"?!"

invokevirtual CallSite.call;
   // スタックのCallSite情報を元に動的メソッド呼び出し(concat)
invokevirtual CallSite.call;
Java SE 6用のJRuby生成バイトコード
      process(opt.concat("?!"))
aload_0
invokevirtual main.getCallSite1;                "yes?!"
   // "process"呼び出し用のCallSiteをスタックに入れる
                                            "process"CallSite
aload_0
invokevirtual main.getCallSite2;
   // "concat"呼び出し用のCallSiteをスタックに入れる
aload 9 // forループ引数optから"yes"を入れる
aload_0
invokevirtual main.getString0;   // 引数の"?!"

invokevirtual CallSite.call;
   // スタックのCallSite情報を元に動的メソッド呼び出し(concat)
invokevirtual CallSite.call;
Java SE 6用のJRuby生成バイトコード
      process(opt.concat("?!"))
aload_0
invokevirtual main.getCallSite1;                "yes?!"
   // "process"呼び出し用のCallSiteをスタックに入れる
                                            "process"CallSite
aload_0
invokevirtual main.getCallSite2;
   // "concat"呼び出し用のCallSiteをスタックに入れる
aload 9 // forループ引数optから"yes"を入れる
aload_0
invokevirtual main.getString0;   // 引数の"?!"

invokevirtual CallSite.call;
   // スタックのCallSite情報を元に動的メソッド呼び出し(concat)
invokevirtual CallSite.call;
   // 同じく動的メソッド呼び出し(process)
Java SE 6でのJRubyメソッド呼び出し
           def target(opt)
             process(opt.concat("?!"))
           end
                                         引数の数、順序の調整
                                         デフォルト引数の補完



                                                    RubyString#
                              CallSite    Invoker
...                                                 concat
invokevirtual getCallSite2                            最終的に
aload 9                                               ここを呼ぶ
aload_0                           呼び出しメソッド検索
invokevirtual getString0          メソッドキャッシュ
invokevirtual CallSite.call       キャッシュミス判定
JRuby独自の最適化

素朴な実装のままでは遅いので...

● メソッドキャッシュ / 無効化
● JITコンパイル
  ○ バイトコード動的生成→読み込み
  ○ 脱最適化

より詳しく:
http://bit.ly/JRubyHackingGuide
#jt12_s204

invokedynamic命令と
動的型付け言語用API
(java.lang.invoke.*)
   InvokeDynamic機能解説
Java SE 6でのJRubyメソッド呼び出し


                                         引数の数、順序の調整
                                         デフォルト引数の補完


...
                                                    RubyString#
invokevirtual getCallSite2    CallSite    Invoker
                                                    concat
aload 9
aload_0                                               最終的に
invokevirtual getString0                              ここを呼ぶ
invokevirtual CallSite.call       呼び出しメソッド検索
                                  メソッドキャッシュ
                                  キャッシュミス判定
Java SE 7でのJRubyメソッド呼び出し

                              呼び出しメソッド検索
                              メソッドキャッシュ             引数の数、順序の調整
                              キャッシュミス判定             デフォルト引数の補完
                                                         MethodHandle
                               bootstrap
                                                             API


                                                             RubyString#
                               CallSite        Invoker
                                                             concat
...                                       ic
                                  edy nam                       最終的に
                           nvok
aload 9
invokedynamic getString   i                                     ここを呼ぶ
invokedynamic concat
InvokeDynamic用生成バイトコード
        process(opt.concat("?!"))

aload_2 // thisであるCommandをスタックに入れる
aload 9 // forループ引数optから"yes"を入れる
invokedynamic getString [...]
  // 引数の"?!"を取り出す

invokedynamic concat (IRubyObject;IRubyObject)IRubyObject [...]
  // "concat"メソッドを動的呼び出し

invokedynamic process (IRubyObject;IRubyObject)IRubyObject
[...]
  // "process"メソッドを動的呼び出し
生成されるバイトコードの違い
独自のCall Siteはなくinvokedynamic命令で直接呼び出す

concatの呼び出し情報は以下
   メソッド名: "concat"
   メソッド型: (IRubyObject;IRubyObject)IRubyObject

  "concat"という名前のメソッドを、2つのRubyオブジェクト
  (先頭レシーバ、引数1つ)と共に呼び出し戻り値を得る

  ...呼び出し先はどこ?
bootstrapメソッド
invokedynamic命令をよく見ると...
invokedynamic concat(IRubyObject;IRubyObject)IRubyObject [...]




invokedynamic process(IRubyObject;IRubyObject)IRubyObject [...]
bootstrapメソッド
invokedynamic命令をよく見ると...
invokedynamic concat(IRubyObject;IRubyObject)IRubyObject [
  invocationBootstrap((Lookup;String;MethodType)CallSite)
]

invokedynamic process(IRubyObject;IRubyObject)IRubyObject [
  invocationBootstrap((Lookup;String;MethodType)CallSite)
]


...bootstrapと呼ぶ初期化メソッドが登録されている
bootstrapメソッド
(Lookup;String;MethodType)CallSite
初回実行時のみ呼ばれるユーザ定義メソッド

Lookup:       メソッド検索用オブジェクト
String:       メソッド名 ("concat")
MethodType:   スタック上の引数オブジェクト型
CallSite:     検索した呼び出し先メソッドの参照
              (MethodHandle)を格納
Java SE 7からのメソッド呼び出し命令

invokestatic    staticメソッドを直接リンク
invokespecial   private/super/コンストラクタ
invokevirtual   インスタンスメソッド検索
                (virtual解決)
invokeinterface インターフェースメソッド検索
                (interface解決)
invokedynamic 動的MethodHandle検索
                (bootstrapによる解決)
Java SE 7 InvokeDynamicとは何か
コンセプト                  道具
Call Siteと呼出先の動的なリンク   invokedynamic, CallSite
リンク先検索ロジックをプログラム可能     bootstrap
メソッド参照                 MethodHandle
型の安全かつ自動的な変換           MethodType
実行時の呼び出し先メソッド分岐        MethodHandle合成


動的型付け言語で、Javaの呼び出しと同じ最適化
MethodHandle(MH)操作API
Lookup#*              クラス名と名前指定でMHを生成
MethodHandle#bindTo   第1引数のレシーバを固定
MethodHandles#*       MHを合成して新たなMHを生成
   insertArguments    引数を部分適用したMHを生成
   guardWithTest      test, then, else用の3MHを合成
                      して実行時に分岐するMH

SwitchPoint#guardWithTest     より最適化された
                              true/false分岐のMH生成
SwitchPoint.invalidateAll     sptの無効化
def fib(n)
                     if n < 2
MH操作の例                 n
                     else
                       fib(n - 2) + fib(n - 1)
                     end
"n - 1"のリンク先は?     end

最初に呼ばれたXInteger#minusにリンク
ただし毎回nの型 == XIntegerのチェックは必要

4つのMHを合成してCallSiteに設定
引数nの型がXIntegerかテストするメソッドのMH
  引数1を部分適用したXInteger#minus(1)のMH
    XInteger#minus(a)を実装したJavaメソッドのMH
  呼出先MHを検索してCallSiteに再設定するメソッドのMH
引数nの型がXIntegerかテストするメソッドのMH
  引数1を部分適用したXInteger#minus(1)のMH
    XInteger#minus(a)を実装したJavaメソッドのMH
  呼出先MHを検索してCallSiteに再設定するメソッドのMH
MethodHandle test, minus, fallback, all;
minus = lookup.findVirtual(XInteger.class, "minus",
    MethodType.methodType(XObject.class, long.class));
minus = MethodHandles.insertArguments(minus, 1, 1);


                                        1番目の引数に
                                        1Lを部分適用
引数nの型がXIntegerかテストするメソッドのMH
  引数1を部分適用したXInteger#minus(1)のMH
    XInteger#minus(a)を実装したJavaメソッドのMH
  呼出先MHを検索してCallSiteに再設定するメソッドのMH
MethodHandle test, minus, fallback, all;
minus = lookup.findVirtual(XInteger.class, "minus",
    MethodType.methodType(XObject.class, long.class));
minus = MethodHandles.insertArguments(minus, 1, 1);

fallback = lookup.findStatic(Utils.class, "fallback",
    MethodType.methodType(CallSite.class));
fallback = fallback.bindTo(site);
引数nの型がXIntegerかテストするメソッドのMH
  引数1を部分適用したXInteger#minus(1)のMH
    XInteger#minus(a)を実装したJavaメソッドのMH
  呼出先MHを検索してCallSiteに再設定するメソッドのMH
MethodHandle test, minus, fallback, all;
minus = lookup.findVirtual(XInteger.class, "minus",
    MethodType.methodType(XObject.class, long.class));
minus = MethodHandles.insertArguments(minus, 1, 1);

fallback = lookup.findStatic(Utils.class, "fallback",
    MethodType.methodType(CallSite.class));
fallback = fallback.bindTo(site);

test = lookup.findStatic(Utils.class, "testClass",
    MethodType.methodType(boolean.class, ..., ...));
test = test.bindTo(self.getClass());
all = MethodHandles.guardWithTest(test, minus, fallback);
site.setTarget(all);
InvokeDynamicによる最適化のコツ

呼び出し側の型(MethodType)と、呼びたい
MethodHandleの型が合うようMH合成

Javaコードは極力入れない
テスト用コードも極力小さくシンプルに

MHの再検索を極力減らす
#jt12_s204

 JRubyにおける
InvokeDynamic
  利用パターン
InvokeDynamic機能の活用
JRuby InvokeDynamic利用パターン

1. 文字列リテラル
2. その他リテラル
3. 擬似定数
4. インスタンス変数
5. メソッド呼び出し
6. 算術演算呼び出し
1. 文字列リテラル                  message = "Hello"
                            message << name << "!"

適用先: リテラル文字列
● "Hello"はbootstrapに渡すようバイトコード生成
● (ctx)Object を (ctx;str)Object にリンクするため、str引数
  を挿入する関数を合成
       ※ThreadContextはThreadなど実行環境情報を格納したオブジェクト



   呼び出しの型: (ThreadContext ctx)Object

    &insert(str = "Hello"):引数を1つ挿入
       &newString(ctx, str):ターゲット
  合成
文字列リテラル参照のインライン化

     def target
       "Hello"
     end

     idx = 0
     while idx < 50000
       target
       idx += 1
     end
文字列リテラル参照のインライン化
$file::method__0$RUBY$target (7 bytes)
 @ 1     j.l.invoke.MH::invokeExact (12 bytes) inline (hot)
  @ 5     o.j...IndySupport::newString (10 bytes) inline (hot)
   @ 6     o.j.RubyString::newStringShared (22 bytes) inline (hot)
     @ 6     o.j.Ruby::getString (5 bytes) inline (hot)
     @ 11     o.j.RubyString::<init> (19 bytes) inline (hot)
      @ 4     o.j.RubyString::<init> (35 bytes) inline (hot)
       @ 3     o.j.RubyObject::<init> (7 bytes) inline (hot)
         @ 3    o.j.RubyBasicObject::<init> (42 bytes) inline (hot)
          @ 1    java.lang.Object::<init> (1 bytes) inline (hot)
          @ 30    o.j...isObjectSpaceEnabled (5 bytes) inline (hot)
          @ 38    o.j...addToObjectSpace (30 bytes) never executed

                                              j.l.* == java.lang.*
                                              o.j.* == org.jruby.*
文字列引数の挿入操作

                                            リンクしたターゲット
$file::method__0$RUBY$target (7 bytes)
 @ 1     j.l.invoke.MH::invokeExact (12 bytes) inline (hot)
  @ 5     o.j...IndySupport::newString (10 bytes) inline (hot)
   @ 6     o.j.RubyString::newStringShared (22 bytes) inline (hot)
     @ 6     o.j.Ruby::getString (5 bytes) inline (hot)
     @ 11     o.j.RubyString::<init> (19 bytes) inline (hot)
      @ 4     o.j.RubyString::<init> (35 bytes) inline (hot)
       @ 3             この辺はJRubyの内部実装
               o.j.RubyObject::<init> (7 bytes) inline (hot)
         @ 3    o.j.RubyBasicObject::<init> (42 bytes) inline (hot)
          @ 1    java.lang.Object::<init> (1 bytes) inline (hot)
          @ 30    o.j...isObjectSpaceEnabled (5 bytes) inline (hot)
          @ 38    o.j...addToObjectSpace (30 bytes) never executed
文字列引数の挿入操作

                                          リンクしたターゲット
$file::method__0$RUBY$target (7 bytes)
 @ 1   j.l.invoke.MH::invokeExact (12 bytes) inline (hot)
  @ 5   o.j...IndySupport::newString (10 bytes) inline (hot)



 &insert(str = "Hello"):引数を1つ挿入
    &newString(ctx, str):ターゲット
times = 10000
2. その他リテラル            matcher = /[A-Z][a-z]*/


適用先: 文字列以外の不変リテラル
● 定数値はbootstrapに渡すようバイトコード生成
● 定数を返すMHを生成
● (ctx)Object から ()Object にリンクするため、ctx引数を削
  る関数を合成


    呼び出しの型: (ThreadContext ctx)Object

     &drop(ctx):引数を1つ削る
        &constant[10000]:常に10000を返すMH
その他リテラル参照のインライン化
                                              引数の削除操作
$file::method__0$RUBY$target (7 bytes)
 @ 1 j.l.invoke.MH::invokeExact (9 bytes) inline (hot)
  @ 2 sun.invoke...Conversions::identity (2 bytes) inline (hot)




                                       定数を返すMHにリンク
invokedynamicの効果
$file::method__0$RUBY$target (7 bytes)
 @ 1 j.l.invoke.MH::invokeExact (9 bytes) inline (hot)
  @ 2 sun.invoke...Conversions::identity (2 bytes) inline (hot)

                               Java SE 7でのインライン化結果

$file$method__0$RUBY$target::call (21 bytes) inline (hot)
 @ 17 $file::method__0$RUBY$target (9 bytes) inline (hot)
  @ 5 o.j...AbstractScript::getFixnum0 (11 bytes) inline (hot)
   @ 7 o.j...RuntimeCache::getFixnum (33 bytes) inline (hot)

                               Java SE 6でのインライン化結果
DEFAULT = Container.new.freeze
3. 擬似定数             comtainer = DEFAULT
                    DEFAULT = nil

適用先: Rubyの定数参照
● Rubyの定数は変更可能なため、「上書きされることの少な
    い変数」として扱う
●   上書き検出にSwitchPointを使う

呼び出しの型: (ThreadContext ctx)Object

&SwitchPoint(&,&):任意の定数が定義されたら破棄
   &drop(ctx):引数を1つ削る
       &constant[obj]:現在の値を定数として返すMH
    &fallback(ctx):同じMHを再構築(→値を再取得)
擬似定数参照のインライン化
$file::method__0$RUBY$target (7 bytes)
 @ 1 j.l.invoke.MH::invokeExact (25 bytes) inline (hot)
  @ 3 j.l.invoke.MH::invokeExact (16 bytes) inline (hot)
   @ 2 j.l.invoke.MH::invokeExact (9 bytes) inline (hot)
    @ 2 j.l.invoke...CallSite::getTarget (5 bytes) inline (hot)
   @ 12 j.l.invoke.MH::invokeExact (5 bytes) inline (hot)
    @ 1 sun.inv...Conversions::identity (2 bytes) inline (hot)
  @ 10 j.l.invoke.MH::invokeExact (10 bytes) inline (hot)
  @ 21 j.l.invoke.MH::invokeExact (6 bytes) inline (hot)
   @ 2 sun.inv...Conversions::identity (2 bytes) inline (hot)
SwitchPointの内部                             SwitchPoint分岐

$file::method__0$RUBY$target (7 bytes)
 @ 1 j.l.invoke.MH::invokeExact (25 bytes) inline (hot)
  @ 3 j.l.invoke.MH::invokeExact (16 bytes) inline (hot)
   @ 2 j.l.invoke.MH::invokeExact (9 bytes) inline (hot)
    @ 2 j.l.invoke...CallSite::getTarget (5 bytes) inline (hot)
   @ 12 j.l.invoke.MH::invokeExact (5 bytes) inline (hot)
    @ 1 sun.inv...Conversions::identity (2 bytes) inline (hot)
  @ 10 j.l.invoke.MH::invokeExact (10 bytes) inline (hot)
  @ 21 j.l.invoke.MH::invokeExact (6 bytes) inline (hot)
   @ 2 sun.inv...Conversions::identity (2 bytes) inline (hot)

                                 SwitchPointの無効化チェック
                       通常は定数を返す

  無効化されていたら再リンクメソッドへ
module Cache
4. インスタンス変数                 def cache(value)
                              @cache = value
                            end
適用先: インスタンス変数アクセス         end
● 呼び出し側selfの変数テーブルを参照     class Foo
                            include Cache
● 変数テーブルはクラスにより異なる        end
                          class Bar
● モジュールが他のクラスに              include Other
  includeされている場合、クラスにより     include Cache
                          end
  "@cache"のテーブル内位置が異なる
● クラスの切り替え判定にguardWithTestを使う
4. インスタンス変数(続き)

呼び出しの型: (ctx;Object self)Object

&guardWithTest(&,&,&):クラスが前回と違えば破棄
   &test(self):クラスに変更がないかテスト
   &filterRetval(&nullToNil):戻り値変換の合成
      &insert(obj = self, index = 2):引数挿入
         &getVariable(ctx,obj,index):ターゲット
   &fallback:新たなメソッド呼び出しMHをネスト
インスタンス変数のインライン化
$file::method__1$RUBY$target (7 bytes)
 @ 1 j.l.invoke.MH::invokeExact (25 bytes) inline (hot)
  @ 3 j.l.invoke.MH::invokeExact (7 bytes) inline (hot)
   @ 3 o.j...Linker::testRealClass (20 bytes) inline (hot)
    @ 5 o.j.RubyBasicObj::getMetaClass (5 bytes) inline (hot)
    @ 8 o.j.RubyClass::getRealClass (2 bytes) inline (hot)
  @ 10 j.l.invoke.MH::invokeExact (10 bytes) inline (hot)
  @ 21 j.l.invoke.MH::invokeExact (14 bytes) inline (hot)
   @ 3 j.l.invoke.MH::invokeExact (8 bytes) inline (hot)
   @ 10 o.j...RuntimeHelpers::nullToNil (10 bytes) inline (hot)
guardWithTestによる分岐
$file::method__1$RUBY$target (7 bytes)
                                           guardWithTest分岐
 @ 1 j.l.invoke.MH::invokeExact (25 bytes) inline (hot)
  @ 3 j.l.invoke.MH::invokeExact (7 bytes) inline (hot)
   @ 3 o.j...Linker::testRealClass (20 bytes) inline (hot)
    @ 5 o.j.RubyBasicObj::getMetaClass (5 bytes) inline (hot)
    @ 8 o.j.RubyClass::getRealClass (2 bytes) inline (hot)
  @ 10 j.l.invoke.MH::invokeExact (10 bytes) inline (hot)
  @ 21 j.l.invoke.MH::invokeExact (14 bytes) inline (hot)
   @ 3 j.l.invoke.MH::invokeExact (8 bytes) inline (hot)
   @ 10 o.j...RuntimeHelpers::nullToNil (10 bytes) inline (hot)

                                 bindしておいたクラスとの比較

          インスタンス変数テーブルの参照
4. インスタンス変数(続き)

呼び出しの型: (ctx;Object self)Object

&guardWithTest(&,&,&):クラスが前回と違えば破棄
   &test(self):クラスに変更がないかテスト
   &filterRetval(&nullToNil):戻り値変換の合成
      &insert(obj = self, index = 2):引数挿入
         &getVariable(ctx,obj,index):ターゲット
   &fallback:新たなメソッド呼び出しMHをネスト
4. インスタンス変数(ネストの具体例)
&guardWithTest:クラスが前回と違えば破棄
  &test(self):クラスはFooか?
  &filterRetval:戻り値がnullならnilに変換
     &insert:テーブル序数として2を挿入
        &getVariable(index):ターゲット
  &fallback:新たなメソッド呼び出しMHをネスト
4. インスタンス変数(ネストの具体例)
&guardWithTest:クラスが前回と違えば破棄
  &test(self):クラスはBarか?
  &filterRetval:戻り値がnullならnilに変換
     &insert:テーブル序数として3を挿入
        &getVariable(index):ターゲット
  &guardWithTest:クラスが前回と違えば破棄
    &test(self):クラスはFooか?
    &filterRetval:戻り値がnullならnilに変換
       &insert:テーブル序数として2を挿入
          &getVariable(index):ターゲット
    &fallback:新たなメソッド呼び出しMHをネスト
def process(router)
                       router.say_hello("Ruby")
5. メソッド呼び出し          end


適用先: 任意のメソッド呼び出し
● レシーバーのクラスに応じ呼び出し先が変わる
● レシーバークラスのメソッドが上書きされる可能性がある
● 引数の個数に応じて5つのタイプ

 呼び出しの型:
 (ctx;self)Object
 (ctx;self;arg1)Object
 (ctx;self;arg1;arg2)Object
 (ctx;self;arg1;arg2;arg3)Object
 (ctx;self;arg[])Object
5. メソッド呼び出し(続き)

呼び出しの型: (ctx;self;arg1)Object

&SwitchPoint:そのクラスでメソッドが定義されたら破棄
   &guardWithTest:レシーバークラスが違えば破棄
      &drop(ctx, self):引数を二つ落とす
         &test(self):クラスは同じか
      &target(ctx, self, arg1):ターゲット
      &fallback:新たなメソッド呼び出しMHをネスト
         ...
   &fallback:同じMHを再構築(→ターゲット更新)
メソッド呼び出しのインライン化
$file::method__1$RUBY$target (9 bytes)
 @ 3 j.l.invoke.MH::invokeExact (33 bytes) inline (hot)
  @ 5 j.l.invoke.MH::invokeExact (20 bytes) inline (hot)
   @ 2 j.l.invoke.MH::invokeExact (9 bytes) inline (hot)
    @ 2 j.l.invoke...CallSite::getTarget (5 bytes) inline (hot)
   @ 16 j.l.invoke.MH::invokeExact (5 bytes) inline (hot)
    @ 1 sun.inv...Conversions::identity (2 bytes) inline (hot)
  @ 12 j.l.invoke.MH::invokeExact (10 bytes) inline (hot)
  @ 29 j.l.invoke.MH::invokeExact (35 bytes) inline (hot)
   @ 5 j.l.invoke.MH::invokeExact (7 bytes) inline (hot)
    @ 3 o.j...Linker::testMetaclass (17 bytes) inline (hot)
     @ 5 o.j...getMetaClass (5 bytes) inline (hot)
   @ 14 j.l.invoke.MH::invokeExact (10 bytes) inline (hot)
   @ 31 j.l.invoke.MH::invokeExact (10 bytes) inline (hot)
    @ 6 $file::method__0$RUBY$stub (7 bytes) inline (hot)
メソッド再定義用に
  分岐のネスト                              SwitchPointのチェック

$file::method__1$RUBY$target (9 bytes)
 @ 3 j.l.invoke.MH::invokeExact (33 bytes) inline (hot)
  @ 5 j.l.invoke.MH::invokeExact (20 bytes) inline (hot)
   @ 2 j.l.invoke.MH::invokeExact (9 bytes) inline (hot)
    @ 2 j.l.invoke...CallSite::getTarget (5 bytes) inline (hot)
                                    レシーバークラスのチェック
   @ 16 j.l.invoke.MH::invokeExact (5 bytes) inline (hot)
    @ 1 sun.inv...Conversions::identity (2 bytes) inline (hot)
  @ 12 j.l.invoke.MH::invokeExact (10 bytes) inline (hot)
  @ 29 j.l.invoke.MH::invokeExact (35 bytes) inline (hot)
   @ 5 j.l.invoke.MH::invokeExact (7 bytes) inline (hot)
    @ 3 o.j...Linker::testMetaclass (17 bytes) inline (hot)
     @ 5 o.j...getMetaClass (5 bytes) inline (hot)
   @ 14 j.l.invoke.MH::invokeExact (10 bytes) inline (hot)
   @ 31 j.l.invoke.MH::invokeExact (10 bytes) inline (hot)
    @ 6 $file::method__0$RUBY$stub (7 bytes) inline (hot)
                     どちらもOKならリンク済みMHを呼び出し
fib(n - 2) + fib(n - 1)
6. 算術演算呼び出し            display if (x >= 5)
                       elapsed = msec * 1000.0

適用先: 右辺が整数、小数の算術演算
● 右辺のunboxをショートカットする

呼び出しの型: (ctx;self)Object

 &guardWithTest:左辺がFixnumならショートカット
    &drop(ctx):引数を1つ落とす
       &test(self):左辺は整数か
    &fixnumMinusOne(ctx, self):ターゲット
    &invoke(ctx, self, value):直接呼び出し
算術演算呼び出しのインライン化
$file::method__0$RUBY$target (14 bytes)
 @ 8 j.l.invoke.MH::invokeExact (33 bytes) inline (hot)
  @ 5 j.l.invoke.MH::invokeExact (7 bytes) inline (hot)
   @ 3 o.j...MathLinker::fixnumTest (20 bytes) inline (hot)
    @ 8 o.j.Ruby::isFixnumReopened (5 bytes) inline (hot)
  @ 12 j.l.invoke.MH::invokeExact (10 bytes) inline (hot)
  @ 29 j.l.invoke.MH::invokeExact (7 bytes) inline (hot)
  @ 29 j.l.invoke.MH::invokeExact (11 bytes) inline (hot)
   @ 7 o.j...fixnumOperatorFail (109 bytes) never executed
   @ 3 o.j...Linker::fixnum_op_minus_one (9 bytes) inline (hot)
    @ 5 o.j.RubyFixnum::op_minus_one (35 bytes) inline (hot)
算術演算呼び出しのインライン化
$file::method__0$RUBY$target (14 bytes)    左辺はFixnumか?
 @ 8 j.l.invoke.MH::invokeExact (33 bytes) inline (hot)
  @ 5 j.l.invoke.MH::invokeExact (7 bytes) inline (hot)
   @ 3 o.j...MathLinker::fixnumTest (20 bytes) inline (hot)
    @ 8 o.j.Ruby::isFixnumReopened (5 bytes) inline (hot)
  @ 12 j.l.invoke.MH::invokeExact (10 bytes) inline (hot)
  @ 29 j.l.invoke.MH::invokeExact (7 bytes) inline (hot)
  @ 29 j.l.invoke.MH::invokeExact (11 bytes) inline (hot)
   @ 7 o.j...fixnumOperatorFail (109 bytes) never executed
   @ 3 o.j...Linker::fixnum_op_minus_one (9 bytes) inline (hot)
    @ 5 o.j.RubyFixnum::op_minus_one (35 bytes) inline (hot)


                            -1専用メソッドを呼び出す
#jt12_s204


JRuby + InvokeDynamic
       性能評価
    InvokeDynamic機能の活用
マイクロベンチマーク

 ※高さはJava 7非indyを1としたときの速度比率。高いほうが速い。
 ※個々のパターンの処理のみを繰り返しループして測定。




     その他リテラル      インスタンス変数         算術演算
文字列リテラル      擬似定数       メソッド呼び出し          全て
二分木ベンチマーク

※高さはJava 7非indyを1としたときの速度比率。高いほうが速い。




       AVL木(再帰)               赤黒木(ループ)
#jt12_s204
Java SE 7 InvokeDynamic
動的型付け言語にとっては革命的
複雑だが、言語処理系が自身で最適化するより楽
→ 以後、最適化はJVMに任せる方向へ

InvokeDynamic機能の適用対象候補
   ● プロファイラ・デバッガ
   ● 関数合成によるロジック再利用
   ● etc.

Más contenido relacionado

La actualidad más candente

Java puzzlers 2013 at JavaFesta Japan
Java puzzlers 2013 at JavaFesta JapanJava puzzlers 2013 at JavaFesta Japan
Java puzzlers 2013 at JavaFesta JapanYoshio Terada
 
Kai = (Dynamo + memcache API) / Erlang
Kai = (Dynamo + memcache API) / ErlangKai = (Dynamo + memcache API) / Erlang
Kai = (Dynamo + memcache API) / ErlangTakeru INOUE
 
Javaセキュアコーディングセミナー東京第3回講義
Javaセキュアコーディングセミナー東京第3回講義Javaセキュアコーディングセミナー東京第3回講義
Javaセキュアコーディングセミナー東京第3回講義JPCERT Coordination Center
 
Shibuya JVM Groovy 20150418
Shibuya JVM Groovy 20150418Shibuya JVM Groovy 20150418
Shibuya JVM Groovy 20150418Uehara Junji
 
Frege, What a Non-strict Language
Frege, What a Non-strict LanguageFrege, What a Non-strict Language
Frege, What a Non-strict Languagey_taka_23
 
Xtend30分クッキング やきに駆動
Xtend30分クッキング   やきに駆動Xtend30分クッキング   やきに駆動
Xtend30分クッキング やきに駆動Shinichi Kozake
 
C#を始めたばかりの人へのLINQ to Objects
C#を始めたばかりの人へのLINQ to ObjectsC#を始めたばかりの人へのLINQ to Objects
C#を始めたばかりの人へのLINQ to ObjectsFumitaka Yamada
 
“Design and Implementation of Generics for the .NET Common Language Runtime”他...
“Design and Implementation of Generics for the .NET Common Language Runtime”他...“Design and Implementation of Generics for the .NET Common Language Runtime”他...
“Design and Implementation of Generics for the .NET Common Language Runtime”他...Masahiro Sakai
 
LINQソースでGO!
LINQソースでGO!LINQソースでGO!
LINQソースでGO!Kouji Matsui
 
An other world awaits you
An other world awaits youAn other world awaits you
An other world awaits you信之 岩永
 
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Mr. Vengineer
 
Java SE 8 lambdaで変わる プログラミングスタイル
Java SE 8 lambdaで変わる プログラミングスタイルJava SE 8 lambdaで変わる プログラミングスタイル
Java SE 8 lambdaで変わる プログラミングスタイルなおき きしだ
 
第2回デザインパターン資料
第2回デザインパターン資料第2回デザインパターン資料
第2回デザインパターン資料gaaupp
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案yohhoy
 
TensorFlow XLA 「XLAとは、から、最近の利用事例について」
TensorFlow XLA 「XLAとは、から、最近の利用事例について」TensorFlow XLA 「XLAとは、から、最近の利用事例について」
TensorFlow XLA 「XLAとは、から、最近の利用事例について」Mr. Vengineer
 
C# ドキドキ ライブ コーディング!! ~ 小島の分 ~ | BuriKaigi 2020
C# ドキドキ ライブ コーディング!! ~ 小島の分 ~ | BuriKaigi 2020C# ドキドキ ライブ コーディング!! ~ 小島の分 ~ | BuriKaigi 2020
C# ドキドキ ライブ コーディング!! ~ 小島の分 ~ | BuriKaigi 2020Fujio Kojima
 
Unit test in android
Unit test in androidUnit test in android
Unit test in androidTatsuya Maki
 
Visual C++で使えるC++11
Visual C++で使えるC++11Visual C++で使えるC++11
Visual C++で使えるC++11nekko1119
 

La actualidad más candente (20)

Java puzzlers 2013 at JavaFesta Japan
Java puzzlers 2013 at JavaFesta JapanJava puzzlers 2013 at JavaFesta Japan
Java puzzlers 2013 at JavaFesta Japan
 
Junit4
Junit4Junit4
Junit4
 
Kai = (Dynamo + memcache API) / Erlang
Kai = (Dynamo + memcache API) / ErlangKai = (Dynamo + memcache API) / Erlang
Kai = (Dynamo + memcache API) / Erlang
 
Javaセキュアコーディングセミナー東京第3回講義
Javaセキュアコーディングセミナー東京第3回講義Javaセキュアコーディングセミナー東京第3回講義
Javaセキュアコーディングセミナー東京第3回講義
 
Shibuya JVM Groovy 20150418
Shibuya JVM Groovy 20150418Shibuya JVM Groovy 20150418
Shibuya JVM Groovy 20150418
 
Frege, What a Non-strict Language
Frege, What a Non-strict LanguageFrege, What a Non-strict Language
Frege, What a Non-strict Language
 
Xtend30分クッキング やきに駆動
Xtend30分クッキング   やきに駆動Xtend30分クッキング   やきに駆動
Xtend30分クッキング やきに駆動
 
C#を始めたばかりの人へのLINQ to Objects
C#を始めたばかりの人へのLINQ to ObjectsC#を始めたばかりの人へのLINQ to Objects
C#を始めたばかりの人へのLINQ to Objects
 
“Design and Implementation of Generics for the .NET Common Language Runtime”他...
“Design and Implementation of Generics for the .NET Common Language Runtime”他...“Design and Implementation of Generics for the .NET Common Language Runtime”他...
“Design and Implementation of Generics for the .NET Common Language Runtime”他...
 
LINQソースでGO!
LINQソースでGO!LINQソースでGO!
LINQソースでGO!
 
An other world awaits you
An other world awaits youAn other world awaits you
An other world awaits you
 
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析
 
Java SE 8 lambdaで変わる プログラミングスタイル
Java SE 8 lambdaで変わる プログラミングスタイルJava SE 8 lambdaで変わる プログラミングスタイル
Java SE 8 lambdaで変わる プログラミングスタイル
 
第2回デザインパターン資料
第2回デザインパターン資料第2回デザインパターン資料
第2回デザインパターン資料
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案
 
VerilatorとSystemC
VerilatorとSystemCVerilatorとSystemC
VerilatorとSystemC
 
TensorFlow XLA 「XLAとは、から、最近の利用事例について」
TensorFlow XLA 「XLAとは、から、最近の利用事例について」TensorFlow XLA 「XLAとは、から、最近の利用事例について」
TensorFlow XLA 「XLAとは、から、最近の利用事例について」
 
C# ドキドキ ライブ コーディング!! ~ 小島の分 ~ | BuriKaigi 2020
C# ドキドキ ライブ コーディング!! ~ 小島の分 ~ | BuriKaigi 2020C# ドキドキ ライブ コーディング!! ~ 小島の分 ~ | BuriKaigi 2020
C# ドキドキ ライブ コーディング!! ~ 小島の分 ~ | BuriKaigi 2020
 
Unit test in android
Unit test in androidUnit test in android
Unit test in android
 
Visual C++で使えるC++11
Visual C++で使えるC++11Visual C++で使えるC++11
Visual C++で使えるC++11
 

Similar a Java SE 7 InvokeDynamic in JRuby

関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会Koichi Sakata
 
Apache Torqueについて
Apache TorqueについてApache Torqueについて
Apache Torqueについてtako pons
 
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_cccJEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_cccYujiSoftware
 
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜JustSystems Corporation
 
C++ マルチスレッドプログラミング
C++ マルチスレッドプログラミングC++ マルチスレッドプログラミング
C++ マルチスレッドプログラミングKohsuke Yuasa
 
Project Loom + Project Panama
Project Loom + Project PanamaProject Loom + Project Panama
Project Loom + Project PanamaYuichi Sakuraba
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門伸男 伊藤
 
Javaはどのように動くのか~スライドでわかるJVMの仕組み
Javaはどのように動くのか~スライドでわかるJVMの仕組みJavaはどのように動くのか~スライドでわかるJVMの仕組み
Javaはどのように動くのか~スライドでわかるJVMの仕組みChihiro Ito
 
明日から使える Java SE 7
明日から使える Java SE 7明日から使える Java SE 7
明日から使える Java SE 7Yuichi Sakuraba
 
Javaセキュアコーディングセミナー東京第3回演習の解説
Javaセキュアコーディングセミナー東京第3回演習の解説Javaセキュアコーディングセミナー東京第3回演習の解説
Javaセキュアコーディングセミナー東京第3回演習の解説JPCERT Coordination Center
 
社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)Iwana Chan
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」yoshiaki iwanaga
 
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~normalian
 
Javaセキュアコーディングセミナー東京第2回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説Javaセキュアコーディングセミナー東京第2回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説JPCERT Coordination Center
 
Javaセキュアコーディングセミナー東京第3回演習
Javaセキュアコーディングセミナー東京第3回演習Javaセキュアコーディングセミナー東京第3回演習
Javaセキュアコーディングセミナー東京第3回演習JPCERT Coordination Center
 
C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~Fujio Kojima
 

Similar a Java SE 7 InvokeDynamic in JRuby (20)

関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会
 
Boost Tour 1.50.0 All
Boost Tour 1.50.0 AllBoost Tour 1.50.0 All
Boost Tour 1.50.0 All
 
Apache Torqueについて
Apache TorqueについてApache Torqueについて
Apache Torqueについて
 
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_cccJEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
 
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
 
C++ マルチスレッドプログラミング
C++ マルチスレッドプログラミングC++ マルチスレッドプログラミング
C++ マルチスレッドプログラミング
 
Ajax 応用
Ajax 応用Ajax 応用
Ajax 応用
 
Project Loom + Project Panama
Project Loom + Project PanamaProject Loom + Project Panama
Project Loom + Project Panama
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 
Javaはどのように動くのか~スライドでわかるJVMの仕組み
Javaはどのように動くのか~スライドでわかるJVMの仕組みJavaはどのように動くのか~スライドでわかるJVMの仕組み
Javaはどのように動くのか~スライドでわかるJVMの仕組み
 
明日から使える Java SE 7
明日から使える Java SE 7明日から使える Java SE 7
明日から使える Java SE 7
 
boost tour 1.48.0 all
boost tour 1.48.0 allboost tour 1.48.0 all
boost tour 1.48.0 all
 
Javaセキュアコーディングセミナー東京第3回演習の解説
Javaセキュアコーディングセミナー東京第3回演習の解説Javaセキュアコーディングセミナー東京第3回演習の解説
Javaセキュアコーディングセミナー東京第3回演習の解説
 
社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
 
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
 
Javaセキュアコーディングセミナー東京第2回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説Javaセキュアコーディングセミナー東京第2回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説
 
Javaセキュアコーディングセミナー東京第3回演習
Javaセキュアコーディングセミナー東京第3回演習Javaセキュアコーディングセミナー東京第3回演習
Javaセキュアコーディングセミナー東京第3回演習
 
C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~
 
Introduction of Python
Introduction of PythonIntroduction of Python
Introduction of Python
 

Más de Hiroshi Nakamura

エンタープライズソフトウェア開発とOSS
エンタープライズソフトウェア開発とOSSエンタープライズソフトウェア開発とOSS
エンタープライズソフトウェア開発とOSSHiroshi Nakamura
 
Information security programming in ruby
Information security programming in rubyInformation security programming in ruby
Information security programming in rubyHiroshi Nakamura
 
ちゃんと理解するForce.com canvas
ちゃんと理解するForce.com canvasちゃんと理解するForce.com canvas
ちゃんと理解するForce.com canvasHiroshi Nakamura
 
Ruby HTTP clients comparison
Ruby HTTP clients comparisonRuby HTTP clients comparison
Ruby HTTP clients comparisonHiroshi Nakamura
 
JavaOne Tokyo JVM言語BOF ベンチマーク JRuby
JavaOne Tokyo JVM言語BOF ベンチマーク JRubyJavaOne Tokyo JVM言語BOF ベンチマーク JRuby
JavaOne Tokyo JVM言語BOF ベンチマーク JRubyHiroshi Nakamura
 
現実世界のJRuby(ショートバージョン)
現実世界のJRuby(ショートバージョン)現実世界のJRuby(ショートバージョン)
現実世界のJRuby(ショートバージョン)Hiroshi Nakamura
 
HSM用ミドルウェア Conduit Toolkitの概要と使い方
HSM用ミドルウェア Conduit Toolkitの概要と使い方HSM用ミドルウェア Conduit Toolkitの概要と使い方
HSM用ミドルウェア Conduit Toolkitの概要と使い方Hiroshi Nakamura
 

Más de Hiroshi Nakamura (10)

エンタープライズソフトウェア開発とOSS
エンタープライズソフトウェア開発とOSSエンタープライズソフトウェア開発とOSS
エンタープライズソフトウェア開発とOSS
 
Information security programming in ruby
Information security programming in rubyInformation security programming in ruby
Information security programming in ruby
 
Embulk 20150411
Embulk 20150411Embulk 20150411
Embulk 20150411
 
ちゃんと理解するForce.com canvas
ちゃんと理解するForce.com canvasちゃんと理解するForce.com canvas
ちゃんと理解するForce.com canvas
 
Ruby HTTP clients comparison
Ruby HTTP clients comparisonRuby HTTP clients comparison
Ruby HTTP clients comparison
 
JavaOne Tokyo JVM言語BOF ベンチマーク JRuby
JavaOne Tokyo JVM言語BOF ベンチマーク JRubyJavaOne Tokyo JVM言語BOF ベンチマーク JRuby
JavaOne Tokyo JVM言語BOF ベンチマーク JRuby
 
現実世界のJRuby(ショートバージョン)
現実世界のJRuby(ショートバージョン)現実世界のJRuby(ショートバージョン)
現実世界のJRuby(ショートバージョン)
 
現実世界のJRuby
現実世界のJRuby現実世界のJRuby
現実世界のJRuby
 
HSM用ミドルウェア Conduit Toolkitの概要と使い方
HSM用ミドルウェア Conduit Toolkitの概要と使い方HSM用ミドルウェア Conduit Toolkitの概要と使い方
HSM用ミドルウェア Conduit Toolkitの概要と使い方
 
HSM超入門講座
HSM超入門講座HSM超入門講座
HSM超入門講座
 

Último

[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Danieldanielhu54
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 

Último (9)

[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Daniel
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 

Java SE 7 InvokeDynamic in JRuby

  • 1. #jt12_s204 Java SE 7 InvokeDynamic in JRuby 日本JRubyユーザ会 中村浩士 @nahi nahi@ruby-lang.org https://github.com/nahi http://slidesha.re/JavaOneJpInvokeDynamic
  • 2. 自己紹介 ネットワークセキュリティ関連のシステム開発 C/C++ (18年)、Java (13年)、Ruby (13年) 余暇のOSS開発 CRuby (8年) とJRuby (2年) のコミッタ soap4r、httpclient他の開発
  • 3. Java SE 7 InvokeDynamicとは Java SE 7に追加された新機能 変数に型のない動的型付け言語の性能向上支援 ● Java仮想マシン(JVM)のバイトコードに invokedynamic命令を追加 ● java.lang.invoke.*に関連APIを追加
  • 4. JRubyとは - http://jruby.org/ 最新リリース版は1.6.7 InvokeDynamic対応は1.7から (来月末のJRubyConfでPreviewリリース) JVM上で動作するRuby(動的型付け言語) Open Source (CPL, GPL, LGPL) 開発開始から10年
  • 6. Agenda 前半: InvokeDynamic機能解説 ● Java言語用メソッド呼び出し ● 動的型付け言語のメソッド呼び出し ● invokedynamic命令と関連API 後半: JRubyにおけるInvokeDynamicの活用 ● 利用パターン ● 性能評価
  • 9. JIT最適化の例: インライン化 double addAllSqrts(int max) { double accum = 0; for (int i = 0; i < max; i++) { accum = addSqrt(accum, i); } return accum; } double addSqrt(double a, int b) { return a + Math.sqrt(b); } public static void main(String[] args) { for (int i = 0; i < 100000; ++i) { (new Target()).addAllSqrts(10); } }
  • 10. JIT最適化の例: インライン化 % java -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining Target 66 1 Target::addAllSqrts (27 bytes) 67 2 Target::addSqrt (8 bytes) @ 3 java.lang.Math::sqrt (5 bytes) (intrinsic) @ 15 Target::addSqrt (8 bytes) inline (hot) @ 3 java.lang.Math::sqrt (5 bytes) (intrinsic) 78 1 % Target::main @ 2 (28 bytes) @ 12 Target::<init> (5 bytes) inline (hot) @ 1 java.lang.Object::<init> (1 bytes) inline (hot) @ 17 Target::addAllSqrts (27 bytes) inline (hot) @ 15 Target::addSqrt (8 bytes) inline (hot) @ 3 java.lang.Math::sqrt (5 bytes) (intrinsic) @ 1 java.lang.Object::<init> (1 bytes) inline (hot)
  • 11. JIT最適化の例 double addSqrt(double a, int b) { return a + Math.sqrt(b); % java -XX:+PrintCompilation } -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining Target 66 1 Target::addAllSqrts (27 bytes) addSqrtをコンパイル 67 2 Target::addSqrt (8 bytes) @ 3 java.lang.Math::sqrt (5 bytes) (intrinsic) @ 15 Target::addSqrt (8 bytes) inline (hot) @ 3 java.lang.Math::sqrt (5 bytes) (intrinsic) 78 1 % Target::main @ 2 (28 bytes) @ 12 Target::<init> (5 bytes) inline (hot) @ 1 java.lang.Object::<init> (1 bytes) inline (hot) @ 17 Target::addAllSqrts (27 bytes) inline (hot) @ 15 Math.sqrt呼び出しと加算を Target::addSqrt (8 bytes) inline (hot) @ 3 インライン化 java.lang.Math::sqrt (5 bytes) (intrinsic) @ 1 java.lang.Object::<init> (1 bytes) inline (hot)
  • 12. double addAllSqrts(int max) { double accum = 0; for (int i = 0; i < max; i++) { accum = addSqrt(accum, i); }} public static void main(String[] args) { % java -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions 0; i < 100000; ++i) Target for (int i = -XX:+PrintInlining { (new Target()).addAllSqrts(10); }} 66 1 Target::addAllSqrts (27 bytes) 67 2 Target::addSqrt (8 bytes) @mainをコンパイル 3 forの中にあるaddAllSqrtsおよび java.lang.Math::sqrt (5 bytes) (intrinsic) @ 15 その中身を全てインライン化 Target::addSqrt (8 bytes) inline (hot) @ 3 java.lang.Math::sqrt (5 bytes) (intrinsic) 78 1 % Target::main @ 2 (28 bytes) @ 12 Target::<init> (5 bytes) inline (hot) @ 1 java.lang.Object::<init> (1 bytes) inline (hot) @ 17 Target::addAllSqrts (27 bytes) inline (hot) @ 15 Target::addSqrt (8 bytes) inline (hot) @ 3 java.lang.Math::sqrt (5 bytes) (intrinsic) @ 1 java.lang.Object::<init> (1 bytes) inline (hot)
  • 13. double addAllSqrts(int max) { double accum = 0; for (int i = 0; i < max; i++) { accum = addSqrt(accum, i); }} OSR: On-stack public static void main(String[] args) { % java -XX:+PrintCompilation replacement -XX:+UnlockDiagnosticVMOptions 0; i < 100000; ++i) Target for (int i = -XX:+PrintInlining { (new Target()).addAllSqrts(10); }} 66 1 Target::addAllSqrts (27 bytes) 67 2 Target::addSqrt (8 bytes) @mainをコンパイル 3 forの中にあるaddAllSqrtsおよび java.lang.Math::sqrt (5 bytes) (intrinsic) @ 15 その中身を全てインライン化 Target::addSqrt (8 bytes) inline (hot) @ 3 java.lang.Math::sqrt (5 bytes) (intrinsic) 78 1 % Target::main @ 2 (28 bytes) @ 12 Target::<init> (5 bytes) inline (hot) @ 1 java.lang.Object::<init> (1 bytes) inline (hot) @ 17 Target::addAllSqrts (27 bytes) inline (hot) @ 15 Target::addSqrt (8 bytes) inline (hot) @ 3 java.lang.Math::sqrt (5 bytes) (intrinsic) @ 1 java.lang.Object::<init> (1 bytes) inline (hot)
  • 16. JVMでのメソッド呼び出し public class Command { void processOptions(String[] options) { boolean result; for (String opt : options) { result = process(opt.concat("?!")); } } boolean process(String opt) { ... } void run() { String[] options = { "yes", "no", "maybe" }; processOptions(options); } }
  • 17. JVMでのメソッド呼び出し public class Command { void processOptions(String[] options) { boolean result; for (String opt : options) { result = process(opt.concat("?!")); } } boolean process(String opt) { ... } void run() { String[] options = { "yes", "no", "maybe" }; processOptions(options); } }
  • 18. JVMでのメソッド呼び出し <Command> void processOptions(java.lang.String[]); process(opt.concat("?!")); 20: aload_0 // thisであるCommandをスタックに入れる 21: aload 5 23: ldc #2 25: invokevirtual #3 28: invokevirtual #4
  • 19. JVMでのメソッド呼び出し "yes" void processOptions(java.lang.String[]); <Command> process(opt.concat("?!")); 20: aload_0 // thisであるCommandをスタックに入れる 21: aload 5 // forループ引数optから"yes"を入れる 23: ldc #2 25: invokevirtual #3 28: invokevirtual #4
  • 20. JVMでのメソッド呼び出し "?!" void processOptions(java.lang.String[]); "yes" process(opt.concat("?!")); <Command> 20: aload_0 // thisであるCommandをスタックに入れる 21: aload 5 // forループ引数optから"yes"を入れる 23: ldc #2 // 定数"?!"を入れる 25: invokevirtual #3 28: invokevirtual #4
  • 21. JVMでのメソッド呼び出し "?!" void processOptions(java.lang.String[]); "yes" process(opt.concat("?!")); <Command> 20: aload_0 // thisであるCommandをスタックに入れる 21: aload 5 // forループ引数optから"yes"を入れる 23: ldc #2 // 定数"?!"を入れる 25: invokevirtual #3 // String.concat // スタックからループ引数と"?!"を取り出し // 引数としてconcatを呼んで... 28: invokevirtual #4
  • 22. JVMでのメソッド呼び出し "yes?!" void processOptions(java.lang.String[]); <Command> process(opt.concat("?!")); 20: aload_0 // thisであるCommandをスタックに入れる 21: aload 5 // forループ引数optから"yes"を入れる 23: ldc #2 // 定数"?!"を入れる 25: invokevirtual #3 // String.concat // スタックからループ引数と"?!"を取り出し // 引数としてconcatを呼んで // 戻り値をスタックに積む 28: invokevirtual #4
  • 23. JVMでのメソッド呼び出し "yes?!" void processOptions(java.lang.String[]); <Command> process(opt.concat("?!")); 20: aload_0 // thisであるCommandをスタックに入れる 21: aload 5// forループ引数optから"yes"を入れる 23: ldc #2 // 定数"?!"を入れる 25: invokevirtual #3 // String.concat // スタックからループ引数と"?!"を取り出し // 引数としてconcatを呼んで // 戻り値をスタックに積む 28: invokevirtual #4 // process // スタックからthisと戻り値文字列を取り出し // 自身であるCommandのprocessを呼ぶ
  • 25. Call Siteに必要な情報 コンパイル時: 呼び出し先の参照情報 メソッドが属するクラス: String メソッド名: "concat" メソッド型(引数と戻り値の型): (String;String)String [本資料でのメソッド型の表記方法] Objectとlongの2引数、Objectが戻り値 → (Object;long)Object
  • 26. Call Siteに必要な情報 コンパイル時: 呼び出し先の参照情報 メソッドが属するクラス: String メソッド名: "concat" メソッド型(引数と戻り値の型): (String;String)String 実行時 呼び出し先メソッドの実体: String#concat レシーバー / 引数オブジェクト: "yes" / "?!" 戻り値オブジェクト / 発生例外: "yes?!"
  • 27. Java言語用メソッド呼び出し命令 参照先メソッドを決定する4種のバイトコード invokestatic staticメソッドを直接リンク invokespecial private/super/コンストラクタ invokevirtual インスタンスメソッド検索 (virtual解決) invokeinterface インターフェースメソッド検索 (interface解決)
  • 28. invokevirtualのメソッド呼び出し コンパイル時: JComponent メソッドが属するクラス: +paint() JTextComponent メソッド名: "getText" JTextComponent +paint() メソッド型: ()Void +getText() 実行時: JTextField JTextArea 呼び出し先メソッドの実体: +paint() +paint() JTextField#getText +getText() +getText() +getColumns() +getRows() +getColumns()
  • 29. invokevirtualのメソッド呼び出し コンパイル時: JComponent メソッドが属するクラス: +paint() JTextComponent メソッド名: "getText" JTextComponent +paint() メソッド型: ()Void +getText() 実行時: JTextField JTextArea 呼び出し先メソッドの実体: +paint() +paint() JTextField#getText +getText() +getText() +getColumns() +getRows() +getColumns()
  • 32. 動的型付け言語のメソッド呼び出し def process_options(options) for opt in options process(opt.concat("?!")) end end mock = Object.new def mock.concat(arg) "tested!" end options = ["yes", "no", mock] process_options(options)
  • 34. 例: Java SE 6用のJRuby実装 JRuby独自のCall Site (呼び出し先の参照情報を格納) 参照先メソッドの検索も独自実装
  • 35. Java SE 6用のJRuby生成バイトコード process(opt.concat("?!")) aload_0 invokevirtual main.getCallSite1; "process"CallSite // "process"呼び出し用のCallSiteをスタックに入れる aload_0 invokevirtual main.getCallSite2; aload 9 aload_0 invokevirtual main.getString0; invokevirtual CallSite.call; invokevirtual CallSite.call;
  • 36. Java SE 6用のJRuby生成バイトコード process(opt.concat("?!")) aload_0 invokevirtual main.getCallSite1; "concat"CallSite // "process"呼び出し用のCallSiteをスタックに入れる "process"CallSite aload_0 invokevirtual main.getCallSite2; // "concat"呼び出し用のCallSiteをスタックに入れる aload 9 aload_0 invokevirtual main.getString0; invokevirtual CallSite.call; invokevirtual CallSite.call;
  • 37. Java SE 6用のJRuby生成バイトコード process(opt.concat("?!")) aload_0 invokevirtual main.getCallSite1; "yes" // "process"呼び出し用のCallSiteをスタックに入れる "concat"CallSite aload_0 invokevirtual main.getCallSite2; "process"CallSite // "concat"呼び出し用のCallSiteをスタックに入れる aload 9 // forループ引数optから"yes"を入れる aload_0 invokevirtual main.getString0; invokevirtual CallSite.call; invokevirtual CallSite.call;
  • 38. Java SE 6用のJRuby生成バイトコード process(opt.concat("?!")) aload_0 invokevirtual main.getCallSite1; "?!" // "process"呼び出し用のCallSiteをスタックに入れる "yes" aload_0 invokevirtual main.getCallSite2; "concat"CallSite // "concat"呼び出し用のCallSiteをスタックに入れる "process"CallSite aload 9 // forループ引数optから"yes"を入れる aload_0 invokevirtual main.getString0; // 引数の"?!" invokevirtual CallSite.call; invokevirtual CallSite.call;
  • 39. Java SE 6用のJRuby生成バイトコード process(opt.concat("?!")) aload_0 invokevirtual main.getCallSite1; "?!" // "process"呼び出し用のCallSiteをスタックに入れる "yes" aload_0 invokevirtual main.getCallSite2; "concat"CallSite // "concat"呼び出し用のCallSiteをスタックに入れる "process"CallSite aload 9 // forループ引数optから"yes"を入れる aload_0 invokevirtual main.getString0; // 引数の"?!" invokevirtual CallSite.call; // スタックのCallSite情報を元に動的メソッド呼び出し(concat) invokevirtual CallSite.call;
  • 40. Java SE 6用のJRuby生成バイトコード process(opt.concat("?!")) aload_0 invokevirtual main.getCallSite1; "yes?!" // "process"呼び出し用のCallSiteをスタックに入れる "process"CallSite aload_0 invokevirtual main.getCallSite2; // "concat"呼び出し用のCallSiteをスタックに入れる aload 9 // forループ引数optから"yes"を入れる aload_0 invokevirtual main.getString0; // 引数の"?!" invokevirtual CallSite.call; // スタックのCallSite情報を元に動的メソッド呼び出し(concat) invokevirtual CallSite.call;
  • 41. Java SE 6用のJRuby生成バイトコード process(opt.concat("?!")) aload_0 invokevirtual main.getCallSite1; "yes?!" // "process"呼び出し用のCallSiteをスタックに入れる "process"CallSite aload_0 invokevirtual main.getCallSite2; // "concat"呼び出し用のCallSiteをスタックに入れる aload 9 // forループ引数optから"yes"を入れる aload_0 invokevirtual main.getString0; // 引数の"?!" invokevirtual CallSite.call; // スタックのCallSite情報を元に動的メソッド呼び出し(concat) invokevirtual CallSite.call; // 同じく動的メソッド呼び出し(process)
  • 42. Java SE 6でのJRubyメソッド呼び出し def target(opt) process(opt.concat("?!")) end 引数の数、順序の調整 デフォルト引数の補完 RubyString# CallSite Invoker ... concat invokevirtual getCallSite2 最終的に aload 9 ここを呼ぶ aload_0 呼び出しメソッド検索 invokevirtual getString0 メソッドキャッシュ invokevirtual CallSite.call キャッシュミス判定
  • 43. JRuby独自の最適化 素朴な実装のままでは遅いので... ● メソッドキャッシュ / 無効化 ● JITコンパイル ○ バイトコード動的生成→読み込み ○ 脱最適化 より詳しく: http://bit.ly/JRubyHackingGuide
  • 45. Java SE 6でのJRubyメソッド呼び出し 引数の数、順序の調整 デフォルト引数の補完 ... RubyString# invokevirtual getCallSite2 CallSite Invoker concat aload 9 aload_0 最終的に invokevirtual getString0 ここを呼ぶ invokevirtual CallSite.call 呼び出しメソッド検索 メソッドキャッシュ キャッシュミス判定
  • 46. Java SE 7でのJRubyメソッド呼び出し 呼び出しメソッド検索 メソッドキャッシュ 引数の数、順序の調整 キャッシュミス判定 デフォルト引数の補完 MethodHandle bootstrap API RubyString# CallSite Invoker concat ... ic edy nam 最終的に nvok aload 9 invokedynamic getString i ここを呼ぶ invokedynamic concat
  • 47. InvokeDynamic用生成バイトコード process(opt.concat("?!")) aload_2 // thisであるCommandをスタックに入れる aload 9 // forループ引数optから"yes"を入れる invokedynamic getString [...] // 引数の"?!"を取り出す invokedynamic concat (IRubyObject;IRubyObject)IRubyObject [...] // "concat"メソッドを動的呼び出し invokedynamic process (IRubyObject;IRubyObject)IRubyObject [...] // "process"メソッドを動的呼び出し
  • 48. 生成されるバイトコードの違い 独自のCall Siteはなくinvokedynamic命令で直接呼び出す concatの呼び出し情報は以下 メソッド名: "concat" メソッド型: (IRubyObject;IRubyObject)IRubyObject "concat"という名前のメソッドを、2つのRubyオブジェクト (先頭レシーバ、引数1つ)と共に呼び出し戻り値を得る ...呼び出し先はどこ?
  • 50. bootstrapメソッド invokedynamic命令をよく見ると... invokedynamic concat(IRubyObject;IRubyObject)IRubyObject [ invocationBootstrap((Lookup;String;MethodType)CallSite) ] invokedynamic process(IRubyObject;IRubyObject)IRubyObject [ invocationBootstrap((Lookup;String;MethodType)CallSite) ] ...bootstrapと呼ぶ初期化メソッドが登録されている
  • 51. bootstrapメソッド (Lookup;String;MethodType)CallSite 初回実行時のみ呼ばれるユーザ定義メソッド Lookup: メソッド検索用オブジェクト String: メソッド名 ("concat") MethodType: スタック上の引数オブジェクト型 CallSite: 検索した呼び出し先メソッドの参照 (MethodHandle)を格納
  • 52. Java SE 7からのメソッド呼び出し命令 invokestatic staticメソッドを直接リンク invokespecial private/super/コンストラクタ invokevirtual インスタンスメソッド検索 (virtual解決) invokeinterface インターフェースメソッド検索 (interface解決) invokedynamic 動的MethodHandle検索 (bootstrapによる解決)
  • 53. Java SE 7 InvokeDynamicとは何か コンセプト 道具 Call Siteと呼出先の動的なリンク invokedynamic, CallSite リンク先検索ロジックをプログラム可能 bootstrap メソッド参照 MethodHandle 型の安全かつ自動的な変換 MethodType 実行時の呼び出し先メソッド分岐 MethodHandle合成 動的型付け言語で、Javaの呼び出しと同じ最適化
  • 54. MethodHandle(MH)操作API Lookup#* クラス名と名前指定でMHを生成 MethodHandle#bindTo 第1引数のレシーバを固定 MethodHandles#* MHを合成して新たなMHを生成 insertArguments 引数を部分適用したMHを生成 guardWithTest test, then, else用の3MHを合成 して実行時に分岐するMH SwitchPoint#guardWithTest より最適化された true/false分岐のMH生成 SwitchPoint.invalidateAll sptの無効化
  • 55. def fib(n) if n < 2 MH操作の例 n else fib(n - 2) + fib(n - 1) end "n - 1"のリンク先は? end 最初に呼ばれたXInteger#minusにリンク ただし毎回nの型 == XIntegerのチェックは必要 4つのMHを合成してCallSiteに設定 引数nの型がXIntegerかテストするメソッドのMH 引数1を部分適用したXInteger#minus(1)のMH XInteger#minus(a)を実装したJavaメソッドのMH 呼出先MHを検索してCallSiteに再設定するメソッドのMH
  • 56. 引数nの型がXIntegerかテストするメソッドのMH 引数1を部分適用したXInteger#minus(1)のMH XInteger#minus(a)を実装したJavaメソッドのMH 呼出先MHを検索してCallSiteに再設定するメソッドのMH MethodHandle test, minus, fallback, all; minus = lookup.findVirtual(XInteger.class, "minus", MethodType.methodType(XObject.class, long.class)); minus = MethodHandles.insertArguments(minus, 1, 1); 1番目の引数に 1Lを部分適用
  • 57. 引数nの型がXIntegerかテストするメソッドのMH 引数1を部分適用したXInteger#minus(1)のMH XInteger#minus(a)を実装したJavaメソッドのMH 呼出先MHを検索してCallSiteに再設定するメソッドのMH MethodHandle test, minus, fallback, all; minus = lookup.findVirtual(XInteger.class, "minus", MethodType.methodType(XObject.class, long.class)); minus = MethodHandles.insertArguments(minus, 1, 1); fallback = lookup.findStatic(Utils.class, "fallback", MethodType.methodType(CallSite.class)); fallback = fallback.bindTo(site);
  • 58. 引数nの型がXIntegerかテストするメソッドのMH 引数1を部分適用したXInteger#minus(1)のMH XInteger#minus(a)を実装したJavaメソッドのMH 呼出先MHを検索してCallSiteに再設定するメソッドのMH MethodHandle test, minus, fallback, all; minus = lookup.findVirtual(XInteger.class, "minus", MethodType.methodType(XObject.class, long.class)); minus = MethodHandles.insertArguments(minus, 1, 1); fallback = lookup.findStatic(Utils.class, "fallback", MethodType.methodType(CallSite.class)); fallback = fallback.bindTo(site); test = lookup.findStatic(Utils.class, "testClass", MethodType.methodType(boolean.class, ..., ...)); test = test.bindTo(self.getClass()); all = MethodHandles.guardWithTest(test, minus, fallback); site.setTarget(all);
  • 60. #jt12_s204 JRubyにおける InvokeDynamic 利用パターン InvokeDynamic機能の活用
  • 61. JRuby InvokeDynamic利用パターン 1. 文字列リテラル 2. その他リテラル 3. 擬似定数 4. インスタンス変数 5. メソッド呼び出し 6. 算術演算呼び出し
  • 62. 1. 文字列リテラル message = "Hello" message << name << "!" 適用先: リテラル文字列 ● "Hello"はbootstrapに渡すようバイトコード生成 ● (ctx)Object を (ctx;str)Object にリンクするため、str引数 を挿入する関数を合成 ※ThreadContextはThreadなど実行環境情報を格納したオブジェクト 呼び出しの型: (ThreadContext ctx)Object &insert(str = "Hello"):引数を1つ挿入 &newString(ctx, str):ターゲット 合成
  • 63. 文字列リテラル参照のインライン化 def target "Hello" end idx = 0 while idx < 50000 target idx += 1 end
  • 64. 文字列リテラル参照のインライン化 $file::method__0$RUBY$target (7 bytes) @ 1 j.l.invoke.MH::invokeExact (12 bytes) inline (hot) @ 5 o.j...IndySupport::newString (10 bytes) inline (hot) @ 6 o.j.RubyString::newStringShared (22 bytes) inline (hot) @ 6 o.j.Ruby::getString (5 bytes) inline (hot) @ 11 o.j.RubyString::<init> (19 bytes) inline (hot) @ 4 o.j.RubyString::<init> (35 bytes) inline (hot) @ 3 o.j.RubyObject::<init> (7 bytes) inline (hot) @ 3 o.j.RubyBasicObject::<init> (42 bytes) inline (hot) @ 1 java.lang.Object::<init> (1 bytes) inline (hot) @ 30 o.j...isObjectSpaceEnabled (5 bytes) inline (hot) @ 38 o.j...addToObjectSpace (30 bytes) never executed j.l.* == java.lang.* o.j.* == org.jruby.*
  • 65. 文字列引数の挿入操作 リンクしたターゲット $file::method__0$RUBY$target (7 bytes) @ 1 j.l.invoke.MH::invokeExact (12 bytes) inline (hot) @ 5 o.j...IndySupport::newString (10 bytes) inline (hot) @ 6 o.j.RubyString::newStringShared (22 bytes) inline (hot) @ 6 o.j.Ruby::getString (5 bytes) inline (hot) @ 11 o.j.RubyString::<init> (19 bytes) inline (hot) @ 4 o.j.RubyString::<init> (35 bytes) inline (hot) @ 3 この辺はJRubyの内部実装 o.j.RubyObject::<init> (7 bytes) inline (hot) @ 3 o.j.RubyBasicObject::<init> (42 bytes) inline (hot) @ 1 java.lang.Object::<init> (1 bytes) inline (hot) @ 30 o.j...isObjectSpaceEnabled (5 bytes) inline (hot) @ 38 o.j...addToObjectSpace (30 bytes) never executed
  • 66. 文字列引数の挿入操作 リンクしたターゲット $file::method__0$RUBY$target (7 bytes) @ 1 j.l.invoke.MH::invokeExact (12 bytes) inline (hot) @ 5 o.j...IndySupport::newString (10 bytes) inline (hot) &insert(str = "Hello"):引数を1つ挿入 &newString(ctx, str):ターゲット
  • 67. times = 10000 2. その他リテラル matcher = /[A-Z][a-z]*/ 適用先: 文字列以外の不変リテラル ● 定数値はbootstrapに渡すようバイトコード生成 ● 定数を返すMHを生成 ● (ctx)Object から ()Object にリンクするため、ctx引数を削 る関数を合成 呼び出しの型: (ThreadContext ctx)Object &drop(ctx):引数を1つ削る &constant[10000]:常に10000を返すMH
  • 68. その他リテラル参照のインライン化 引数の削除操作 $file::method__0$RUBY$target (7 bytes) @ 1 j.l.invoke.MH::invokeExact (9 bytes) inline (hot) @ 2 sun.invoke...Conversions::identity (2 bytes) inline (hot) 定数を返すMHにリンク
  • 69. invokedynamicの効果 $file::method__0$RUBY$target (7 bytes) @ 1 j.l.invoke.MH::invokeExact (9 bytes) inline (hot) @ 2 sun.invoke...Conversions::identity (2 bytes) inline (hot) Java SE 7でのインライン化結果 $file$method__0$RUBY$target::call (21 bytes) inline (hot) @ 17 $file::method__0$RUBY$target (9 bytes) inline (hot) @ 5 o.j...AbstractScript::getFixnum0 (11 bytes) inline (hot) @ 7 o.j...RuntimeCache::getFixnum (33 bytes) inline (hot) Java SE 6でのインライン化結果
  • 70. DEFAULT = Container.new.freeze 3. 擬似定数 comtainer = DEFAULT DEFAULT = nil 適用先: Rubyの定数参照 ● Rubyの定数は変更可能なため、「上書きされることの少な い変数」として扱う ● 上書き検出にSwitchPointを使う 呼び出しの型: (ThreadContext ctx)Object &SwitchPoint(&,&):任意の定数が定義されたら破棄 &drop(ctx):引数を1つ削る &constant[obj]:現在の値を定数として返すMH &fallback(ctx):同じMHを再構築(→値を再取得)
  • 71. 擬似定数参照のインライン化 $file::method__0$RUBY$target (7 bytes) @ 1 j.l.invoke.MH::invokeExact (25 bytes) inline (hot) @ 3 j.l.invoke.MH::invokeExact (16 bytes) inline (hot) @ 2 j.l.invoke.MH::invokeExact (9 bytes) inline (hot) @ 2 j.l.invoke...CallSite::getTarget (5 bytes) inline (hot) @ 12 j.l.invoke.MH::invokeExact (5 bytes) inline (hot) @ 1 sun.inv...Conversions::identity (2 bytes) inline (hot) @ 10 j.l.invoke.MH::invokeExact (10 bytes) inline (hot) @ 21 j.l.invoke.MH::invokeExact (6 bytes) inline (hot) @ 2 sun.inv...Conversions::identity (2 bytes) inline (hot)
  • 72. SwitchPointの内部 SwitchPoint分岐 $file::method__0$RUBY$target (7 bytes) @ 1 j.l.invoke.MH::invokeExact (25 bytes) inline (hot) @ 3 j.l.invoke.MH::invokeExact (16 bytes) inline (hot) @ 2 j.l.invoke.MH::invokeExact (9 bytes) inline (hot) @ 2 j.l.invoke...CallSite::getTarget (5 bytes) inline (hot) @ 12 j.l.invoke.MH::invokeExact (5 bytes) inline (hot) @ 1 sun.inv...Conversions::identity (2 bytes) inline (hot) @ 10 j.l.invoke.MH::invokeExact (10 bytes) inline (hot) @ 21 j.l.invoke.MH::invokeExact (6 bytes) inline (hot) @ 2 sun.inv...Conversions::identity (2 bytes) inline (hot) SwitchPointの無効化チェック 通常は定数を返す 無効化されていたら再リンクメソッドへ
  • 73. module Cache 4. インスタンス変数 def cache(value) @cache = value end 適用先: インスタンス変数アクセス end ● 呼び出し側selfの変数テーブルを参照 class Foo include Cache ● 変数テーブルはクラスにより異なる end class Bar ● モジュールが他のクラスに include Other includeされている場合、クラスにより include Cache end "@cache"のテーブル内位置が異なる ● クラスの切り替え判定にguardWithTestを使う
  • 74. 4. インスタンス変数(続き) 呼び出しの型: (ctx;Object self)Object &guardWithTest(&,&,&):クラスが前回と違えば破棄 &test(self):クラスに変更がないかテスト &filterRetval(&nullToNil):戻り値変換の合成 &insert(obj = self, index = 2):引数挿入 &getVariable(ctx,obj,index):ターゲット &fallback:新たなメソッド呼び出しMHをネスト
  • 75. インスタンス変数のインライン化 $file::method__1$RUBY$target (7 bytes) @ 1 j.l.invoke.MH::invokeExact (25 bytes) inline (hot) @ 3 j.l.invoke.MH::invokeExact (7 bytes) inline (hot) @ 3 o.j...Linker::testRealClass (20 bytes) inline (hot) @ 5 o.j.RubyBasicObj::getMetaClass (5 bytes) inline (hot) @ 8 o.j.RubyClass::getRealClass (2 bytes) inline (hot) @ 10 j.l.invoke.MH::invokeExact (10 bytes) inline (hot) @ 21 j.l.invoke.MH::invokeExact (14 bytes) inline (hot) @ 3 j.l.invoke.MH::invokeExact (8 bytes) inline (hot) @ 10 o.j...RuntimeHelpers::nullToNil (10 bytes) inline (hot)
  • 76. guardWithTestによる分岐 $file::method__1$RUBY$target (7 bytes) guardWithTest分岐 @ 1 j.l.invoke.MH::invokeExact (25 bytes) inline (hot) @ 3 j.l.invoke.MH::invokeExact (7 bytes) inline (hot) @ 3 o.j...Linker::testRealClass (20 bytes) inline (hot) @ 5 o.j.RubyBasicObj::getMetaClass (5 bytes) inline (hot) @ 8 o.j.RubyClass::getRealClass (2 bytes) inline (hot) @ 10 j.l.invoke.MH::invokeExact (10 bytes) inline (hot) @ 21 j.l.invoke.MH::invokeExact (14 bytes) inline (hot) @ 3 j.l.invoke.MH::invokeExact (8 bytes) inline (hot) @ 10 o.j...RuntimeHelpers::nullToNil (10 bytes) inline (hot) bindしておいたクラスとの比較 インスタンス変数テーブルの参照
  • 77. 4. インスタンス変数(続き) 呼び出しの型: (ctx;Object self)Object &guardWithTest(&,&,&):クラスが前回と違えば破棄 &test(self):クラスに変更がないかテスト &filterRetval(&nullToNil):戻り値変換の合成 &insert(obj = self, index = 2):引数挿入 &getVariable(ctx,obj,index):ターゲット &fallback:新たなメソッド呼び出しMHをネスト
  • 78. 4. インスタンス変数(ネストの具体例) &guardWithTest:クラスが前回と違えば破棄 &test(self):クラスはFooか? &filterRetval:戻り値がnullならnilに変換 &insert:テーブル序数として2を挿入 &getVariable(index):ターゲット &fallback:新たなメソッド呼び出しMHをネスト
  • 79. 4. インスタンス変数(ネストの具体例) &guardWithTest:クラスが前回と違えば破棄 &test(self):クラスはBarか? &filterRetval:戻り値がnullならnilに変換 &insert:テーブル序数として3を挿入 &getVariable(index):ターゲット &guardWithTest:クラスが前回と違えば破棄 &test(self):クラスはFooか? &filterRetval:戻り値がnullならnilに変換 &insert:テーブル序数として2を挿入 &getVariable(index):ターゲット &fallback:新たなメソッド呼び出しMHをネスト
  • 80. def process(router) router.say_hello("Ruby") 5. メソッド呼び出し end 適用先: 任意のメソッド呼び出し ● レシーバーのクラスに応じ呼び出し先が変わる ● レシーバークラスのメソッドが上書きされる可能性がある ● 引数の個数に応じて5つのタイプ 呼び出しの型: (ctx;self)Object (ctx;self;arg1)Object (ctx;self;arg1;arg2)Object (ctx;self;arg1;arg2;arg3)Object (ctx;self;arg[])Object
  • 81. 5. メソッド呼び出し(続き) 呼び出しの型: (ctx;self;arg1)Object &SwitchPoint:そのクラスでメソッドが定義されたら破棄 &guardWithTest:レシーバークラスが違えば破棄 &drop(ctx, self):引数を二つ落とす &test(self):クラスは同じか &target(ctx, self, arg1):ターゲット &fallback:新たなメソッド呼び出しMHをネスト ... &fallback:同じMHを再構築(→ターゲット更新)
  • 82. メソッド呼び出しのインライン化 $file::method__1$RUBY$target (9 bytes) @ 3 j.l.invoke.MH::invokeExact (33 bytes) inline (hot) @ 5 j.l.invoke.MH::invokeExact (20 bytes) inline (hot) @ 2 j.l.invoke.MH::invokeExact (9 bytes) inline (hot) @ 2 j.l.invoke...CallSite::getTarget (5 bytes) inline (hot) @ 16 j.l.invoke.MH::invokeExact (5 bytes) inline (hot) @ 1 sun.inv...Conversions::identity (2 bytes) inline (hot) @ 12 j.l.invoke.MH::invokeExact (10 bytes) inline (hot) @ 29 j.l.invoke.MH::invokeExact (35 bytes) inline (hot) @ 5 j.l.invoke.MH::invokeExact (7 bytes) inline (hot) @ 3 o.j...Linker::testMetaclass (17 bytes) inline (hot) @ 5 o.j...getMetaClass (5 bytes) inline (hot) @ 14 j.l.invoke.MH::invokeExact (10 bytes) inline (hot) @ 31 j.l.invoke.MH::invokeExact (10 bytes) inline (hot) @ 6 $file::method__0$RUBY$stub (7 bytes) inline (hot)
  • 83. メソッド再定義用に 分岐のネスト SwitchPointのチェック $file::method__1$RUBY$target (9 bytes) @ 3 j.l.invoke.MH::invokeExact (33 bytes) inline (hot) @ 5 j.l.invoke.MH::invokeExact (20 bytes) inline (hot) @ 2 j.l.invoke.MH::invokeExact (9 bytes) inline (hot) @ 2 j.l.invoke...CallSite::getTarget (5 bytes) inline (hot) レシーバークラスのチェック @ 16 j.l.invoke.MH::invokeExact (5 bytes) inline (hot) @ 1 sun.inv...Conversions::identity (2 bytes) inline (hot) @ 12 j.l.invoke.MH::invokeExact (10 bytes) inline (hot) @ 29 j.l.invoke.MH::invokeExact (35 bytes) inline (hot) @ 5 j.l.invoke.MH::invokeExact (7 bytes) inline (hot) @ 3 o.j...Linker::testMetaclass (17 bytes) inline (hot) @ 5 o.j...getMetaClass (5 bytes) inline (hot) @ 14 j.l.invoke.MH::invokeExact (10 bytes) inline (hot) @ 31 j.l.invoke.MH::invokeExact (10 bytes) inline (hot) @ 6 $file::method__0$RUBY$stub (7 bytes) inline (hot) どちらもOKならリンク済みMHを呼び出し
  • 84. fib(n - 2) + fib(n - 1) 6. 算術演算呼び出し display if (x >= 5) elapsed = msec * 1000.0 適用先: 右辺が整数、小数の算術演算 ● 右辺のunboxをショートカットする 呼び出しの型: (ctx;self)Object &guardWithTest:左辺がFixnumならショートカット &drop(ctx):引数を1つ落とす &test(self):左辺は整数か &fixnumMinusOne(ctx, self):ターゲット &invoke(ctx, self, value):直接呼び出し
  • 85. 算術演算呼び出しのインライン化 $file::method__0$RUBY$target (14 bytes) @ 8 j.l.invoke.MH::invokeExact (33 bytes) inline (hot) @ 5 j.l.invoke.MH::invokeExact (7 bytes) inline (hot) @ 3 o.j...MathLinker::fixnumTest (20 bytes) inline (hot) @ 8 o.j.Ruby::isFixnumReopened (5 bytes) inline (hot) @ 12 j.l.invoke.MH::invokeExact (10 bytes) inline (hot) @ 29 j.l.invoke.MH::invokeExact (7 bytes) inline (hot) @ 29 j.l.invoke.MH::invokeExact (11 bytes) inline (hot) @ 7 o.j...fixnumOperatorFail (109 bytes) never executed @ 3 o.j...Linker::fixnum_op_minus_one (9 bytes) inline (hot) @ 5 o.j.RubyFixnum::op_minus_one (35 bytes) inline (hot)
  • 86. 算術演算呼び出しのインライン化 $file::method__0$RUBY$target (14 bytes) 左辺はFixnumか? @ 8 j.l.invoke.MH::invokeExact (33 bytes) inline (hot) @ 5 j.l.invoke.MH::invokeExact (7 bytes) inline (hot) @ 3 o.j...MathLinker::fixnumTest (20 bytes) inline (hot) @ 8 o.j.Ruby::isFixnumReopened (5 bytes) inline (hot) @ 12 j.l.invoke.MH::invokeExact (10 bytes) inline (hot) @ 29 j.l.invoke.MH::invokeExact (7 bytes) inline (hot) @ 29 j.l.invoke.MH::invokeExact (11 bytes) inline (hot) @ 7 o.j...fixnumOperatorFail (109 bytes) never executed @ 3 o.j...Linker::fixnum_op_minus_one (9 bytes) inline (hot) @ 5 o.j.RubyFixnum::op_minus_one (35 bytes) inline (hot) -1専用メソッドを呼び出す
  • 87. #jt12_s204 JRuby + InvokeDynamic 性能評価 InvokeDynamic機能の活用
  • 88. マイクロベンチマーク ※高さはJava 7非indyを1としたときの速度比率。高いほうが速い。 ※個々のパターンの処理のみを繰り返しループして測定。 その他リテラル インスタンス変数 算術演算 文字列リテラル 擬似定数 メソッド呼び出し 全て
  • 90. #jt12_s204 Java SE 7 InvokeDynamic 動的型付け言語にとっては革命的 複雑だが、言語処理系が自身で最適化するより楽 → 以後、最適化はJVMに任せる方向へ InvokeDynamic機能の適用対象候補 ● プロファイラ・デバッガ ● 関数合成によるロジック再利用 ● etc.