Kink: プロトタイプベース言語で
の invokedynamic (構想)
@miyakawa_taku
2012-02-22
JJUG Night Seminar
1



要旨
• Kink という JVM 言語を作っています
• JavaScript や Lua と同様に、クラスのないオブ
  ジェクト指向言語です
• invokedynamic がどこに使えるものか考えて
  みました
2



論点
• Kink の紹介
  – クラスのない世界
  – なんでもメソッド
  – 気になる性能は?
• invokedynamic の使い所
  – スロットアクセスの最適化
  – SwitchPoint で実行モード切り替え
3



論点
• Kink の紹介
  – クラスのない世界
  – なんでもメソッド
  – 気になる性能は?
• invokedynamic の使い所
  – スロットアクセスの最適化
  – SwitchPoint で実行モード切り替え
4



クラスのない世界
• クラスはなく値だけがある
• データもメソッドもいきなり値のスロット
  (≒フィールド) に突っ込む

   &DOG = value
   DOG.&bark = { 'Bow!' }
   printline(DOG.bark) # => Bow!
5



クラスのかわりに親
• 自分自身がスロットを持っていなかったら親
  から取ってくる
• 親のことをプロトタイプとも言う

  &PROTODOG = value('bark' : { 'Bow!' })
  &DOG = PROTODOG.child
  printline(DOG.bark) # => Bow!
6



親/子関係の一つ覚え
• つまり子は親の名前空間を継承する
• 様々な仕組みを親/子関係で実現する
 – クラス / インスタンス (のようなもの)
 – 親クラス / 子クラス (のようなもの)
 – 外側のスコープ / 内側のスコープ
7



なんでもメソッド
•   足し算も掛け算もメソッド
•   条件分岐もメソッド
•   代入もメソッド
•   引数渡しもメソッド
8



足し算も掛け算もメソッド
• 演算子はメソッドの構文糖

      (TOP + BOTTOM) * HEIGHT


  TOP.plus(BOTTOM).multiply(HEIGHT)
9



条件分岐もメソッド
• if-then-else は bool 値のメソッド

    (N % 2 == 0).then { 'even' } { 'odd' }



    (N % 2 == 0).then({ 'even' } { 'odd' })
10



代入もメソッド
• スロットへの代入はスロットのメソッド

         &NUM = 42



       &NUM.assign(42)
11



引数渡しもメソッド
• 引数渡しは仮引数列 (スロットのリスト) のメ
  ソッド

       &diff = { (&X &Y) X - Y }



   &diff = { [&X &Y] = _args X - Y }
12



気になる性能は?
• tarai(13 6 0) (たらい回し関数、竹内関数) で
  マイクロベンチマーク

   &tarai = { (&X &Y &Z)
     (X <= Y).then {
        Y
     }{
        tarai(tarai(X - 1 Y Z) tarai(Y - 1 Z X) tarai(Z - 1 X Y))
     }
   }
   printline(tarai(~ argv.map { __.int }))
13



結果: bc よりは速い
GNU bc 1.06.95
Kink 2012-02-19
   C Ruby 1.8.7
       scm 5e5
   Python 2.6.6
    mawk 1.3.3
   C Ruby 1.9.2
      Lua 5.0.3
   Groovy 1.7.0
    JRuby 1.6.6

                  0   20   40   60   80   100   120   140   160
                                                            秒
14



つまりこんな言語
• クラスがなくて値だけがある
• 代入も制御構造もメソッド呼び出し
• 速くするのはかなり難渋する

• あと、末尾呼び出しでスタックオーバーフロー
  が起きないことを保証しています
15



論点
• Kink の紹介
  – クラスのない世界
  – なんでもメソッド
  – 気になる性能は?
• invokedynamic の使い所
  – スロットアクセスの最適化
  – SwitchPoint で実行モード切り替え
16



処理系の作り
• プログラムはJVM バイトコードにせず、「評価
  器」を作って実行する (cf. SICP 4章)

                           call                  call
&loop.do {
  print("twift!")   slot          proc    slot          proc
  loop
}                                 chunk                 chunk

  プログラム             抽象構文木                        評価器
17



invokedynamic の使い所
• そもそもJVM バイトコードにしないので、メソッ
  ド呼び出しがいきなり invokedynamic になるこ
  とはない
• ただし、高速化のためにバイトコード生成を
  使っている所はあって、そこに invokedynamic
  が使えるかも
18



スロットアクセスの最適化
• スロットアクセスを速くするため、スロット集合
  のクラスを実行時に生成している
• 本来はアクセス元のコードでキャッシュを効か
  せて速くする (現在は未実装)
• ここに invokedynamic が使えそう
                    DOG
    DOG.bark
               bark { "Bow!" }
               jump { "Pong!" }
   ここに使う
19



スロットアクセスの最適化
• キャッシュヒット → フィールドを直接取得
• キャッシュミス → フォールバック
• MethodHandles#guardWithTest が使えそう

   if (slots.getClass() == #cachedClass) {   test
      return ((#cachedClass) slots).bar;     target
   } else {
      deoptimize();
                                             fallback
      return slots.get("bar");
   }
20



SwitchPoint で実行モード切り替え
• スロットやリストへの代入はメソッド呼び出し
• 毎回メソッドを呼ぶと大変なコストなので、可
  能な限りショートカット処理している
• ここで SwitchPoint#guardWithTest が使えそう

    if 代入メソッドは再定義されていない?
       ショートカット処理
    else
       真面目にメソッド呼び出し
21



SwitchPoint で実行モード切り替え
• SwitchPoint は MethodHandle のファクトリ
  – SP.guardWithTest(target, fallback):MethodHandle
  – 通常は target が実行される
  – SwitchPoint が invalidate されると、それ以降は
    fallback が実行される
• 処理の実行モードを切り替えるのに使える
  – 代入処理の MH を SwitchPoint で生成
  – 代入メソッドが再定義されたら invalidate
22



invokedynamic の使い所 (rep)
• クラスのない言語でも充分使い所はある
 – スロットアクセスの最適化
 – 実行モード切り替え
23



参考
• Kink Programming Language
  – http://code.google.com/p/kink-lang/
• V8 JavaScript Engine
  – http://code.google.com/p/v8/
  – スロットアクセスを最適化する仕組みのパクリ元
    (Hidden Class)
• An efficient implementation of SELF
  – http://dl.acm.org/citation.cfm?id=74884

Kink: invokedynamic on a prototype-based language