These are chat archives for Constellation/iv

16th
Apr 2014
iseki
@iseki-masaya
Apr 16 2014 10:22
初歩的な質問になってしまうのですが、deoptimizationは何で必要なのですか?
compile済みのコードでは扱えない型が来てしまった場合、baseline(or interpreter)まで落としてしまうという方法では何か問題があるんですか?
Yusuke Suzuki
@Constellation
Apr 16 2014 11:34
guard の check が外れた時に, 全く同じ場所に method の途中から移らなければいけないからです.
例えば, map の guard を入れていて, その type に specialized した code を走っている時, guard が外れると, 以降のコードは type specialized なので実行できないです. そこでgeneric なコードのちょうど該当する部分にうまく移る (具体的には method のどまんなかからどまんなかへ) 必要があります.
このとき, optimized code は register の中身は boxing していないでしょうし (type specialized なので boxing の必要はない),
stack layout も異なります.
inlining していたとして, inline 先の code のどまんなかで guard が外れれば,
generic code に戻った時には inline した関数を, ちゃんと呼び出してここまで来たかのような stack layout にしておく必要があります.
これが deoptimization です.
iseki
@iseki-masaya
Apr 16 2014 11:37
説明ありがとうございます。
メソッドコンパイルの場合でもdeoptimizationは必要になりますか?
Yusuke Suzuki
@Constellation
Apr 16 2014 11:42
Method JIT (currently called as breaker compiler), の場合は, 基本的に generic path を作成して, slow path / fast path を opcode 毎に作るので, 全体として generic なコードになります.
このため, guard が入りません. というのも, ある guard を入れた後, その情報 (type specialized) をつかって型を決め打った code を吐いていないからです.
このため, register の値はすべて boxed です.
iseki
@iseki-masaya
Apr 16 2014 12:11

あー、だんだんと理解できてきました。
今回のLLVMを用いて作成するJITはTracingJITであるという理解であってますか。そして、TracingJITの目的はHot loopの高速化なので以下のようなコードを高速化します。

function f(x) {
    return 1 + x;
}

//しきい値をこえるような大きなsizeのarray
var arr = [1,2,3,...,1.5];
for (var i=0; i<arr.length; ++i) {
    f(arr[i]);
}

arrは十分大きなsizeの配列で最後の要素がdoubleで後はintであるとします。ループの途中でOSRで飛んでintに最適化されたコードを生成し、以降はそのコードを使って実行します。しかし、最後にdoubleが入力されてきてguardがfailしてしまい、deoptimizationする必要がある。
この理解であってますか?

Yusuke Suzuki
@Constellation
Apr 16 2014 13:54
はい, そのとおりです.
iseki
@iseki-masaya
Apr 16 2014 13:59
ありがとうございます。