SlideShare a Scribd company logo
1 of 37
Download to read offline
OpenJDK HotSpot C1Compiler Overview
              version 1.0




           Author nothingcosmos




            November 09, 2011
Contents
Welcome to OpenJDK Internals's documentation!    1
    OpenJDK HotSpot Client Compiler Overview     1
        タイトル                                     1
        自己紹介                                     1
        OpenJDK キーワード                            1
        HotSpotの見どころ1                            1
        HotSpotの見どころ2                            1
        本日紹介するC1 Compiler                        2
        C1コンパイラの構成                               3
    コンパイル前の動作                                    4
        JITコンパイラ                                 4
        JITコンパイラが呼ばれる仕組み                         5
        JITコンパイルの入出力                             6
        JITコンパイルする条件                             6
        JITコンパイルする際のしきい値                         9
    C1コンパイラの内部構造                                10
        大まかなコンパイルの概要                            10
        コンパイラ全体の制御                              10
        BytecodeからHIRへの変換                       11
        if_icmpXXの変換                            12
        invokeの変換                               13
        dependency                              14
        プロファイラ                                  18
        HIR から LIR への変換                         19
    C1コンパイラのHIR最適化                              20
        eliminate_conditional_expressions       20
        GlobalValueNumbering                    21
        EscapeAnalysis                          22
    C1コンパイラのLIR最適化                              22
        EdgeMoveOptimizer                       22
        ControlFlowOptimizer                    22
    sample code factIf                          23
    sample code factFor                         28
    参考文献                                        32
Indices and tables                              33
Welcome to OpenJDK Internals's documentation!



 Welcome to OpenJDK Internals's documentation!
 Contents:


 OpenJDK HotSpot Client Compiler Overview

 タイトル
 OpenJDK HotSpot Client Compiler Overview
 第4回JVMソースコードリーディングの会
 nothingcosmos<nothingcosmos@gmail.com>
 http://nothingcosmos.blog52.fc2.com/
 http://nothingcosmos.wiki.fc2.com/


 自己紹介
 HN:nothingcosmos
 元コンパイラ屋のソフトウェアエンジニア 現在は金融系SIer
 趣味で、LLVMを読んだり、OpenJDKを読んだり、UNIXv6を読んだりしています。
 先週は、箱根でLions'Commentary on UNIX勉強会(2011秋合宿)へ参加してました。


 OpenJDK キーワード
    • HotSpotコンパイラ
    • C1(Client)/C2(Server)コンパイラ
    • JIT
    • Adaptive Compilation

        • Deoptimize 脱最適化
    • 中間表現/中間言語

 HotSpotの見どころ1
 一般ユーザからみたコンパイラの見どころ

    • ...
 Scalaユーザからみたコンパイラの見どころ

    • Scalaでは細かいオブジェクトをたくさん作るので、 EscapeAnalysisがあると全部レジスタやスタックに乗る
     という話を以前kmizuさんに聞いた記憶が...
     毎回ヒープに割り付けないので、高速

 HotSpotの見どころ2
 私個人は、

    • コンパイラ内部の中間言語構造とアーキテクチャ
    • 大した最適化してないのに速いコードを吐くHotSpot Client Compiler




1
本日紹介するC1 Compiler




      • 適応的コンパイル Adaptive Compilation

             • JITコンパイラ/脱最適化のコントロール
           • Profiling/Tracingの取得方法と活用方法
      • HotSpot特有の最適化技術

             • EscapeAnalysis/ClassHierarchyAnalysis
             • 複数アーキテクチャへの対応方法
             • OpenJDK7の最適化のバグ

本日紹介するC1 Compiler




OpenJDKのHotSpot Glossary of Termsより抜粋
    Fast, lightly optimizing bytecode compiler.
    Performs some value numbering, inlining, and class analysis.
    Uses a simple CFG-oriented SSA "high" IR, a machine-oriented "low" IR,
    a linear scan register allocation, and a template-style code generator.

      • ValueNumbering

             • 値番号付けというSSA形式を利用した最適化のアルゴリズムの名前. 冗長な式を削除する
      • inlining

           • インライン展開
      • class analysis

           • CHA(ClassHierachyAnalysis). クラス解析 仮想関数呼出の呼び出し先を特定する際に活躍する
      • CFG-oriented SSA

             • CFG ControlFlowGraph
             • SSA StaticSingleAssignment form
      • IR

            • Intermediate Representation コンパイラ独自の中間表現
      • linear scan register allocation



2
C1コンパイラの構成


          • リニアスキャンというレジスタ割り付けのアルゴリズム
     • template-style code generator

         • asmの生成はあまり頑張らない。LIRからシーケンシャルに生成




C1コンパイラの構成
hotspot/src/share/vm

     • c1 <-- C1コンパイラの本体
     • compiler <-- コンパイラの抽象クラス
   • runtime <-- JVMのruntime部分
hotspot/src/share/vm/c1
C1コンパイラ 全体で36kstep
top5
    c1_LinerScan 7700step LinerScanでレジスタ割り付け
    c1_LIR        4300step LIR(Low-Level IRの定義)
    c1_GraphBuilder 4200step BytecodeからHIRへの変換
    c1_LIRGenerator 3500step HIRからLIRへの変換
    c1_Instruction 3300step HIR(High-Level IR)の定義

vm/c1/*
    c1_CFGPrinter.cpp          <-- -XX:+PrintCFGToFile オプションを指定時、
    c1_CFGPrinter.hpp             中間表現のHIRやLIRをxmlで出力。c1visualizerで解析する
    c1_Canonicalizer.cpp       <-- HIRへ変換する際に正規化する
    c1_Canonicalizer.hpp          c1_GraphBuilderから呼ばれる
    c1_CodeStubs.hpp           <-- LIRやAssemblerで挿入される、JVMのciXX/runtime向けのStub
    c1_Compilation.cpp         <-- C1コンパイラのコントローラー Driver???
    c1_Compilation.hpp
    c1_Compiler.cpp           <-- C1コンパイラの本体
    c1_Compiler.hpp
    c1_Defs.cpp             <-- architecture依存の各種定義ファイル レジスタとか
    c1_Defs.hpp
    c1_FpuStackSim.hpp          <-- architecture依存のFPUStackのシミュレータの定義ファイル
    c1_FrameMap.cpp            <-- architecture依存のFrameMapや仮想レジスタやCallingConvension
    c1_FrameMap.hpp
    c1_GraphBuilder.cpp        <-- BytecodeからHIRへの変換
    c1_GraphBuilder.hpp           各種最適化も行う(inlining, devirtualize, canonicalize
    c1_IR.cpp              <-- IRの定義
    c1_IR.hpp                  HIR/LIR/BB/各種helperを統合したIRという名のDescripter
    c1_Instruction.cpp        <-- HIRの定義や、IRクラスのUtility
    c1_Instruction.hpp
    c1_InstructionPrinter.cpp <-- HIRのprinter 見やすいように情報を絞って整形して表示する
    c1_InstructionPrinter.hpp
    c1_LIR.cpp              <-- LIRの定義
    c1_LIR.hpp
    c1_LIRAssembler.cpp         <-- LIRからAsmのemitter兼helper Asmのコード生成
    c1_LIRAssembler.hpp
    c1_LIRGenerator.cpp         <-- HIRからLIRへの変換



3
コンパイル前の動作


    c1_LIRGenerator.hpp         命令選択、レジスタ割り付け、LIRレベルの最適化も行う。
    c1_LinearScan.cpp      <-- LinearScanレジスタ割り付け
    c1_LinearScan.hpp
    c1_MacroAssembler.hpp     <-- architecture依存のAsm出力用マクロ(Assember向けpsuedo code)
    c1_Optimizer.cpp       <-- HIR向け各種最適化 Eliminate (const expr|blocks|null checks)
    c1_Optimizer.hpp
    c1_Runtime1.cpp        <-- C1コンパイラのRuntime JVM本体のruntimeとの橋渡し
    c1_Runtime1.hpp
    c1_ValueMap.cpp         <-- HIR向け最適化 ValueNumberingの本体
    c1_ValueMap.hpp
    c1_ValueSet.cpp        <-- HIR向けADT @todo
    c1_ValueSet.hpp
    c1_ValueStack.cpp      <-- HIR向けADT @todo
    c1_ValueStack.hpp
    c1_ValueType.cpp        <-- C1コンパイラ内部のIR向け型定義
    c1_ValueType.hpp
    c1_globals.cpp        <-- C1コンパイラ向けのオプション定義
    c1_globals.hpp

※ architecture依存と書いたものは、hotspot/src/cpu/XXX/vm の下に本体がいる。
※ architectureは、x86_32/x86_64 sparc zero がある


コンパイル前の動作

JITコンパイラ
JVMは、最初bytecodeをclassloaderが呼び出した後、インタプリタ実行を行う。
インタプリタ実行中にプロファイルを行い、条件を満たしたらJITコンパイルする




JITコンパイルは、コンパイラの抽象クラス経由で操作する。 コンパイラクラスは3種類ある.
C1/C2/Shark
C1コンパイラ
      -clientオプション指定時のコンパイラ
      コンパイル時間が短く、メモリ使用量もそこそこ。 大した最適化をしない割にそこそこ高速に動作するコード
      を生成するのが特徴
      JVM間の比較では、ベンチマーク結果がそこそこ高い。
C2コンパイラ
      -serverオプション指定時のコンパイラ。今回は扱わない。
      コンパイル時間はそこそこ長く、C1より高速に動作するコードを生成する。 また、コンパイル時のメモリも
      大きく消費する。
      詳細は、vm/opto参照。C1とは中間言語が異なり、Idealと呼ばれる中間言語。
Sharkコンパイラ
      使い方はまだちゃんと調べてない。




4
JITコンパイラが呼ばれる仕組み


       LLVMと連携してJITコンパイルを行う. JITコンパイラをC1/C2ではなく、LLVMを使うということ。JVMの制
       御はそのまま。
       Sharkは、method単位でBytecodeをBitcodeに変換したのち、 LLVMに渡してJITコンパイルする。
       LLVMにBitcodeを渡す際に何も小細工しないので、脱仮想化とかEscapeAnalysisとかさっぱり LLVMのBitcod
       eにMetadataを埋め込んで、 (たとえば、このcallはこのメソッドに脱仮想化候補だとか、allocaはstack/regi
       ster割り付け可能だとか) LLVMのJITコンパイラ起動時、上記metadata用最適化パスをオプションで渡せば連
       携できるはず。
       いろいろと夢広がる。 現在は、対応アーキテクチャを増やすために使っている ex) ARM PowerPC PTX CBac
       kend
       LLVM 3.0 のReleaseNoteから、Sharkの連携やIcedTeaとの連携のことがかかれているので、 興味があるかた
       はLLVMのページへ


JITコンパイラが呼ばれる仕組み
compileBrokerがJITコンパイラを生成し、メソッド単位でコンパイルする
compiler::compile_method()
    compileBroker
     compiler/abstructCompiler
       compile_method(ciEnv*, ciMethod*, int entry_bci)

条件を満たしたときにJITコンパイラを生成し、メソッド単位でJITコンパイルを行う。

      • 条件を満たしたときに ... vm/runtime/compilationPolicy
   • JITコンパイラを生成 ... vm/compiler/compileBroker
JITコンパイラは、JVMがメモリを確保して、別スレッドでコンパイルブローカーに処理を移譲する。
JVMTIを使うので、スレッドが切れていて、処理が追いにくい。
また、スレッド並列で、インタプリタと並行してJITコンパイルは走るが、
-Xbatchオプションを指定すると、JITコンパイル中にインタプリタ実行を停止することができる。
compileBroker::compilation_init()
    // ------------------------------------------------------------------
    // CompileBroker::compilation_init
    //
    // Initialize the Compilation object
    void CompileBroker::compilation_init() {
     _last_method_compiled[0] = '0';

    #ifndef SHARK
     // Set the interface to the current compiler(s).
     int c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple);
     int c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization);
    #ifdef COMPILER1
     if (c1_count > 0) {
       _compilers[0] = new Compiler();
     }
    #endif // COMPILER1

    #ifdef COMPILER2
     if (c2_count > 0) {
       _compilers[1] = new C2Compiler();
     }
    #endif // COMPILER2

    #else // SHARK
     int c1_count = 0;



5
JITコンパイルの入出力


     int c2_count = 1;

     _compilers[1] = new SharkCompiler();
    #endif // SHARK




JITコンパイルの入出力
JVMのJITコンパイラは、ciMethodクラスが入力
compiler::compile_method()
    compiler/abstructCompiler
     compile_method(ciEnv*, ciMethod*, int entry_bci)

JITコンパイラの出力の形式は複数存在する。

      • method->codeの書き換え
   • もし書き換え対象のメソッドを今実行中だったら。。。
JITコンパイルの入り口のメソッド
CompileBroker::compile_method_base()
    void CompileBroker::compile_method_base(methodHandle method,
                                 int osr_bci,
                                 int comp_level,
                                 methodHandle hot_method,
                                 int hot_count,
                                 const char* comment,
                                 TRAPS) {


JITコンパイルする条件
JVMのインタプリタ実行中にprofileを行い、 下記に示すカウンタをカウントアップする。

      • invocation count

          • メソッドの呼び出し回数をカウント
      • backward branch count

        • ループの実行回数をカウント
invocation countのカウントアップ:



6
JITコンパイルの入出力


    bytecodeInterpreter.cpp::BytecodeInterpreter::run()

    case method_entry: {
     THREAD->set_do_not_unlock();
     // count invocations
     assert(initialized, "Interpreter not initialized");
     if (_compiling) {
       if (ProfileInterpreter) {
         METHOD->increment_interpreter_invocation_count();
       }
       INCR_INVOCATION_COUNT;
       if (INVOCATION_COUNT->reached_InvocationLimit()) {
         CALL_VM((void)InterpreterRuntime::frequency_counter_overflow(THREAD, NULL), handle_exception);

          // We no longer retry on a counter overflow

          // istate->set_msg(retry_method);
          // THREAD->clr_do_not_unlock();
          // return;
         }
         SAFEPOINT;
     }

     if ((istate->_stack_base - istate->_stack_limit) != istate->method()->max_stack() + 1) {
       // initialize
       os::breakpoint();
     }

//memo frequency_counter_overflowでJITコンパイラを呼ぶはず
backward branch countのカウントアップ
    CASE(_goto):
    {
      int16_t offset = (int16_t)Bytes::get_Java_u2(pc + 1);
      address branch_pc = pc;
      UPDATE_PC(offset);
      DO_BACKEDGE_CHECKS(offset, branch_pc);
      CONTINUE;
    }

    CASE(_goto_w):
    {
      int32_t offset = Bytes::get_Java_u4(pc + 1);
      address branch_pc = pc;
      UPDATE_PC(offset);
      DO_BACKEDGE_CHECKS(offset, branch_pc);
      CONTINUE;
    }

    #define DO_BACKEDGE_CHECKS(skip, branch_pc)
    if ((skip) <= 0) {                                                       
      if (UseLoopCounter) {                                                    
        bool do_OSR = UseOnStackReplacement;                                          
        BACKEDGE_COUNT->increment();                                                
        if (do_OSR) do_OSR = BACKEDGE_COUNT->reached_InvocationLimit();                          
        if (do_OSR) {                                                        
          nmethod* osr_nmethod;                                                  
          OSR_REQUEST(osr_nmethod, branch_pc);                                         
          if (osr_nmethod != NULL && osr_nmethod->osr_entry_bci() != InvalidOSREntryBci) {           
            intptr_t* buf = SharedRuntime::OSR_migration_begin(THREAD);                      



7
JITコンパイルの入出力


                 istate->set_msg(do_osr);                                          
                 istate->set_osr_buf((address)buf);                                    
                 istate->set_osr_entry(osr_nmethod->osr_entry());                          
                 return;                                                   
             }                                                         
         }                                                             
        } /* UseCompiler ... */                                                
        INCR_INVOCATION_COUNT;                                                         
        SAFEPOINT;                                                             
    }

インタプリタがprofileのカウンタを更新する様子
gdb stack trace
    Breakpoint 5, NonTieredCompPolicy::reset_counter_for_invocation_event (this=0x807a738, m=...)
     at /home/elise/language/openjdk6/hotspot/src/share/vm/runtime/compilationPolicy.cpp:189
     189 m->invocation_counter()->set_carry();
     (gdb) up
    #1 0x004cbdd5 in SimpleCompPolicy::method_invocation_event (this=0x807a738, m=..., __the_th
     at /home/elise/language/openjdk6/hotspot/src/share/vm/runtime/compilationPolicy.cpp:394
     394 reset_counter_for_invocation_event(m);
     (gdb)
    #2 0x004cba19 in NonTieredCompPolicy::event (this=0x807a738, method=..., inlinee=..., branc
     comp_level=CompLevel_none, __the_thread__=0x806d000)
     at /home/elise/language/openjdk6/hotspot/src/share/vm/runtime/compilationPolicy.cpp:323
     323      method_invocation_event(method, CHECK_NULL);
     (gdb)
    #3 0x005dafd2 in InterpreterRuntime::frequency_counter_overflow_inner (thread=0x806d000, br
     at /home/elise/language/openjdk6/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp:854
     854 nmethod* osr_nm = CompilationPolicy::policy()->event(method, method, branch_bci, bci, CompLevel_none,
     (gdb)
    #4 0x005daced in InterpreterRuntime::frequency_counter_overflow (thread=0x806d000, branch_b
     at /home/elise/language/openjdk6/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp:826
     826 nmethod* nm = frequency_counter_overflow_inner(thread, branch_bcp);
     (gdb)
    #5 0xb5fef92c in ?? ()
     (gdb)

//interpreterのgoto命令実行時にカウントアップ
//memo OSR_REQESTマクロの中で、frequency_counter_overflow()を呼び出し
JITコンパイラが呼ばれるのは、2つのケース
対象のメソッドの呼び出し回数が規定回数以上になった場合

        • 通常のJITコンパイル。メソッド単位でJITコンパイルする。
  次回呼ばれた際にインタプリタではなく、JITコンパイルしたコードを実行する
対象のループのバックエッジの通過回数が規定回数以上になった場合

        • 現在実行中のメソッドをJITコンパイルする。
         現在実行中のメソッドなので、インタプリタからJITしたコードへ遷移するのが難しい
         インタプリタ実行中からJITしたコードへ遷移する技術をOnStackReplacementと呼ぶ。
         おもにsafepointを設けて(分岐の前や、分岐の集合地点)
         インタプリタ実行中のFrameとJITコンパイルしたコードのFrameを記録、計算し、
         遷移できるようにテーブルを作成するはず
//OnStackReplacementは、runtime/sharedRuntime.cpp::SharedRuntime::OSR_migration_begin()
//詳細は"コンパイラとバーチャルマシン"っていう書籍が図入りで説明している



8
JITコンパイルする際のしきい値


JITコンパイルする際のしきい値
JITコンパイルのしきい値は、clientコンパイラの場合、2000回, serverコンパイラの場合、15000回のはず。
JITコンパイルのしきい値は、CompLevel で計算方法が異なるらしい
CompLevel_simple or CompLevel_full_optimization or CompLevel_limited_profile or CompLevel_full_profil
e
オプション:

  • -XX:CompileThreshold=xxx
デフォルト:

      • Tier3CompileThreshold 2000
   • Tier4CompileThreshold 15000
compile_methodが呼ばれた際のstack trace
gdb stack trace
    // topからdownしていきます
    #6 0xb5fef92c in ?? () <-- template intepreter経由なのでこれ以上終えない
     (gdb) down
    #5 0x005daced in InterpreterRuntime::frequency_counter_overflow (thread=0x806d000, branch_b
     at /home/elise/language/openjdk6/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp:826
     826 nmethod* nm = frequency_counter_overflow_inner(thread, branch_bcp);
     (gdb)
    #4 0x005dafd2 in InterpreterRuntime::frequency_counter_overflow_inner (thread=0x806d000, br
     at /home/elise/language/openjdk6/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp:854
     854 nmethod* osr_nm = CompilationPolicy::policy()->event(method, method, branch_bci, bci, CompLevel_none,
     (gdb)
    #3 0x004cba19 in NonTieredCompPolicy::event (this=0x807a738, method=..., inlinee=..., branc
     comp_level=CompLevel_none, __the_thread__=0x806d000)
     at /home/elise/language/openjdk6/hotspot/src/share/vm/runtime/compilationPolicy.cpp:323
     323      method_invocation_event(method, CHECK_NULL);
     (gdb)
    #2 0x004cbe50 in SimpleCompPolicy::method_invocation_event (this=0x807a738, m=..., __the_th
     at /home/elise/language/openjdk6/hotspot/src/share/vm/runtime/compilationPolicy.cpp:402
     402                           m, hot_count, comment, CHECK);
     (gdb)
    #1 0x004cf34e in CompileBroker::compile_method (method=..., osr_bci=-1, comp_level=1, hot_m
     comment=0x94b7f6 "count", __the_thread__=0x806d000)
     at /home/elise/language/openjdk6/hotspot/src/share/vm/compiler/compileBroker.cpp:1084
     1084     compile_method_base(method, osr_bci, comp_level, hot_method, hot_count, comment, CHECK_0);
     (gdb)
    #0 CompileBroker::compile_method_base (method=..., osr_bci=-1, comp_level=1, hot_method=...
     comment=0x94b7f6 "count", __the_thread__=0x806d000)
     at /home/elise/language/openjdk6/hotspot/src/share/vm/compiler/compileBroker.cpp:840
     840 if (!_initialized ) {

InterpreterInvocationLimitとInterpreterBackwardBranchLimitの設定
    void InvocationCounter::reinitialize(bool delay_overflow) {
     // define states
     guarantee((int)number_of_states <= (int)state_limit, "adjust number_of_state_bits");
     def(wait_for_nothing, 0, do_nothing);
     if (delay_overflow) {
       def(wait_for_compile, 0, do_decay);
     } else {
       def(wait_for_compile, 0, dummy_invocation_counter_overflow);
     }

     InterpreterInvocationLimit = CompileThreshold << number_of_noncount_bits;



9
C1コンパイラの内部構造


     InterpreterProfileLimit = ((CompileThreshold * InterpreterProfilePercentage) / 100)<< number_of_noncount_bit

     // When methodData is collected, the backward branch limit is compared against a
     // methodData counter, rather than an InvocationCounter. In the former case, we
     // don't need the shift by number_of_noncount_bits, but we do need to adjust
     // the factor by which we scale the threshold.
     if (ProfileInterpreter) {
       InterpreterBackwardBranchLimit = (CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercen
     } else {
       InterpreterBackwardBranchLimit = ((CompileThreshold * OnStackReplacePercentage) / 100) << number_of_non
     }

ちなみに、clientの場合
InterpreterInvocationLimit = 12000
InterpreterBackwardBranchLimit = 111960
serverの場合
InterpreterInvocationLimit = 80000
InterpreterBackwardBranchLimit = 10700
clientコンパイラのしきい値って、メソッド呼び出しが1500回で、OnStackReplacementが14000回じゃないの?


C1コンパイラの内部構造

大まかなコンパイルの概要




method単位で、BytecodeからHIRへの変換
HIRからLIRへの変換
LIRからMachine codeへの変換


コンパイラ全体の制御
c1_Compiler.cpp コンパイルの入り口
 // 入力はciMethond* method <-- bytecode method単位
 void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci)
  compile_method()

c1_Compilation.cpp コンパイラの全体制御
 Compilation::compile_method()
  method()->break_at_execute()
  compile_java_method()
  install_code(frame_size)

 Compilation::compile_java_method()
  build_hir()
   _hir = new IR()
   _hir->optimize()
   _hir->split_critical_edges()
   _hir->compute_code()
   GlobalValueNumbering gvn(_hir)
   _hir->compute_use_counts()



10
BytecodeからHIRへの変換


     FrameMap()

     emit_lir()
      LIRGenerator gen()
      hir()->iterate_linear_scan_order()
      LinearScan allocator = new LinearScan()
      allocator->do_linear_scan()
        compute_local_live_sets()
        compute_global_live_sets()
        build_intervals()
        allocate_registers()
        resolve_data_flow()
        propagate_spill_slots()
        eliminate_spill_moves()
        assign_reg_num()
        allocate_fpu_stack()

       EdgeMoveOptimizer::optimize(ir()->code())
       ControlFlowOptimizer::optimize(ir()->code())

     emit_code_body()
      setup_code_buffer()
      _masm = new C1_MacroAssembler()
      LIR_Asssembler lir_asm()
      lir_asm.emit_code()
      emit_code_epilog()
        generate code for deopt handler


BytecodeからHIRへの変換
BytecodeからHIRへの変換は、大体1Bytecodeにつき、1HIRに変換する
IR()
 IR()->IRScope()->XHandlers()
   IRScope()
     _requires_phi_function
   IR()->IRScope()->IRScope()
     _start = GraphBuilder gm() constructor

 GraphBuilder()
  GraphBuilder::iterate_all_blocks()
    GraphBuilder::iterate_bytecodes_for_block(int bci)

Bytecodeの各命令ごとに処理をわけているところ
GraphBuilder::iterate_bytecodes_for_block(int bci):
 _skip_block = false;
 assert(state() != NULL, "ValueStack missing!");
 ciBytecodeStream s(method());
 s.reset_to_bci(bci);
 int prev_bci = bci;
 scope_data()->set_stream(&s);
 // iterate
 Bytecodes::Code code = Bytecodes::_illegal;
 bool push_exception = false;

 if (block()->is_set(BlockBegin::exception_entry_flag) && block()->next() == NULL) {
   // first thing in the exception entry block should be the exception object.
   push_exception = true;
 }


11
if_icmpXXの変換




 while (!bailed_out() && last()->as_BlockEnd() == NULL &&
      (code = stream()->next()) != ciBytecodeStream::EOBC() &&
      (block_at(s.cur_bci()) == NULL || block_at(s.cur_bci()) == block())) {
  assert(state()->kind() == ValueStack::Parsing, "invalid state kind");

     // Check for active jsr during OSR compilation
     if (compilation()->is_osr_compile()
         && scope()->is_top_scope()
         && parsing_jsr()
         && s.cur_bci() == compilation()->osr_bci()) {
       bailout("OSR not supported while a jsr is active");
     }

     if (push_exception) {
       apush(append(new ExceptionObject()));
       push_exception = false;
     }

     // handle bytecode
     switch (code) {
     case Bytecodes::_nop         : /* nothing to do */ break;
     case Bytecodes::_aconst_null : apush(append(new Constant(objectNull             ))); break;
     case Bytecodes::_iconst_m1      : ipush(append(new Constant(new IntConstant    (-1)))); break;
     case Bytecodes::_iconst_0      : ipush(append(new Constant(intZero            ))); break;
     case Bytecodes::_iconst_1      : ipush(append(new Constant(intOne             ))); break;
     case Bytecodes::_iconst_2      : ipush(append(new Constant(new IntConstant    ( 2)))); break;
     case Bytecodes::_iconst_3      : ipush(append(new Constant(new IntConstant    ( 3)))); break;
     case Bytecodes::_iconst_4      : ipush(append(new Constant(new IntConstant    ( 4)))); break;
     case Bytecodes::_iconst_5      : ipush(append(new Constant(new IntConstant    ( 5)))); break;
     ...
     case Bytecodes::_invokevirtual : // fall through
     case Bytecodes::_invokespecial : // fall through
     case Bytecodes::_invokestatic : // fall through
     case Bytecodes::_invokedynamic : // fall through
     case Bytecodes::_invokeinterface: invoke(code); break;

invoke命令を変換時にdevirtualize/inline展開する

     • @todo codeを追う
     • @todo devirtualizeの仕組み
     • @todo is_profile_callの仕組み

if_icmpXXの変換
if_icmpXXの変換が分かりやすい
Bytecodeのiterate
 case   Bytecodes::_if_icmpeq       : if_same(intType , If::eql); break;
 case   Bytecodes::_if_icmpne       : if_same(intType , If::neq); break;
 case   Bytecodes::_if_icmplt      : if_same(intType , If::lss); break;
 case   Bytecodes::_if_icmpge       : if_same(intType , If::geq); break;
 case   Bytecodes::_if_icmpgt       : if_same(intType , If::gtr); break;
 case   Bytecodes::_if_icmple      : if_same(intType , If::leq); break;
 case   Bytecodes::_if_acmpeq        : if_same(objectType, If::eql); break;
 case   Bytecodes::_if_acmpne        : if_same(objectType, If::neq); break;

ifの変換部




12
invokeの変換


 void GraphBuilder::if_same(ValueType* type, If::Condition cond) {
   ValueStack* state_before = copy_state_before();
   Value y = pop(type);
   Value x = pop(type);
   if_node(x, cond, y, state_before);
 }

 void GraphBuilder::if_node(Value x, If::Condition cond, Value y, ValueStack* state_before) {
  BlockBegin* tsux = block_at(stream()->get_dest());
  BlockBegin* fsux = block_at(stream()->next_bci());
  bool is_bb = tsux->bci() < stream()->cur_bci() || fsux->bci() < stream()->cur_bci();
  Instruction *i = append(new If(x, cond, false, y, tsux, fsux, is_bb ? state_before : NULL, is_bb));

     if (is_profiling()) {
       If* if_node = i->as_If();
       if (if_node != NULL) {
         // Note that we'd collect profile data in this method if we wanted it.
         compilation()->set_would_profile(true);
         // At level 2 we need the proper bci to count backedges
         if_node->set_profiled_bci(bci());
         if (profile_branches()) {
           // Successors can be rotated by the canonicalizer, check for this case.
           if_node->set_profiled_method(method());
           if_node->set_should_profile(true);
           if (if_node->tsux() == fsux) {
             if_node->set_swapped(true);
           }
         }
         return;
       }

         // Check if this If was reduced to Goto.
         Goto *goto_node = i->as_Goto();
         if (goto_node != NULL) {
           compilation()->set_would_profile(true);
           if (profile_branches()) {
             goto_node->set_profiled_method(method());
             goto_node->set_profiled_bci(bci());
             goto_node->set_should_profile(true);
             // Find out which successor is used.
             if (goto_node->default_sux() == tsux) {
               goto_node->set_direction(Goto::taken);
             } else if (goto_node->default_sux() == fsux) {
               goto_node->set_direction(Goto::not_taken);
             } else {
               ShouldNotReachHere();
             }
           }
           return;
         }
     }
 }


invokeの変換
BytecodeのinvokeXXXは、invoke()メソッドで処理する。
invokeを処理する際に、呼び出し対象が一意に定まるか判定し、
もし定まる場合は、inline展開を試行する。



13
dependency


 また、invokevirtualやinvokeinterfaceのdevirtual化(invokespecialとみなす)を行い、 積極的にinline展開を試行
 する
 invoke
 switch (code) {
 case Bytecodes::_nop         : /* nothing to do */ break;
 ...
 case Bytecodes::_invokevirtual : // fall through
 case Bytecodes::_invokespecial : // fall through
 case Bytecodes::_invokestatic : // fall through
 case Bytecodes::_invokedynamic : // fall through
 case Bytecodes::_invokeinterface: invoke(code); break;

 GraphBuilder::invoke(Bytecodes::Code)
 ciMethod* cha_monomorphic_target
 ciMethod* exact_target

 if (!target->is_static()) {
   type_is_exact
   exact_target = target->resolve_invoke(calling_klass, receiver_klass);
     code = invokespecial

     invokevirtual || invokeinterfaceの場合
       cha_monomorphic_target = target->find_monomorphic_target(calling_klass, callee_holder, actual_recv);

     invokeinterface && singleton?
       CheckCast* c = new CheckCast(klass, receiver, copy_state_for_exception())
       set_incompatible_class_change_check()

 cha_monomorphic_targetがabstractだった場合、
  NULL

 cha_monomorphic_targetが見つかった場合
  dependency_recorder()->assert_unique_concrete_method(actual_recv, cha_monomorphic_target)
  code = invokespecial

 もし上記処理で一意に分かったら
 try_inline(inline_target, );
  try_inline_full() <-- 200stepの関数なので、あまり見たくない
    最終的には、iterate_bytecode_ みたいなのを呼び出す


 is_profiling()
   target_klass = cha_monomorphic_target->holder() || exact_garget->holder()
   profile_call(recv, target_klass)


 dependency
 dependencyは、JVM上での制約をチェックし、違反した場合イベントを起動してくれるイベントハンドラみたい
 なもの
 よく脱仮想化する際に使用し、もし脱仮想化の条件が崩れた場合、脱最適化するようにイベントを登録する
 脱仮想化の条件が崩れる例として、newで新しいクラスを作成した時や、classloader、redefine
 void GraphBuilder::invoke(Bytecodes::Code code)
 if (cha_monomorphic_target != NULL) {
   if (!(target->is_final_method())) {
     // If we inlined because CHA revealed only a single target method,
     // then we are dependent on that target method not getting overridden
     // by dynamic class loading. Be sure to test the "static" receiver


14
dependency


      // dest_method here, as opposed to the actual receiver, which may
      // falsely lead us to believe that the receiver is final or private.
      dependency_recorder()->assert_unique_concrete_method(actual_recv, cha_monomorphic_target);
     }
     code = Bytecodes::_invokespecial;
 }

 GraphBuilder::call_register_finalizer()
 ciInstanceKlass* ik = compilation()->method()->holder();
 //finalだったら、一意
 if (ik->is_final()) {
   exact_type = ik;
 //クラス階層解析を使用するかつサブクラスを持ってない
 } else if (UseCHA && !(ik->has_subklass() || ik->is_interface())) {
   // test class is leaf class
   compilation()->dependency_recorder()->assert_leaf_type(ik);
   exact_type = ik;
 } else {
   declared_type = ik;
 }

 Dependencyを試す場合のオプション
      -XX:+TraceDependencies
      -XX:+VerifyDependencies
 dependencyの制約にひっかかり、deoptimizeするサンプルプログラム
 deoptimize sample
 interface getter {
   public int num();
   public int get();
 }

 class Bgetter implements getter {
   public int num() {
     return 1;
   }
   public int get() {
     int sum = 0;
     for (int i=0; i<100; i++) {
       sum += num();
     }
     return sum;
   }
 }
 class Cgetter implements getter {
   public int num() {
     return 2;
   }
   public int get() {
     int sum = 0;
     for (int i=0; i<100; i++) {
       sum += num();
     }
     return sum;
   }
 }

 public class iftest {



15
dependency


     static final long LEN=100000000;
     public static void main(String args[]) {
      getter f = new B();
      long sum=0;
      for( long i=0; i<LEN; i++ ) {
        sum += f.get();
      }

         //   getter f2 = new C(); //devirtualize

         System.out.println(sum);
     }
 }

 getter f2のコメントを外すと、new C()された際にdependencyが反応し、deoptimizeが走る
 log
 Failed dependency of type unique_concrete_method
  context = *getter
  method = {method} 'get' '()I' in 'B'
  witness = *getter
  code: 9434 1%         nmethod iftest::main @ 13 (58 bytes)
  Marked for deoptimization
  context = getter
  dependee = C
  context supers = 1, interfaces = 1
  Compiled (c1) 9434 1%          nmethod iftest::main @ 13 (58 bytes)
  total in heap [0xb5891388,0xb5891acc] = 1860
  relocation    [0xb5891458,0xb5891500] = 168
  main code      [0xb5891500,0xb58917c0] = 704
  stub code     [0xb58917c0,0xb589180c] = 76
  oops         [0xb589180c,0xb5891818] = 12
  scopes data [0xb5891818,0xb58918ec] = 212
  scopes pcs     [0xb58918ec,0xb5891aac] = 448
  dependencies [0xb5891aac,0xb5891ab0] = 4
  nul chk table [0xb5891ab0,0xb5891acc] = 28
  Dependencies:
  Dependency of type unique_concrete_method
  context = *getter
  method = {method} 'get' '()I' in 'B'
  [nmethod<=klass]getter
  checking (true) 9434 1%         nmethod iftest::main @ 13 (58 bytes)

 depdnecyのcheck処理が呼ばれた際のstack trace
 Breakpoint 4, Dependencies::DepStream::check_dependency_impl (this=0xfd05c8, changes=0xfd06f8)
 at /home/elise/language/openjdk6/hotspot/src/share/vm/code/dependencies.cpp:1449
 1449     if (TraceDependencies) {
 #1 0x00530b7e in Dependencies::DepStream::spot_check_dependency_at (this=0xfd05c8, changes=
 at /home/elise/language/openjdk6/hotspot/src/share/vm/code/dependencies.cpp:1464
 1464 return check_dependency_impl(&changes);
 #0 Dependencies::DepStream::check_dependency_impl (this=0xfd05c8, changes=0xfd06f8)
 at /home/elise/language/openjdk6/hotspot/src/share/vm/code/dependencies.cpp:1449
 1449     if (TraceDependencies) {
 #1 0x00530b7e in Dependencies::DepStream::spot_check_dependency_at (this=0xfd05c8, changes=
 at /home/elise/language/openjdk6/hotspot/src/share/vm/code/dependencies.cpp:1464
 1464 return check_dependency_impl(&changes);
 #2 0x007573ae in nmethod::check_dependency_on (this=0xb60d4388, changes=...)
 at /home/elise/language/openjdk6/hotspot/src/share/vm/code/nmethod.cpp:2063
 2063     if (deps.spot_check_dependency_at(changes) != NULL) {
 #3 0x005b6030 in instanceKlass::mark_dependent_nmethods (this=0xb212bde0, changes=...)


16
dependency


 at /home/elise/language/openjdk6/hotspot/src/share/vm/oops/instanceKlass.cpp:1406
 1406      if (nm->is_alive() && !nm->is_marked_for_deoptimization() && nm->check_dependency_on(changes)) {
 #4 0x004b0f83 in CodeCache::mark_for_deoptimization (changes=...)
 at /home/elise/language/openjdk6/hotspot/src/share/vm/code/codeCache.cpp:641
 641       number_of_marked_CodeBlobs += instanceKlass::cast(d)->mark_dependent_nmethods(changes);
 #5 0x00866302 in Universe::flush_dependents_on (dependee=...)
 at /home/elise/language/openjdk6/hotspot/src/share/vm/memory/universe.cpp:1182
 1182 if (CodeCache::mark_for_deoptimization(changes) > 0) {
 #6 0x00825729 in SystemDictionary::add_to_hierarchy (k=..., __the_thread__=0x806cc00)
 at /home/elise/language/openjdk6/hotspot/src/share/vm/classfile/systemDictionary.cpp:1727
 1727 Universe::flush_dependents_on(k);
 #7 0x00824e09 in SystemDictionary::define_instance_class (k=..., __the_thread__=0x806cc00)
 at /home/elise/language/openjdk6/hotspot/src/share/vm/classfile/systemDictionary.cpp:1506
 1506      add_to_hierarchy(k, CHECK); // No exception, but can block
 #8 0x00823df1 in SystemDictionary::resolve_from_stream (class_name=..., class_loader=..., p
    verify=true, __the_thread__=0x806cc00) at /home/elise/language/openjdk6/hotspot/src/share/vm/classfile/
 1138        define_instance_class(k, THREAD);
 #9 0x0064c2d9 in jvm_define_class_common (env=0x806cd3c, name=0xfd0eac "C", loader=0xfd0fac
    len=316, pd=0xfd0f98, source=0xfd0aac "file:/home/elise/language/java/sample6/", verify=1 '001', __the_t
 at /home/elise/language/openjdk6/hotspot/src/share/vm/prims/jvm.cpp:864
 864                                        CHECK_NULL);
 #10 0x0064c7d6 in JVM_DefineClassWithSource (env=0x806cd3c, name=0xfd0eac "C", loader=0xfd0f
    len=316, pd=0xfd0f98, source=0xfd0aac "file:/home/elise/language/java/sample6/")
 at /home/elise/language/openjdk6/hotspot/src/share/vm/prims/jvm.cpp:884
 884 return jvm_define_class_common(env, name, loader, buf, len, pd, source, true, THREAD);
 #11 0x00ff7942 in Java_java_lang_ClassLoader_defineClass1 (env=0x806cd3c, loader=0xfd0fac, n
    length=316, pd=0xfd0f98, source=0xfd0f94) at ../../../src/share/native/java/lang/ClassLoader.c:151
 151     result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource);

 @todo DepStream::check_dependency_impl() code/dependencies.cpp
 invokenの際は、unique_concreate_method
 CHAで再度チェックしている
 klassOop Dependencies::DepStream::check_dependency_impl(DepChange* changes) {
 assert_locked_or_safepoint(Compile_lock);

 klassOop witness = NULL;
 switch (type()) {
 case evol_method:
   witness = check_evol_method(method_argument(0));
   break;
 case leaf_type:
   witness = check_leaf_type(context_type());
   break;
 case abstract_with_unique_concrete_subtype:
   witness = check_abstract_with_unique_concrete_subtype(context_type(),
                                         type_argument(1),
                                         changes);
   break;
 case abstract_with_no_concrete_subtype:
   witness = check_abstract_with_no_concrete_subtype(context_type(),
                                      changes);
   break;
 case concrete_with_no_concrete_subtype:
   witness = check_concrete_with_no_concrete_subtype(context_type(),
                                      changes);
   break;
 case unique_concrete_method:
   witness = check_unique_concrete_method(context_type(),



17
プロファイラ


                                 method_argument(1),
                                 changes);
   break;
 case abstract_with_exclusive_concrete_subtypes_2:
   witness = check_abstract_with_exclusive_concrete_subtypes(context_type(),
                                             type_argument(1),
                                             type_argument(2),
                                             changes);
   break;
 case exclusive_concrete_methods_2:
   witness = check_exclusive_concrete_methods(context_type(),
                                  method_argument(1),
                                  method_argument(2),
                                  changes);
   break;
 case no_finalizable_subclasses:
   witness = check_has_no_finalizable_subclasses(context_type(),
                                    changes);
   break;
 default:
   witness = NULL;
   ShouldNotReachHere();
   break;
 }

deoptimizeも、thread並列で行うが、実際にコードを置換する際には全体をmutexで止める
dependenceからDeoptimizeを呼び出す場所
 // Flushes compiled methods dependent on dependee.
 void Universe::flush_dependents_on(instanceKlassHandle dependee) {
  assert_lock_strong(Compile_lock);

     if (CodeCache::number_of_nmethods_with_dependencies() == 0) return;

     // CodeCache can only be updated by a thread_in_VM and they will all be
     // stopped dring the safepoint so CodeCache will be safe to update without
     // holding the CodeCache_lock.

     DepChange changes(dependee);

     // Compute the dependent nmethods
     if (CodeCache::mark_for_deoptimization(changes) > 0) { //<----- koko
       // At least one nmethod has been marked for deoptimization
       VM_Deoptimize op;
       VMThread::execute(&op);
     }
 }

dependenciesのルールから、VM_deoptimizeがキックされ、 dependenciesに引っかかった要素をdeoptimizeする
deoptimizeも、2種類あり、mutexで止めた際に、実行中でないなら、oopsのcodeを書き換える抱け。
もし実行中だったら、frameを書き換えて、JITコンパイルしたコードからintepreter実行に切り替える


プロファイラ
C1コンパイラでは、
プロファイルした情報を活用する部分と、
C1コンパイラが生成したコードにプロファイルする命令を埋め込む部分がある。
プロファイル系のオプション


18
HIR から LIR への変換


 product(bool, C1ProfileCalls, true,                             
       "Profile calls when generating code for updating MDOs")         
                                                         
 // dead
 product(bool, C1ProfileVirtualCalls, true,                        
       "Profile virtual calls when generating code for updating MDOs") 
                                                         
 product(bool, C1ProfileInlinedCalls, true,                        
       "Profile inlined calls when generating code for updating MDOs") 
                                                         
 product(bool, C1ProfileBranches, true,                            
       "Profile branches when generating code for updating MDOs")        
                                                         
 product(bool, C1ProfileCheckcasts, true,                            
       "Profile checkcasts when generating code for updating MDOs")      

主にプロファイルはインタプリタが行っているが、
C1コンパイラがJITコンパイルしたコードにも埋め込み可能になっている。
JITコンパイルしたコードに埋め込む場合、2回目、3回目のJITコンパイルが行われるはず
複数回のJITコンパイルの条件は不明。。
プロファイルの様子は、TemplateIntepreterの解説に期待


HIR から LIR への変換
HIRからLIRへの変換はLIRGeneratorが行う。
visitorでHIRを走査し、HIRに対して複数のLIRへ分解する
LIRは仮想レジスタを無限に持つことを仮定し、レジスタ割り付けで実レジスタを割り振る
void LIRGenerator::block_do(BlockBegin* block)
 block_do_prolog(block);
  __ branch_destination(block->label()); <-- label設定

 set_block(block);

 for (Instruction* instr = block; instr != NULL; instr = instr->next()) {
   if (instr->is_pinned()) do_root(instr);
 }

 set_block(NULL);
 block_do_epilog(block);

void LIRGenerator::do_IfOp(IfOp* x)
 // Code for : x->x() {x->cond()} x->y() ? x->tval() : x->fval()

     LIRItem left(x->x(), this);
     LIRItem right(x->y(), this);
     left.load_item();
     if (can_inline_as_constant(right.value())) {
       right.dont_load_item();
     } else {
       right.load_item();
     }

     LIRItem t_val(x->tval(), this);
     LIRItem f_val(x->fval(), this);
     t_val.dont_load_item();
     f_val.dont_load_item();


19
C1コンパイラのHIR最適化


     LIR_Opr reg = rlock_result(x);

     __ cmp(lir_cond(x->cond()), left.result(), right.result());
     __ cmove(lir_cond(x->cond()), t_val.result(), f_val.result(), reg, as_BasicType(x->x()->type()));
 }

invokeの処理なんかは複雑で面白いかもしれない


C1コンパイラのHIR最適化
HIR Optimizationは、BytecodeからHIRへ変換終わった後に行う
c1_Compilation.cpp::build_hir()
 _hir->optimize();
  IR::optimize()
    opt.eliminate_conditional_expressions();
    opt.eliminate_blocks();
    opt.eliminate_null_checks();


eliminate_conditional_expressions
@todo 時間があればコードを追うこと
CE_Eliminator::block_do()が本体
 ブロックの終端のifを取得
 ifはint型かobject型か判定

 true block
 false block
 true_instruction
 false_instruction

 a = (b > c) ? b : c;

 BB:
  if ... then BBn false BBm
 BBn:
  const n
  goto BBs
 BBm:
  const m
  goto BBs
 BBs:
  phi [][]

CEE Java:
 public static int CETest(int ret, int n,int m) {
   ret += (n < m) ? n : m;
   return ret;
 }

CEE HIR
 B62:
  i179 = i103 - i76
  i180 = i178 - i151
  v186 = if i179 > i180 then B73 else B72 <-- replace i186 = ifop (i179 > i180) ixx, iyy;
                               <-- add     goto B74
 B73:                           <-- delete
  v188 = goto B74                    <-- delete


20
GlobalValueNumbering


 B72:                                     <-- delete
  v187 = goto B74                             <-- delete
 B74:
  i189 = [i179,i180]                          <-- replace
  v190 = goto B70
 B70:
  i191 = i151 + i189


 GlobalValueNumbering
 @todo 時間があればコードを追うこと
 c1_ValueMap.hpp::GlobalValueNumbering(IR* ir)
 ShortLoopOptimizer short_loop_optimizer(this);

 for (int i = 1; i < num_blocks; i++) {
  BlockBegin* block = blocks->at(i);

     ...

     if (num_preds == 1) {
       // nothing to do here

     } else if (block->is_set(BlockBegin::linear_scan_loop_header_flag)) {
       // block has incoming backward branches -> try to optimize short loops
       if (!short_loop_optimizer.process(block)) {         <-- ループは特別に処理
         // loop is too complicated, so kill all memory loads because there might be
         // stores to them in the loop
         current_map()->kill_memory();
       }

     } else {
       // only incoming forward branches that are already processed
       for (int j = 0; j < num_preds; j++) {
        BlockBegin* pred = block->pred_at(j);
        ValueMap* pred_map = value_map_of(pred);

             if (pred_map != NULL) {
               // propagate killed values of the predecessor to this block
               current_map()->kill_map(value_map_of(pred));
             } else {
               // kill all memory loads because predecessor not yet processed
               // (this can happen with non-natural loops and OSR-compiles)
               current_map()->kill_memory();
             }
         }
     }

     if (block->is_set(BlockBegin::exception_entry_flag)) {
       current_map()->kill_exception();
     }

     TRACE_VALUE_NUMBERING(tty->print("value map before processing block: "); current_map()->print());

     // visit all instructions of this block
     for (Value instr = block->next(); instr != NULL; instr = instr->next()) {
      assert(!instr->has_subst(), "substitution already set");

         // check if instruction kills any values
         instr->visit(this);


21
EscapeAnalysis




          if (instr->hash() != 0) {
            Value f = current_map()->find_insert(instr); <-- ここがキモ
            if (f != instr) {
              assert(!f->has_subst(), "can't have a substitution");
              instr->set_subst(f);
              subst_count++;
            }
          }
      }

      // remember value map for successors
      set_value_map_of(block, current_map());
  }


 EscapeAnalysis
 c1コンパイラからは呼ばれません!!!
 wimmerの資料によるとclientからも呼ばれるようだが、昔のJDKもしくはSun JDKだけなのかもしれない。
 Serverだとbreakを確認できた。
 Sharkだとifdef切ってるけど、多分動かないんだろうと推測


 C1コンパイラのLIR最適化

 EdgeMoveOptimizer
 c1_LinearScan.cpp::EdgeMoveOptimizer::optimize(BlockList* code)
  EdgeMoveOptimizer optimizer = EdgeMoveOptimizer();

  // ignore the first block in the list (index 0 is not processed)
  for (int i = code->length() - 1; i >= 1; i--) {
   BlockBegin* block = code->at(i);

      if (block->number_of_preds() > 1 && !block->is_set(BlockBegin::exception_entry_flag)) {
        optimizer.optimize_moves_at_block_end(block);
      }
      if (block->number_of_sux() == 2) {
        optimizer.optimize_moves_at_block_begin(block);
      }
  }

 preds > 1 --> ブロックへのjumpが複数ある場合
          CFGの合流ブロックとか、loopのheaderとか
          code sink みたいな処理
 sux == 2 --> ブロックからのjumpが複数ある場合
          分岐とか、loopのback_edgeとか
          code hoist みたいな処理


 ControlFlowOptimizer
 c1_LiearScan.cpp::ControlFlowOptimize::optimize(BlockList* code)
  ControlFlowOptimizer optimizer = ControlFlowOptimizer();

  // push the OSR entry block to the end so that we're not jumping over it.


22
sample code factIf


  BlockBegin* osr_entry = code->at(0)->end()->as_Base()->osr_entry();
  if (osr_entry) {
    int index = osr_entry->linear_scan_number();
    assert(code->at(index) == osr_entry, "wrong index");
    code->remove_at(index);
    code->append(osr_entry);
  }

  optimizer.reorder_short_loops(code);
  optimizer.delete_empty_blocks(code);
  optimizer.delete_unnecessary_jumps(code);
  optimizer.delete_jumps_to_return(code);

 reorder_short_loops()
 下記のようなケースをpost jumpっぽくする
 end_block
  B4 (V) [35, 50] -> B3 dom B3 sux: B3 pred: B3

  __bci__use__tid____instr____________________________________
  35 1 i19 31
  38 1 i20 i15 * i19
  41 2 i21 1
  . 41 1 i22 i16 + i21
  . 44 1 i23 a11[i16] (C)
  . 45 1 i24 i20 + i23
  . 47 1 i26 i17 + i21
  . 50 0    27 goto B3 (safepoint)

 header_block
  B3 (LHbV) [28, 32] -> B5 B4 dom B1 sux: B5 B4 pred: B1 B4

  __bci__use__tid____instr____________________________________
  . 32 0    18 if i17 >= i12 then B5 else B4

 delete_unnecessary_jumps()
     last_branchが次のブロックへの飛び先だったらdelete
     cmp branch1 branch2の場合、branch1が次のブロックへのjumpだったら、 branch1を書き換えて、condの
     条件を反転 branch2を削除


 sample code factIf
 入力ソースコードfactIf
  public static int factIf(int n) {
    int p;
    if (n > 1) {
      p = n * factIf(n - 1);
    } else {
      p = 1;
    }
    return p;
  }

 factIf Bytecode
  public static int factIf(int):
  Code:
  0: iload_0
  1: iconst_1


23
sample code factIf


  2:    if_icmple      17
  5:    iload_0
  6:    iload_0
  7:    iconst_1
  8:    isub
  9:    invokestatic   #3; //Method factIf:(I)I
  12:    imul
  13:    istore_1
  14:    goto 19
  17:    iconst_1
  18:    istore_1
  19:    iload_1
  20:    ireturn

 factIf HIR:
  static jint Fact.factIf(jint)
  B9:
   i4 = method parameter
   v32 = std entry B0
  B0:
   i5 = 1
   v6 = if i4 <= i5 then B2 else B1
  B1:
   i7 = 1
   i8 = i4 - i7
   v15 = if i8 <= i7 then B7 else B6
  B7:
   i21 = 1
   v22 = goto B8
  B6:
   i16 = 1
   i17 = i8 - i16
   i18 = invokestatic(i17) Fact.factIf(I)I
   i19 = i8 * i18
   v20 = goto B8
  B8:
   i23 = [i19,i21]
   v24 = goto B4
  B4:
   i25 = i4 * i23
   v26 = goto B3
  B2:
   i27 = 1
   v28 = goto B3
  B3:
   i29 = [i25,i27]
   i30 = ireturn i29

 factIf HIR CFG




 factIf HIR DFG



24
sample code factIf




 factIf Optimized HIR
  static jint Fact.factIf(jint)
  B9:
   i4 = method parameter
   v32 = std entry B0
  B0:
   i5 = 1
   v6 = if i4 <= i5 then B2 else B1
  B1:
                              // deleted i7 = 1
   i8 = i4 - i7
   v15 = if i8 <= i7 then B7 else B6
  B7:
                              // deleted i21 = 1
   v22 = goto B8
  B6:
   // deleted i16 = 1
   i17 = i8 - i5                 // replaced i17 = i8 - i16
   i18 = invokestatic(i17) Fact.factIf(I)I
   i19 = i8 * i18
   v20 = goto B8
  B8:
   i23 = [i19,i5]                 // replaced i23 = [i19,i21]
                              // deleted v24 = goto B4
                              // deleted B4:
   i25 = i4 * i23
   v26 = goto B3
  B2:
                              // deleted i27 = 1
   v28 = goto B3
  B3:
   i29 = [i25,i5]                 // replaced i29 = [i25,i27]
   i30 = ireturn i29

 基本的には、HIRからLIRへシーケンシャルに変換する BBの入り口処理とかは遣るけどさ
 factIf translate HIR to LIR
  #             #         #    #
  label B9
    std_entry
    move    ecx     R41
    branch AL       B0
  label B0
    cmp     R41     1
    branch LE       B2
    branch AL       B1
  label B1
    move    R41     R42


25
sample code factIf


    sub     R42 1        R42
    cmp      R42 1
    branch LE B7
    branch AL B6
  label B6
    move     R42 R43
    sub     R43 1        R43
    move     R43 ecx
    static call [static jint Fact.factIf(jint)] result eax bci:9
    move     eax R44
    move     R44 R45
    mul     R45 R42 R45
    move     R45 R46
    branch AL B8
  label B7
    move     1     R46
    branch AL B8
  label B8
    move     R46 R47
    mul     R47 R41
    move     R47 R48
    branch AL B3
  label B2
    move     1     B48
    branch AL B3
  label B3
    move     R48 eax
    return eax




26
sample code factIf




               B9:
               std_entry
               move ecx R41
               branch AL B0




                B0:
                cmp   R41 1
                branch LE B2
                branch AL B1




                      B1:
                      move R41 R42
                      sub   R42 1 R42
                      cmp    R42 1
                      branch LE B7
                      branch AL B6




                                        B6:
                                        move R42 R43
                                        sub     R43 1 R43
                                        move R43 ecx
                       B7:
                                        static call [static jint Fact.factIf(jint)] result eax bci:9
                       move 1 R46
                                        move eax R44
                       branch AL B8
                                        move R44 R45
                                        mul     R45 R42 R45
                                        move R45 R46
                                        branch AL B8




                            B8:
        B2:                 move R46 R47
        move 1 B48          mul   R47 R41
        branch AL B3        move R47 R48
                            branch AL B3




                     B3:
                     move R48 eax
                     return eax




 LinearScanレジスタ割り付け




27
sample code factFor




 LIRでも色々冗長な命令を削る
 Before Code Generation
  #              #        #      #      #
  label B9
    std_entry
                          // deleted move       ecx   R41
                          // deleted branch     AL    B0
  label B0
    cmp    ecx       1        // replaced cmp     R41   1
    branch LE        B2
                          // deleted branch AL B1
  label B1
    move     ecx esi          // replaced move     R41 R42
    sub     esi 1      esi // replaced sub        R42 1      R42
    cmp      esi 1           // replaced cmp      R42 1
    move     ecx stack:2        // add
    branch LE B7
                          // deleted branch AL B6
  label B6
    move     esi edi          // replaced move     R42 R43
    sub     edi 1       edi // replaced sub       R43 1      R43
    move     edi ecx          // replaced move      R43 ecx
    move     esi stack:1       // add
    static call [static jint Fact.factIf(jint)] result eax bci:9
    move     stack:1 esi       // add
                          // deleted move       eax R44
                          // deleted move       R44 R45
    mul     eax esi eax // replaced mul            R45 R42 R45
                          // deleted move       R45 R46
    branch AL B8
  label B7
    move     1     eax        // replaced move     1    R46
                          // deleted branch AL B8
  label B8
    move     stack:2 ecx        // add
                          // deleted move       R46 R47
    mul     eax ecx eax // replaced mul            R47 R41
                          // deleted move       R47 R48
                          // deleted branch AL B3
    return eax               // add
  label B2
    move     1     eax        // replaced move     1    B48
                          // deleted branch AL B3
  label B3
                          // deleted move       R48 eax
    return eax


 sample code factFor
 入力ソースコードfactFor
  public static int factFor(int n) {
   int p = 1;
   for (int i = 1; i <= n; i++) {


28
sample code factFor


        p = p * i;
      }
      return p;
  }

 factFor Bytecode
  public static int factFor(int);
  Code:
  0: iconst_1
  1: istore_1
  2: iconst_1
  3: istore_2
  4: iload_2
  5: iload_0
  6: if_icmpgt        19
  9: iload_1
  10: iload_2
  11: imul
  12: istore_1
  13: iinc 2, 1
  16: goto 4
  19: iload_1
  20: ireturn

 factFor HIR
  static jint Fact.factFor(jint)
  B4:
   i4 = method parameter
   v17 = std entry B0
  B0:
   i5 = 1
   v7 = goto B1
  B1:
   i8 = [i5, i11]
   i9 = [i5, i13]
   v10 = if i9 > i4 then B3 else B2
  B2:
   i11 = i8 * i9
   i12 = 1
   i13 = i9 + i12
   v14 = goto B1
  B3:
   i15 = ireturn i8

 factFor HIR CFG




 factFor HIR DFG




 factFor Optimized HIR




29
sample code factFor


  static jint Fact.factFor(jint)
  B4:
   i4 = method parameter
   v17 = std entry B0
  B0:
   i5 = 1
   v7 = goto B1
  B1:
   i8 = [i5, i11]
   i9 = [i5, i13]
   v10 = if i9 > i4 then B3 else B2
  B2:
   i11 = i8 * i9
                       // deleted i12 = 1
   i13 = i9 + i5          // replaced i13 = i9 + i12
   v14 = goto B1
  B3:
   i15 = ireturn i8

 factFor translate HIR to LIR
  #             #     #         #
  label B4
    std_entry
    move     ecx R41
    branch AL B0
  label B0
    move     1    R43
    move     1    R42
    branch AL B1
  label B1
    cmp     R43 R41
    branch GT B3
    branch AL B2
  label B2
    move     R42 R44
    mul     R44 R43 R44
    move     R43 R45
    add     R45 1     R45
    safepoint bci:16
    move     R45 R43
    move     R44 R42
    branch AL B1
  label B3
    move     R42 eax
    return eax




30
sample code factFor




                                                    B4
                                                    std_entry
                                                    move ecx R41
                                                    branch AL B0



                                                    B0
                                                    move 1 R43
                                                    move 1 R42
                                                    branch AL B1



                                                B1
                                                cmp    R43 R41
                                                branch GT B3
                                                 branch AL B2



                                             B2
                                             move R42 R44
                                             mul    R44 R43 R44
             B3                              move R43 R45
             move R42 eax                    add    R45 1 R45
             return eax                      safepoint bci:16
                                             move R45 R43
                                             move R44 R42
                                             branch AL B1



 LenearScanレジスタ割り付け




 Before Code Generation
  #               #         #     #
  label B4
    std_entry
                                // deleted move      ecx   R41
                                // deleted branch    AL    B0
  label B0
    move     1        eax          // replaced move    1     R43
    move     1        esi         // replaced move     1     R42
    branch   AL        B1



31
参考文献


 label B2
                                // deleted move     R42 R44
     mul     esi    eax   esi      // replaced mul    R44 R43 R44
                                // deleted move     R43 R45
     add     eax 1        eax       // replaced add    R45 1  R45
     safepoint bci:16
                                // deleted move       R45 R43
                                // deleted move       R44 R42
                                // deleted branch     AL B1
     label B1
      cmp     eax   ecx             // replaced cmp    R43 R41
                                // deleted branch GT B3
   branch LE B2                     // replaced branch AL B2
 label B3
   move   esi eax                  // replaced move     R42   eax
   return eax


参考文献
SSA Form for the Java HotSpot™ Client Compiler
 Christian Wimmer
 April 2009
 Sun Microsystems, Inc.
 Institute for System Software
 Johannes Kepler University Linz, Austria
 Department of Computer Science
 University of California, Irvine

Linear Scan Register Allocation
 Christian Wimmer
 Linear Scan Register Allocation
 for the Java HotSpot™ Client Compiler
 A thesis submitted in partial satisfaction of
 the requirements for the degree of
 Master of Science
 (Diplom-Ingenieur)

Design of the Java HotSpotTM Client Compiler for Java 6
 Design of the Java HotSpotTM Client
 Compiler for Java 6
 THOMAS KOTZMANN, CHRISTIAN WIMMER
 and HANSPETER MO¨ SSENBO¨ CK
 Johannes Kepler University Linz
 and
 THOMAS RODRIGUEZ, KENNETH RUSSELL, and DAVID COX
 Sun Microsystems, Inc.

Escape Analysis in the Context of Dynamic Compilation and Deoptimization
 Thomas Kotzmann
 Escape Analysis in the Context of
 Dynamic Compilation and Deoptimization
 A PhD thesis
 submitted in partial satisfaction of the requirements for the degree of
 Doctor of Technical Sciences
 Institute for System Software
 Johannes Kepler University Linz




32
Indices and tables



 Indices and tables
     • genindex
     • modindex
     • search




33

More Related Content

What's hot

Perlと出会い、Perlを作る
Perlと出会い、Perlを作るPerlと出会い、Perlを作る
Perlと出会い、Perlを作るgoccy
 
OPcache の最適化器の今
OPcache の最適化器の今OPcache の最適化器の今
OPcache の最適化器の今y-uti
 
PHPとシグナル、その裏側
PHPとシグナル、その裏側PHPとシグナル、その裏側
PHPとシグナル、その裏側do_aki
 
Zynq VIPを利用したテストベンチ
Zynq VIPを利用したテストベンチZynq VIPを利用したテストベンチ
Zynq VIPを利用したテストベンチMr. Vengineer
 
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Mr. Vengineer
 
コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道なおき きしだ
 
Java 9で進化する診断ツール
Java 9で進化する診断ツールJava 9で進化する診断ツール
Java 9で進化する診断ツールYasumasa Suenaga
 
PHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とPHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とdo_aki
 
Async design with Unity3D
Async design with Unity3DAsync design with Unity3D
Async design with Unity3DKouji Hosoda
 
大義のために:趣味と実益のためのVMware RPCインターフェースの活用 by アブドゥル・アジズ・ハリリ, ジャシエル・スペルマン, ブライアン・ゴーレンク
大義のために:趣味と実益のためのVMware RPCインターフェースの活用 by アブドゥル・アジズ・ハリリ, ジャシエル・スペルマン, ブライアン・ゴーレンク大義のために:趣味と実益のためのVMware RPCインターフェースの活用 by アブドゥル・アジズ・ハリリ, ジャシエル・スペルマン, ブライアン・ゴーレンク
大義のために:趣味と実益のためのVMware RPCインターフェースの活用 by アブドゥル・アジズ・ハリリ, ジャシエル・スペルマン, ブライアン・ゴーレンクCODE BLUE
 
Php in ruby
Php in rubyPhp in ruby
Php in rubydo_aki
 
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かsignal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かdo_aki
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案yohhoy
 
Jvm reading-synchronization
Jvm reading-synchronizationJvm reading-synchronization
Jvm reading-synchronizationMinoru Nakamura
 
発表資料 Fortranを用いた高位合成技術FortRockの開発
発表資料 Fortranを用いた高位合成技術FortRockの開発発表資料 Fortranを用いた高位合成技術FortRockの開発
発表資料 Fortranを用いた高位合成技術FortRockの開発貴大 山下
 
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しようUnity Technologies Japan K.K.
 

What's hot (20)

Perlと出会い、Perlを作る
Perlと出会い、Perlを作るPerlと出会い、Perlを作る
Perlと出会い、Perlを作る
 
OPcache の最適化器の今
OPcache の最適化器の今OPcache の最適化器の今
OPcache の最適化器の今
 
PHPとシグナル、その裏側
PHPとシグナル、その裏側PHPとシグナル、その裏側
PHPとシグナル、その裏側
 
ZynqMPのQEMU
ZynqMPのQEMUZynqMPのQEMU
ZynqMPのQEMU
 
Zynq VIPを利用したテストベンチ
Zynq VIPを利用したテストベンチZynq VIPを利用したテストベンチ
Zynq VIPを利用したテストベンチ
 
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析
 
JVM-Reading-ParalleGC
JVM-Reading-ParalleGCJVM-Reading-ParalleGC
JVM-Reading-ParalleGC
 
コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道
 
Java 9で進化する診断ツール
Java 9で進化する診断ツールJava 9で進化する診断ツール
Java 9で進化する診断ツール
 
PHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とPHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 と
 
about Perl5.10
about Perl5.10about Perl5.10
about Perl5.10
 
Improvement future api
Improvement future apiImprovement future api
Improvement future api
 
Async design with Unity3D
Async design with Unity3DAsync design with Unity3D
Async design with Unity3D
 
大義のために:趣味と実益のためのVMware RPCインターフェースの活用 by アブドゥル・アジズ・ハリリ, ジャシエル・スペルマン, ブライアン・ゴーレンク
大義のために:趣味と実益のためのVMware RPCインターフェースの活用 by アブドゥル・アジズ・ハリリ, ジャシエル・スペルマン, ブライアン・ゴーレンク大義のために:趣味と実益のためのVMware RPCインターフェースの活用 by アブドゥル・アジズ・ハリリ, ジャシエル・スペルマン, ブライアン・ゴーレンク
大義のために:趣味と実益のためのVMware RPCインターフェースの活用 by アブドゥル・アジズ・ハリリ, ジャシエル・スペルマン, ブライアン・ゴーレンク
 
Php in ruby
Php in rubyPhp in ruby
Php in ruby
 
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かsignal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何か
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案
 
Jvm reading-synchronization
Jvm reading-synchronizationJvm reading-synchronization
Jvm reading-synchronization
 
発表資料 Fortranを用いた高位合成技術FortRockの開発
発表資料 Fortranを用いた高位合成技術FortRockの開発発表資料 Fortranを用いた高位合成技術FortRockの開発
発表資料 Fortranを用いた高位合成技術FortRockの開発
 
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
 

Viewers also liked

Tiered Compilation in Hotspot JVM
Tiered Compilation in Hotspot JVMTiered Compilation in Hotspot JVM
Tiered Compilation in Hotspot JVMIgor Veresov
 
JVM JIT compilation overview by Vladimir Ivanov
JVM JIT compilation overview by Vladimir IvanovJVM JIT compilation overview by Vladimir Ivanov
JVM JIT compilation overview by Vladimir IvanovZeroTurnaround
 
Jjug ccc 2016 spring i 5 javaデスクトッププログラムを云々
Jjug ccc 2016 spring i 5 javaデスクトッププログラムを云々Jjug ccc 2016 spring i 5 javaデスクトッププログラムを云々
Jjug ccc 2016 spring i 5 javaデスクトッププログラムを云々torutk
 
JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?Doug Hawkins
 
OpenJDK コミュニティに参加してみよう #jjug
OpenJDK コミュニティに参加してみよう #jjugOpenJDK コミュニティに参加してみよう #jjug
OpenJDK コミュニティに参加してみよう #jjugYuji Kubota
 
Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4
Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4
Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4bitter_fox
 
Java仮想マシンの実装技術
Java仮想マシンの実装技術Java仮想マシンの実装技術
Java仮想マシンの実装技術Kiyokuni Kawachiya
 
Introduction to Chemical Bonding
Introduction to Chemical BondingIntroduction to Chemical Bonding
Introduction to Chemical BondingBryan Nozaleda
 
Aspergillosis Patients Support Outreach Meeting London June 2011 - Graham Ath...
Aspergillosis Patients Support Outreach Meeting London June 2011 - Graham Ath...Aspergillosis Patients Support Outreach Meeting London June 2011 - Graham Ath...
Aspergillosis Patients Support Outreach Meeting London June 2011 - Graham Ath...Graham Atherton
 
tai lieu ve nuoi cay thuy sinh
tai lieu ve nuoi cay thuy sinhtai lieu ve nuoi cay thuy sinh
tai lieu ve nuoi cay thuy sinhParadise Kiss
 
Fort Lauderdale - A Veneza dos USA
Fort Lauderdale - A Veneza dos USAFort Lauderdale - A Veneza dos USA
Fort Lauderdale - A Veneza dos USAUmberto Pacheco
 
공익마케팅스쿨 1기, 넉달간의 기록
공익마케팅스쿨 1기, 넉달간의 기록공익마케팅스쿨 1기, 넉달간의 기록
공익마케팅스쿨 1기, 넉달간의 기록승훈 오
 
Becker product training 2011
Becker product training 2011Becker product training 2011
Becker product training 2011BECKERGPS
 
Real Estate Market Report for The Woodlands, Texas
Real Estate Market Report for The Woodlands, TexasReal Estate Market Report for The Woodlands, Texas
Real Estate Market Report for The Woodlands, TexasTanya Lavoie Bugbee
 

Viewers also liked (20)

Tiered Compilation in Hotspot JVM
Tiered Compilation in Hotspot JVMTiered Compilation in Hotspot JVM
Tiered Compilation in Hotspot JVM
 
JVM JIT compilation overview by Vladimir Ivanov
JVM JIT compilation overview by Vladimir IvanovJVM JIT compilation overview by Vladimir Ivanov
JVM JIT compilation overview by Vladimir Ivanov
 
Jjug ccc 2016 spring i 5 javaデスクトッププログラムを云々
Jjug ccc 2016 spring i 5 javaデスクトッププログラムを云々Jjug ccc 2016 spring i 5 javaデスクトッププログラムを云々
Jjug ccc 2016 spring i 5 javaデスクトッププログラムを云々
 
JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?
 
OpenJDK コミュニティに参加してみよう #jjug
OpenJDK コミュニティに参加してみよう #jjugOpenJDK コミュニティに参加してみよう #jjug
OpenJDK コミュニティに参加してみよう #jjug
 
Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4
Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4
Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4
 
Java仮想マシンの実装技術
Java仮想マシンの実装技術Java仮想マシンの実装技術
Java仮想マシンの実装技術
 
Introduction to Chemical Bonding
Introduction to Chemical BondingIntroduction to Chemical Bonding
Introduction to Chemical Bonding
 
quiz
quizquiz
quiz
 
Aspergillosis Patients Support Outreach Meeting London June 2011 - Graham Ath...
Aspergillosis Patients Support Outreach Meeting London June 2011 - Graham Ath...Aspergillosis Patients Support Outreach Meeting London June 2011 - Graham Ath...
Aspergillosis Patients Support Outreach Meeting London June 2011 - Graham Ath...
 
O fim aproxima-se ... !
O fim aproxima-se ... !O fim aproxima-se ... !
O fim aproxima-se ... !
 
Mexotel
MexotelMexotel
Mexotel
 
The.past.cont.tense.istock
The.past.cont.tense.istockThe.past.cont.tense.istock
The.past.cont.tense.istock
 
Dead in 60 seconds
Dead in 60 secondsDead in 60 seconds
Dead in 60 seconds
 
Dhvm 2.0
Dhvm 2.0Dhvm 2.0
Dhvm 2.0
 
tai lieu ve nuoi cay thuy sinh
tai lieu ve nuoi cay thuy sinhtai lieu ve nuoi cay thuy sinh
tai lieu ve nuoi cay thuy sinh
 
Fort Lauderdale - A Veneza dos USA
Fort Lauderdale - A Veneza dos USAFort Lauderdale - A Veneza dos USA
Fort Lauderdale - A Veneza dos USA
 
공익마케팅스쿨 1기, 넉달간의 기록
공익마케팅스쿨 1기, 넉달간의 기록공익마케팅스쿨 1기, 넉달간의 기록
공익마케팅스쿨 1기, 넉달간의 기록
 
Becker product training 2011
Becker product training 2011Becker product training 2011
Becker product training 2011
 
Real Estate Market Report for The Woodlands, Texas
Real Estate Market Report for The Woodlands, TexasReal Estate Market Report for The Woodlands, Texas
Real Estate Market Report for The Woodlands, Texas
 

Similar to OpenJDK HotSpot C1Compiler Overview

IL2CPPに関する軽い話
IL2CPPに関する軽い話IL2CPPに関する軽い話
IL2CPPに関する軽い話Wooram Yang
 
サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23
サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23
サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23Masashi Shibata
 
130329 04
130329 04130329 04
130329 04openrtm
 
20130329 rtm4
20130329 rtm420130329 rtm4
20130329 rtm4openrtm
 
130710 02
130710 02130710 02
130710 02openrtm
 
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門Preferred Networks
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputingNoboru Irieda
 
C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml ssuser3a4b8c
 
関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPU関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPUTakuro Iizuka
 
Vivado hls勉強会4(axi4 master)
Vivado hls勉強会4(axi4 master)Vivado hls勉強会4(axi4 master)
Vivado hls勉強会4(axi4 master)marsee101
 
4章 Linuxカーネル - 割り込み・例外 4
 4章 Linuxカーネル - 割り込み・例外 4 4章 Linuxカーネル - 割り込み・例外 4
4章 Linuxカーネル - 割り込み・例外 4mao999
 
高位合成友の会@ドワンゴ,2015年12月8日
高位合成友の会@ドワンゴ,2015年12月8日高位合成友の会@ドワンゴ,2015年12月8日
高位合成友の会@ドワンゴ,2015年12月8日貴大 山下
 
Nand2tetris 11
Nand2tetris 11Nand2tetris 11
Nand2tetris 11Hash29
 
Machine configoperatorのちょっとイイかもしれない話
Machine configoperatorのちょっとイイかもしれない話 Machine configoperatorのちょっとイイかもしれない話
Machine configoperatorのちょっとイイかもしれない話 Toshihiro Araki
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門伸男 伊藤
 
Kubernetes Operator for vSphere VM
Kubernetes Operator for vSphere VMKubernetes Operator for vSphere VM
Kubernetes Operator for vSphere VMMasanori Nara
 

Similar to OpenJDK HotSpot C1Compiler Overview (20)

IL2CPPに関する軽い話
IL2CPPに関する軽い話IL2CPPに関する軽い話
IL2CPPに関する軽い話
 
サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23
サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23
サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23
 
130329 04
130329 04130329 04
130329 04
 
20130329 rtm4
20130329 rtm420130329 rtm4
20130329 rtm4
 
Let's play with Goldfish
Let's play with GoldfishLet's play with Goldfish
Let's play with Goldfish
 
130710 02
130710 02130710 02
130710 02
 
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
 
PCL
PCLPCL
PCL
 
C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml
 
関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPU関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPU
 
Vivado hls勉強会4(axi4 master)
Vivado hls勉強会4(axi4 master)Vivado hls勉強会4(axi4 master)
Vivado hls勉強会4(axi4 master)
 
4章 Linuxカーネル - 割り込み・例外 4
 4章 Linuxカーネル - 割り込み・例外 4 4章 Linuxカーネル - 割り込み・例外 4
4章 Linuxカーネル - 割り込み・例外 4
 
高位合成友の会@ドワンゴ,2015年12月8日
高位合成友の会@ドワンゴ,2015年12月8日高位合成友の会@ドワンゴ,2015年12月8日
高位合成友の会@ドワンゴ,2015年12月8日
 
C# 3.0 以降
C# 3.0 以降C# 3.0 以降
C# 3.0 以降
 
Nand2tetris 11
Nand2tetris 11Nand2tetris 11
Nand2tetris 11
 
Machine configoperatorのちょっとイイかもしれない話
Machine configoperatorのちょっとイイかもしれない話 Machine configoperatorのちょっとイイかもしれない話
Machine configoperatorのちょっとイイかもしれない話
 
Minix smp
Minix smpMinix smp
Minix smp
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 
Kubernetes Operator for vSphere VM
Kubernetes Operator for vSphere VMKubernetes Operator for vSphere VM
Kubernetes Operator for vSphere VM
 

More from nothingcosmos

More from nothingcosmos (6)

2014 dart flight school in Tokyo
2014 dart flight school in Tokyo2014 dart flight school in Tokyo
2014 dart flight school in Tokyo
 
Dart 1.1
Dart 1.1Dart 1.1
Dart 1.1
 
Source Code of Dart
Source Code of DartSource Code of Dart
Source Code of Dart
 
Dart VM Performance
Dart VM PerformanceDart VM Performance
Dart VM Performance
 
DartVM on Android
DartVM on AndroidDartVM on Android
DartVM on Android
 
X86opti01 nothingcosmos
X86opti01 nothingcosmosX86opti01 nothingcosmos
X86opti01 nothingcosmos
 

Recently uploaded

[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 
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
 
論文紹介: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
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 
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
 
論文紹介: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
 
論文紹介: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
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
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
 

Recently uploaded (10)

[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 
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」の紹介
 
論文紹介: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
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 
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
 
論文紹介: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
 
論文紹介: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...
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
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
 

OpenJDK HotSpot C1Compiler Overview

  • 1. OpenJDK HotSpot C1Compiler Overview version 1.0 Author nothingcosmos November 09, 2011
  • 2.
  • 3. Contents Welcome to OpenJDK Internals's documentation! 1 OpenJDK HotSpot Client Compiler Overview 1 タイトル 1 自己紹介 1 OpenJDK キーワード 1 HotSpotの見どころ1 1 HotSpotの見どころ2 1 本日紹介するC1 Compiler 2 C1コンパイラの構成 3 コンパイル前の動作 4 JITコンパイラ 4 JITコンパイラが呼ばれる仕組み 5 JITコンパイルの入出力 6 JITコンパイルする条件 6 JITコンパイルする際のしきい値 9 C1コンパイラの内部構造 10 大まかなコンパイルの概要 10 コンパイラ全体の制御 10 BytecodeからHIRへの変換 11 if_icmpXXの変換 12 invokeの変換 13 dependency 14 プロファイラ 18 HIR から LIR への変換 19 C1コンパイラのHIR最適化 20 eliminate_conditional_expressions 20 GlobalValueNumbering 21 EscapeAnalysis 22 C1コンパイラのLIR最適化 22 EdgeMoveOptimizer 22 ControlFlowOptimizer 22 sample code factIf 23 sample code factFor 28 参考文献 32 Indices and tables 33
  • 4.
  • 5. Welcome to OpenJDK Internals's documentation! Welcome to OpenJDK Internals's documentation! Contents: OpenJDK HotSpot Client Compiler Overview タイトル OpenJDK HotSpot Client Compiler Overview 第4回JVMソースコードリーディングの会 nothingcosmos<nothingcosmos@gmail.com> http://nothingcosmos.blog52.fc2.com/ http://nothingcosmos.wiki.fc2.com/ 自己紹介 HN:nothingcosmos 元コンパイラ屋のソフトウェアエンジニア 現在は金融系SIer 趣味で、LLVMを読んだり、OpenJDKを読んだり、UNIXv6を読んだりしています。 先週は、箱根でLions'Commentary on UNIX勉強会(2011秋合宿)へ参加してました。 OpenJDK キーワード • HotSpotコンパイラ • C1(Client)/C2(Server)コンパイラ • JIT • Adaptive Compilation • Deoptimize 脱最適化 • 中間表現/中間言語 HotSpotの見どころ1 一般ユーザからみたコンパイラの見どころ • ... Scalaユーザからみたコンパイラの見どころ • Scalaでは細かいオブジェクトをたくさん作るので、 EscapeAnalysisがあると全部レジスタやスタックに乗る という話を以前kmizuさんに聞いた記憶が... 毎回ヒープに割り付けないので、高速 HotSpotの見どころ2 私個人は、 • コンパイラ内部の中間言語構造とアーキテクチャ • 大した最適化してないのに速いコードを吐くHotSpot Client Compiler 1
  • 6. 本日紹介するC1 Compiler • 適応的コンパイル Adaptive Compilation • JITコンパイラ/脱最適化のコントロール • Profiling/Tracingの取得方法と活用方法 • HotSpot特有の最適化技術 • EscapeAnalysis/ClassHierarchyAnalysis • 複数アーキテクチャへの対応方法 • OpenJDK7の最適化のバグ 本日紹介するC1 Compiler OpenJDKのHotSpot Glossary of Termsより抜粋 Fast, lightly optimizing bytecode compiler. Performs some value numbering, inlining, and class analysis. Uses a simple CFG-oriented SSA "high" IR, a machine-oriented "low" IR, a linear scan register allocation, and a template-style code generator. • ValueNumbering • 値番号付けというSSA形式を利用した最適化のアルゴリズムの名前. 冗長な式を削除する • inlining • インライン展開 • class analysis • CHA(ClassHierachyAnalysis). クラス解析 仮想関数呼出の呼び出し先を特定する際に活躍する • CFG-oriented SSA • CFG ControlFlowGraph • SSA StaticSingleAssignment form • IR • Intermediate Representation コンパイラ独自の中間表現 • linear scan register allocation 2
  • 7. C1コンパイラの構成 • リニアスキャンというレジスタ割り付けのアルゴリズム • template-style code generator • asmの生成はあまり頑張らない。LIRからシーケンシャルに生成 C1コンパイラの構成 hotspot/src/share/vm • c1 <-- C1コンパイラの本体 • compiler <-- コンパイラの抽象クラス • runtime <-- JVMのruntime部分 hotspot/src/share/vm/c1 C1コンパイラ 全体で36kstep top5 c1_LinerScan 7700step LinerScanでレジスタ割り付け c1_LIR 4300step LIR(Low-Level IRの定義) c1_GraphBuilder 4200step BytecodeからHIRへの変換 c1_LIRGenerator 3500step HIRからLIRへの変換 c1_Instruction 3300step HIR(High-Level IR)の定義 vm/c1/* c1_CFGPrinter.cpp <-- -XX:+PrintCFGToFile オプションを指定時、 c1_CFGPrinter.hpp 中間表現のHIRやLIRをxmlで出力。c1visualizerで解析する c1_Canonicalizer.cpp <-- HIRへ変換する際に正規化する c1_Canonicalizer.hpp c1_GraphBuilderから呼ばれる c1_CodeStubs.hpp <-- LIRやAssemblerで挿入される、JVMのciXX/runtime向けのStub c1_Compilation.cpp <-- C1コンパイラのコントローラー Driver??? c1_Compilation.hpp c1_Compiler.cpp <-- C1コンパイラの本体 c1_Compiler.hpp c1_Defs.cpp <-- architecture依存の各種定義ファイル レジスタとか c1_Defs.hpp c1_FpuStackSim.hpp <-- architecture依存のFPUStackのシミュレータの定義ファイル c1_FrameMap.cpp <-- architecture依存のFrameMapや仮想レジスタやCallingConvension c1_FrameMap.hpp c1_GraphBuilder.cpp <-- BytecodeからHIRへの変換 c1_GraphBuilder.hpp 各種最適化も行う(inlining, devirtualize, canonicalize c1_IR.cpp <-- IRの定義 c1_IR.hpp HIR/LIR/BB/各種helperを統合したIRという名のDescripter c1_Instruction.cpp <-- HIRの定義や、IRクラスのUtility c1_Instruction.hpp c1_InstructionPrinter.cpp <-- HIRのprinter 見やすいように情報を絞って整形して表示する c1_InstructionPrinter.hpp c1_LIR.cpp <-- LIRの定義 c1_LIR.hpp c1_LIRAssembler.cpp <-- LIRからAsmのemitter兼helper Asmのコード生成 c1_LIRAssembler.hpp c1_LIRGenerator.cpp <-- HIRからLIRへの変換 3
  • 8. コンパイル前の動作 c1_LIRGenerator.hpp 命令選択、レジスタ割り付け、LIRレベルの最適化も行う。 c1_LinearScan.cpp <-- LinearScanレジスタ割り付け c1_LinearScan.hpp c1_MacroAssembler.hpp <-- architecture依存のAsm出力用マクロ(Assember向けpsuedo code) c1_Optimizer.cpp <-- HIR向け各種最適化 Eliminate (const expr|blocks|null checks) c1_Optimizer.hpp c1_Runtime1.cpp <-- C1コンパイラのRuntime JVM本体のruntimeとの橋渡し c1_Runtime1.hpp c1_ValueMap.cpp <-- HIR向け最適化 ValueNumberingの本体 c1_ValueMap.hpp c1_ValueSet.cpp <-- HIR向けADT @todo c1_ValueSet.hpp c1_ValueStack.cpp <-- HIR向けADT @todo c1_ValueStack.hpp c1_ValueType.cpp <-- C1コンパイラ内部のIR向け型定義 c1_ValueType.hpp c1_globals.cpp <-- C1コンパイラ向けのオプション定義 c1_globals.hpp ※ architecture依存と書いたものは、hotspot/src/cpu/XXX/vm の下に本体がいる。 ※ architectureは、x86_32/x86_64 sparc zero がある コンパイル前の動作 JITコンパイラ JVMは、最初bytecodeをclassloaderが呼び出した後、インタプリタ実行を行う。 インタプリタ実行中にプロファイルを行い、条件を満たしたらJITコンパイルする JITコンパイルは、コンパイラの抽象クラス経由で操作する。 コンパイラクラスは3種類ある. C1/C2/Shark C1コンパイラ -clientオプション指定時のコンパイラ コンパイル時間が短く、メモリ使用量もそこそこ。 大した最適化をしない割にそこそこ高速に動作するコード を生成するのが特徴 JVM間の比較では、ベンチマーク結果がそこそこ高い。 C2コンパイラ -serverオプション指定時のコンパイラ。今回は扱わない。 コンパイル時間はそこそこ長く、C1より高速に動作するコードを生成する。 また、コンパイル時のメモリも 大きく消費する。 詳細は、vm/opto参照。C1とは中間言語が異なり、Idealと呼ばれる中間言語。 Sharkコンパイラ 使い方はまだちゃんと調べてない。 4
  • 9. JITコンパイラが呼ばれる仕組み LLVMと連携してJITコンパイルを行う. JITコンパイラをC1/C2ではなく、LLVMを使うということ。JVMの制 御はそのまま。 Sharkは、method単位でBytecodeをBitcodeに変換したのち、 LLVMに渡してJITコンパイルする。 LLVMにBitcodeを渡す際に何も小細工しないので、脱仮想化とかEscapeAnalysisとかさっぱり LLVMのBitcod eにMetadataを埋め込んで、 (たとえば、このcallはこのメソッドに脱仮想化候補だとか、allocaはstack/regi ster割り付け可能だとか) LLVMのJITコンパイラ起動時、上記metadata用最適化パスをオプションで渡せば連 携できるはず。 いろいろと夢広がる。 現在は、対応アーキテクチャを増やすために使っている ex) ARM PowerPC PTX CBac kend LLVM 3.0 のReleaseNoteから、Sharkの連携やIcedTeaとの連携のことがかかれているので、 興味があるかた はLLVMのページへ JITコンパイラが呼ばれる仕組み compileBrokerがJITコンパイラを生成し、メソッド単位でコンパイルする compiler::compile_method() compileBroker compiler/abstructCompiler compile_method(ciEnv*, ciMethod*, int entry_bci) 条件を満たしたときにJITコンパイラを生成し、メソッド単位でJITコンパイルを行う。 • 条件を満たしたときに ... vm/runtime/compilationPolicy • JITコンパイラを生成 ... vm/compiler/compileBroker JITコンパイラは、JVMがメモリを確保して、別スレッドでコンパイルブローカーに処理を移譲する。 JVMTIを使うので、スレッドが切れていて、処理が追いにくい。 また、スレッド並列で、インタプリタと並行してJITコンパイルは走るが、 -Xbatchオプションを指定すると、JITコンパイル中にインタプリタ実行を停止することができる。 compileBroker::compilation_init() // ------------------------------------------------------------------ // CompileBroker::compilation_init // // Initialize the Compilation object void CompileBroker::compilation_init() { _last_method_compiled[0] = '0'; #ifndef SHARK // Set the interface to the current compiler(s). int c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple); int c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization); #ifdef COMPILER1 if (c1_count > 0) { _compilers[0] = new Compiler(); } #endif // COMPILER1 #ifdef COMPILER2 if (c2_count > 0) { _compilers[1] = new C2Compiler(); } #endif // COMPILER2 #else // SHARK int c1_count = 0; 5
  • 10. JITコンパイルの入出力 int c2_count = 1; _compilers[1] = new SharkCompiler(); #endif // SHARK JITコンパイルの入出力 JVMのJITコンパイラは、ciMethodクラスが入力 compiler::compile_method() compiler/abstructCompiler compile_method(ciEnv*, ciMethod*, int entry_bci) JITコンパイラの出力の形式は複数存在する。 • method->codeの書き換え • もし書き換え対象のメソッドを今実行中だったら。。。 JITコンパイルの入り口のメソッド CompileBroker::compile_method_base() void CompileBroker::compile_method_base(methodHandle method, int osr_bci, int comp_level, methodHandle hot_method, int hot_count, const char* comment, TRAPS) { JITコンパイルする条件 JVMのインタプリタ実行中にprofileを行い、 下記に示すカウンタをカウントアップする。 • invocation count • メソッドの呼び出し回数をカウント • backward branch count • ループの実行回数をカウント invocation countのカウントアップ: 6
  • 11. JITコンパイルの入出力 bytecodeInterpreter.cpp::BytecodeInterpreter::run() case method_entry: { THREAD->set_do_not_unlock(); // count invocations assert(initialized, "Interpreter not initialized"); if (_compiling) { if (ProfileInterpreter) { METHOD->increment_interpreter_invocation_count(); } INCR_INVOCATION_COUNT; if (INVOCATION_COUNT->reached_InvocationLimit()) { CALL_VM((void)InterpreterRuntime::frequency_counter_overflow(THREAD, NULL), handle_exception); // We no longer retry on a counter overflow // istate->set_msg(retry_method); // THREAD->clr_do_not_unlock(); // return; } SAFEPOINT; } if ((istate->_stack_base - istate->_stack_limit) != istate->method()->max_stack() + 1) { // initialize os::breakpoint(); } //memo frequency_counter_overflowでJITコンパイラを呼ぶはず backward branch countのカウントアップ CASE(_goto): { int16_t offset = (int16_t)Bytes::get_Java_u2(pc + 1); address branch_pc = pc; UPDATE_PC(offset); DO_BACKEDGE_CHECKS(offset, branch_pc); CONTINUE; } CASE(_goto_w): { int32_t offset = Bytes::get_Java_u4(pc + 1); address branch_pc = pc; UPDATE_PC(offset); DO_BACKEDGE_CHECKS(offset, branch_pc); CONTINUE; } #define DO_BACKEDGE_CHECKS(skip, branch_pc) if ((skip) <= 0) { if (UseLoopCounter) { bool do_OSR = UseOnStackReplacement; BACKEDGE_COUNT->increment(); if (do_OSR) do_OSR = BACKEDGE_COUNT->reached_InvocationLimit(); if (do_OSR) { nmethod* osr_nmethod; OSR_REQUEST(osr_nmethod, branch_pc); if (osr_nmethod != NULL && osr_nmethod->osr_entry_bci() != InvalidOSREntryBci) { intptr_t* buf = SharedRuntime::OSR_migration_begin(THREAD); 7
  • 12. JITコンパイルの入出力 istate->set_msg(do_osr); istate->set_osr_buf((address)buf); istate->set_osr_entry(osr_nmethod->osr_entry()); return; } } } /* UseCompiler ... */ INCR_INVOCATION_COUNT; SAFEPOINT; } インタプリタがprofileのカウンタを更新する様子 gdb stack trace Breakpoint 5, NonTieredCompPolicy::reset_counter_for_invocation_event (this=0x807a738, m=...) at /home/elise/language/openjdk6/hotspot/src/share/vm/runtime/compilationPolicy.cpp:189 189 m->invocation_counter()->set_carry(); (gdb) up #1 0x004cbdd5 in SimpleCompPolicy::method_invocation_event (this=0x807a738, m=..., __the_th at /home/elise/language/openjdk6/hotspot/src/share/vm/runtime/compilationPolicy.cpp:394 394 reset_counter_for_invocation_event(m); (gdb) #2 0x004cba19 in NonTieredCompPolicy::event (this=0x807a738, method=..., inlinee=..., branc comp_level=CompLevel_none, __the_thread__=0x806d000) at /home/elise/language/openjdk6/hotspot/src/share/vm/runtime/compilationPolicy.cpp:323 323 method_invocation_event(method, CHECK_NULL); (gdb) #3 0x005dafd2 in InterpreterRuntime::frequency_counter_overflow_inner (thread=0x806d000, br at /home/elise/language/openjdk6/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp:854 854 nmethod* osr_nm = CompilationPolicy::policy()->event(method, method, branch_bci, bci, CompLevel_none, (gdb) #4 0x005daced in InterpreterRuntime::frequency_counter_overflow (thread=0x806d000, branch_b at /home/elise/language/openjdk6/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp:826 826 nmethod* nm = frequency_counter_overflow_inner(thread, branch_bcp); (gdb) #5 0xb5fef92c in ?? () (gdb) //interpreterのgoto命令実行時にカウントアップ //memo OSR_REQESTマクロの中で、frequency_counter_overflow()を呼び出し JITコンパイラが呼ばれるのは、2つのケース 対象のメソッドの呼び出し回数が規定回数以上になった場合 • 通常のJITコンパイル。メソッド単位でJITコンパイルする。 次回呼ばれた際にインタプリタではなく、JITコンパイルしたコードを実行する 対象のループのバックエッジの通過回数が規定回数以上になった場合 • 現在実行中のメソッドをJITコンパイルする。 現在実行中のメソッドなので、インタプリタからJITしたコードへ遷移するのが難しい インタプリタ実行中からJITしたコードへ遷移する技術をOnStackReplacementと呼ぶ。 おもにsafepointを設けて(分岐の前や、分岐の集合地点) インタプリタ実行中のFrameとJITコンパイルしたコードのFrameを記録、計算し、 遷移できるようにテーブルを作成するはず //OnStackReplacementは、runtime/sharedRuntime.cpp::SharedRuntime::OSR_migration_begin() //詳細は"コンパイラとバーチャルマシン"っていう書籍が図入りで説明している 8
  • 13. JITコンパイルする際のしきい値 JITコンパイルする際のしきい値 JITコンパイルのしきい値は、clientコンパイラの場合、2000回, serverコンパイラの場合、15000回のはず。 JITコンパイルのしきい値は、CompLevel で計算方法が異なるらしい CompLevel_simple or CompLevel_full_optimization or CompLevel_limited_profile or CompLevel_full_profil e オプション: • -XX:CompileThreshold=xxx デフォルト: • Tier3CompileThreshold 2000 • Tier4CompileThreshold 15000 compile_methodが呼ばれた際のstack trace gdb stack trace // topからdownしていきます #6 0xb5fef92c in ?? () <-- template intepreter経由なのでこれ以上終えない (gdb) down #5 0x005daced in InterpreterRuntime::frequency_counter_overflow (thread=0x806d000, branch_b at /home/elise/language/openjdk6/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp:826 826 nmethod* nm = frequency_counter_overflow_inner(thread, branch_bcp); (gdb) #4 0x005dafd2 in InterpreterRuntime::frequency_counter_overflow_inner (thread=0x806d000, br at /home/elise/language/openjdk6/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp:854 854 nmethod* osr_nm = CompilationPolicy::policy()->event(method, method, branch_bci, bci, CompLevel_none, (gdb) #3 0x004cba19 in NonTieredCompPolicy::event (this=0x807a738, method=..., inlinee=..., branc comp_level=CompLevel_none, __the_thread__=0x806d000) at /home/elise/language/openjdk6/hotspot/src/share/vm/runtime/compilationPolicy.cpp:323 323 method_invocation_event(method, CHECK_NULL); (gdb) #2 0x004cbe50 in SimpleCompPolicy::method_invocation_event (this=0x807a738, m=..., __the_th at /home/elise/language/openjdk6/hotspot/src/share/vm/runtime/compilationPolicy.cpp:402 402 m, hot_count, comment, CHECK); (gdb) #1 0x004cf34e in CompileBroker::compile_method (method=..., osr_bci=-1, comp_level=1, hot_m comment=0x94b7f6 "count", __the_thread__=0x806d000) at /home/elise/language/openjdk6/hotspot/src/share/vm/compiler/compileBroker.cpp:1084 1084 compile_method_base(method, osr_bci, comp_level, hot_method, hot_count, comment, CHECK_0); (gdb) #0 CompileBroker::compile_method_base (method=..., osr_bci=-1, comp_level=1, hot_method=... comment=0x94b7f6 "count", __the_thread__=0x806d000) at /home/elise/language/openjdk6/hotspot/src/share/vm/compiler/compileBroker.cpp:840 840 if (!_initialized ) { InterpreterInvocationLimitとInterpreterBackwardBranchLimitの設定 void InvocationCounter::reinitialize(bool delay_overflow) { // define states guarantee((int)number_of_states <= (int)state_limit, "adjust number_of_state_bits"); def(wait_for_nothing, 0, do_nothing); if (delay_overflow) { def(wait_for_compile, 0, do_decay); } else { def(wait_for_compile, 0, dummy_invocation_counter_overflow); } InterpreterInvocationLimit = CompileThreshold << number_of_noncount_bits; 9
  • 14. C1コンパイラの内部構造 InterpreterProfileLimit = ((CompileThreshold * InterpreterProfilePercentage) / 100)<< number_of_noncount_bit // When methodData is collected, the backward branch limit is compared against a // methodData counter, rather than an InvocationCounter. In the former case, we // don't need the shift by number_of_noncount_bits, but we do need to adjust // the factor by which we scale the threshold. if (ProfileInterpreter) { InterpreterBackwardBranchLimit = (CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercen } else { InterpreterBackwardBranchLimit = ((CompileThreshold * OnStackReplacePercentage) / 100) << number_of_non } ちなみに、clientの場合 InterpreterInvocationLimit = 12000 InterpreterBackwardBranchLimit = 111960 serverの場合 InterpreterInvocationLimit = 80000 InterpreterBackwardBranchLimit = 10700 clientコンパイラのしきい値って、メソッド呼び出しが1500回で、OnStackReplacementが14000回じゃないの? C1コンパイラの内部構造 大まかなコンパイルの概要 method単位で、BytecodeからHIRへの変換 HIRからLIRへの変換 LIRからMachine codeへの変換 コンパイラ全体の制御 c1_Compiler.cpp コンパイルの入り口 // 入力はciMethond* method <-- bytecode method単位 void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) compile_method() c1_Compilation.cpp コンパイラの全体制御 Compilation::compile_method() method()->break_at_execute() compile_java_method() install_code(frame_size) Compilation::compile_java_method() build_hir() _hir = new IR() _hir->optimize() _hir->split_critical_edges() _hir->compute_code() GlobalValueNumbering gvn(_hir) _hir->compute_use_counts() 10
  • 15. BytecodeからHIRへの変換 FrameMap() emit_lir() LIRGenerator gen() hir()->iterate_linear_scan_order() LinearScan allocator = new LinearScan() allocator->do_linear_scan() compute_local_live_sets() compute_global_live_sets() build_intervals() allocate_registers() resolve_data_flow() propagate_spill_slots() eliminate_spill_moves() assign_reg_num() allocate_fpu_stack() EdgeMoveOptimizer::optimize(ir()->code()) ControlFlowOptimizer::optimize(ir()->code()) emit_code_body() setup_code_buffer() _masm = new C1_MacroAssembler() LIR_Asssembler lir_asm() lir_asm.emit_code() emit_code_epilog() generate code for deopt handler BytecodeからHIRへの変換 BytecodeからHIRへの変換は、大体1Bytecodeにつき、1HIRに変換する IR() IR()->IRScope()->XHandlers() IRScope() _requires_phi_function IR()->IRScope()->IRScope() _start = GraphBuilder gm() constructor GraphBuilder() GraphBuilder::iterate_all_blocks() GraphBuilder::iterate_bytecodes_for_block(int bci) Bytecodeの各命令ごとに処理をわけているところ GraphBuilder::iterate_bytecodes_for_block(int bci): _skip_block = false; assert(state() != NULL, "ValueStack missing!"); ciBytecodeStream s(method()); s.reset_to_bci(bci); int prev_bci = bci; scope_data()->set_stream(&s); // iterate Bytecodes::Code code = Bytecodes::_illegal; bool push_exception = false; if (block()->is_set(BlockBegin::exception_entry_flag) && block()->next() == NULL) { // first thing in the exception entry block should be the exception object. push_exception = true; } 11
  • 16. if_icmpXXの変換 while (!bailed_out() && last()->as_BlockEnd() == NULL && (code = stream()->next()) != ciBytecodeStream::EOBC() && (block_at(s.cur_bci()) == NULL || block_at(s.cur_bci()) == block())) { assert(state()->kind() == ValueStack::Parsing, "invalid state kind"); // Check for active jsr during OSR compilation if (compilation()->is_osr_compile() && scope()->is_top_scope() && parsing_jsr() && s.cur_bci() == compilation()->osr_bci()) { bailout("OSR not supported while a jsr is active"); } if (push_exception) { apush(append(new ExceptionObject())); push_exception = false; } // handle bytecode switch (code) { case Bytecodes::_nop : /* nothing to do */ break; case Bytecodes::_aconst_null : apush(append(new Constant(objectNull ))); break; case Bytecodes::_iconst_m1 : ipush(append(new Constant(new IntConstant (-1)))); break; case Bytecodes::_iconst_0 : ipush(append(new Constant(intZero ))); break; case Bytecodes::_iconst_1 : ipush(append(new Constant(intOne ))); break; case Bytecodes::_iconst_2 : ipush(append(new Constant(new IntConstant ( 2)))); break; case Bytecodes::_iconst_3 : ipush(append(new Constant(new IntConstant ( 3)))); break; case Bytecodes::_iconst_4 : ipush(append(new Constant(new IntConstant ( 4)))); break; case Bytecodes::_iconst_5 : ipush(append(new Constant(new IntConstant ( 5)))); break; ... case Bytecodes::_invokevirtual : // fall through case Bytecodes::_invokespecial : // fall through case Bytecodes::_invokestatic : // fall through case Bytecodes::_invokedynamic : // fall through case Bytecodes::_invokeinterface: invoke(code); break; invoke命令を変換時にdevirtualize/inline展開する • @todo codeを追う • @todo devirtualizeの仕組み • @todo is_profile_callの仕組み if_icmpXXの変換 if_icmpXXの変換が分かりやすい Bytecodeのiterate case Bytecodes::_if_icmpeq : if_same(intType , If::eql); break; case Bytecodes::_if_icmpne : if_same(intType , If::neq); break; case Bytecodes::_if_icmplt : if_same(intType , If::lss); break; case Bytecodes::_if_icmpge : if_same(intType , If::geq); break; case Bytecodes::_if_icmpgt : if_same(intType , If::gtr); break; case Bytecodes::_if_icmple : if_same(intType , If::leq); break; case Bytecodes::_if_acmpeq : if_same(objectType, If::eql); break; case Bytecodes::_if_acmpne : if_same(objectType, If::neq); break; ifの変換部 12
  • 17. invokeの変換 void GraphBuilder::if_same(ValueType* type, If::Condition cond) { ValueStack* state_before = copy_state_before(); Value y = pop(type); Value x = pop(type); if_node(x, cond, y, state_before); } void GraphBuilder::if_node(Value x, If::Condition cond, Value y, ValueStack* state_before) { BlockBegin* tsux = block_at(stream()->get_dest()); BlockBegin* fsux = block_at(stream()->next_bci()); bool is_bb = tsux->bci() < stream()->cur_bci() || fsux->bci() < stream()->cur_bci(); Instruction *i = append(new If(x, cond, false, y, tsux, fsux, is_bb ? state_before : NULL, is_bb)); if (is_profiling()) { If* if_node = i->as_If(); if (if_node != NULL) { // Note that we'd collect profile data in this method if we wanted it. compilation()->set_would_profile(true); // At level 2 we need the proper bci to count backedges if_node->set_profiled_bci(bci()); if (profile_branches()) { // Successors can be rotated by the canonicalizer, check for this case. if_node->set_profiled_method(method()); if_node->set_should_profile(true); if (if_node->tsux() == fsux) { if_node->set_swapped(true); } } return; } // Check if this If was reduced to Goto. Goto *goto_node = i->as_Goto(); if (goto_node != NULL) { compilation()->set_would_profile(true); if (profile_branches()) { goto_node->set_profiled_method(method()); goto_node->set_profiled_bci(bci()); goto_node->set_should_profile(true); // Find out which successor is used. if (goto_node->default_sux() == tsux) { goto_node->set_direction(Goto::taken); } else if (goto_node->default_sux() == fsux) { goto_node->set_direction(Goto::not_taken); } else { ShouldNotReachHere(); } } return; } } } invokeの変換 BytecodeのinvokeXXXは、invoke()メソッドで処理する。 invokeを処理する際に、呼び出し対象が一意に定まるか判定し、 もし定まる場合は、inline展開を試行する。 13
  • 18. dependency また、invokevirtualやinvokeinterfaceのdevirtual化(invokespecialとみなす)を行い、 積極的にinline展開を試行 する invoke switch (code) { case Bytecodes::_nop : /* nothing to do */ break; ... case Bytecodes::_invokevirtual : // fall through case Bytecodes::_invokespecial : // fall through case Bytecodes::_invokestatic : // fall through case Bytecodes::_invokedynamic : // fall through case Bytecodes::_invokeinterface: invoke(code); break; GraphBuilder::invoke(Bytecodes::Code) ciMethod* cha_monomorphic_target ciMethod* exact_target if (!target->is_static()) { type_is_exact exact_target = target->resolve_invoke(calling_klass, receiver_klass); code = invokespecial invokevirtual || invokeinterfaceの場合 cha_monomorphic_target = target->find_monomorphic_target(calling_klass, callee_holder, actual_recv); invokeinterface && singleton? CheckCast* c = new CheckCast(klass, receiver, copy_state_for_exception()) set_incompatible_class_change_check() cha_monomorphic_targetがabstractだった場合、 NULL cha_monomorphic_targetが見つかった場合 dependency_recorder()->assert_unique_concrete_method(actual_recv, cha_monomorphic_target) code = invokespecial もし上記処理で一意に分かったら try_inline(inline_target, ); try_inline_full() <-- 200stepの関数なので、あまり見たくない 最終的には、iterate_bytecode_ みたいなのを呼び出す is_profiling() target_klass = cha_monomorphic_target->holder() || exact_garget->holder() profile_call(recv, target_klass) dependency dependencyは、JVM上での制約をチェックし、違反した場合イベントを起動してくれるイベントハンドラみたい なもの よく脱仮想化する際に使用し、もし脱仮想化の条件が崩れた場合、脱最適化するようにイベントを登録する 脱仮想化の条件が崩れる例として、newで新しいクラスを作成した時や、classloader、redefine void GraphBuilder::invoke(Bytecodes::Code code) if (cha_monomorphic_target != NULL) { if (!(target->is_final_method())) { // If we inlined because CHA revealed only a single target method, // then we are dependent on that target method not getting overridden // by dynamic class loading. Be sure to test the "static" receiver 14
  • 19. dependency // dest_method here, as opposed to the actual receiver, which may // falsely lead us to believe that the receiver is final or private. dependency_recorder()->assert_unique_concrete_method(actual_recv, cha_monomorphic_target); } code = Bytecodes::_invokespecial; } GraphBuilder::call_register_finalizer() ciInstanceKlass* ik = compilation()->method()->holder(); //finalだったら、一意 if (ik->is_final()) { exact_type = ik; //クラス階層解析を使用するかつサブクラスを持ってない } else if (UseCHA && !(ik->has_subklass() || ik->is_interface())) { // test class is leaf class compilation()->dependency_recorder()->assert_leaf_type(ik); exact_type = ik; } else { declared_type = ik; } Dependencyを試す場合のオプション -XX:+TraceDependencies -XX:+VerifyDependencies dependencyの制約にひっかかり、deoptimizeするサンプルプログラム deoptimize sample interface getter { public int num(); public int get(); } class Bgetter implements getter { public int num() { return 1; } public int get() { int sum = 0; for (int i=0; i<100; i++) { sum += num(); } return sum; } } class Cgetter implements getter { public int num() { return 2; } public int get() { int sum = 0; for (int i=0; i<100; i++) { sum += num(); } return sum; } } public class iftest { 15
  • 20. dependency static final long LEN=100000000; public static void main(String args[]) { getter f = new B(); long sum=0; for( long i=0; i<LEN; i++ ) { sum += f.get(); } // getter f2 = new C(); //devirtualize System.out.println(sum); } } getter f2のコメントを外すと、new C()された際にdependencyが反応し、deoptimizeが走る log Failed dependency of type unique_concrete_method context = *getter method = {method} 'get' '()I' in 'B' witness = *getter code: 9434 1% nmethod iftest::main @ 13 (58 bytes) Marked for deoptimization context = getter dependee = C context supers = 1, interfaces = 1 Compiled (c1) 9434 1% nmethod iftest::main @ 13 (58 bytes) total in heap [0xb5891388,0xb5891acc] = 1860 relocation [0xb5891458,0xb5891500] = 168 main code [0xb5891500,0xb58917c0] = 704 stub code [0xb58917c0,0xb589180c] = 76 oops [0xb589180c,0xb5891818] = 12 scopes data [0xb5891818,0xb58918ec] = 212 scopes pcs [0xb58918ec,0xb5891aac] = 448 dependencies [0xb5891aac,0xb5891ab0] = 4 nul chk table [0xb5891ab0,0xb5891acc] = 28 Dependencies: Dependency of type unique_concrete_method context = *getter method = {method} 'get' '()I' in 'B' [nmethod<=klass]getter checking (true) 9434 1% nmethod iftest::main @ 13 (58 bytes) depdnecyのcheck処理が呼ばれた際のstack trace Breakpoint 4, Dependencies::DepStream::check_dependency_impl (this=0xfd05c8, changes=0xfd06f8) at /home/elise/language/openjdk6/hotspot/src/share/vm/code/dependencies.cpp:1449 1449 if (TraceDependencies) { #1 0x00530b7e in Dependencies::DepStream::spot_check_dependency_at (this=0xfd05c8, changes= at /home/elise/language/openjdk6/hotspot/src/share/vm/code/dependencies.cpp:1464 1464 return check_dependency_impl(&changes); #0 Dependencies::DepStream::check_dependency_impl (this=0xfd05c8, changes=0xfd06f8) at /home/elise/language/openjdk6/hotspot/src/share/vm/code/dependencies.cpp:1449 1449 if (TraceDependencies) { #1 0x00530b7e in Dependencies::DepStream::spot_check_dependency_at (this=0xfd05c8, changes= at /home/elise/language/openjdk6/hotspot/src/share/vm/code/dependencies.cpp:1464 1464 return check_dependency_impl(&changes); #2 0x007573ae in nmethod::check_dependency_on (this=0xb60d4388, changes=...) at /home/elise/language/openjdk6/hotspot/src/share/vm/code/nmethod.cpp:2063 2063 if (deps.spot_check_dependency_at(changes) != NULL) { #3 0x005b6030 in instanceKlass::mark_dependent_nmethods (this=0xb212bde0, changes=...) 16
  • 21. dependency at /home/elise/language/openjdk6/hotspot/src/share/vm/oops/instanceKlass.cpp:1406 1406 if (nm->is_alive() && !nm->is_marked_for_deoptimization() && nm->check_dependency_on(changes)) { #4 0x004b0f83 in CodeCache::mark_for_deoptimization (changes=...) at /home/elise/language/openjdk6/hotspot/src/share/vm/code/codeCache.cpp:641 641 number_of_marked_CodeBlobs += instanceKlass::cast(d)->mark_dependent_nmethods(changes); #5 0x00866302 in Universe::flush_dependents_on (dependee=...) at /home/elise/language/openjdk6/hotspot/src/share/vm/memory/universe.cpp:1182 1182 if (CodeCache::mark_for_deoptimization(changes) > 0) { #6 0x00825729 in SystemDictionary::add_to_hierarchy (k=..., __the_thread__=0x806cc00) at /home/elise/language/openjdk6/hotspot/src/share/vm/classfile/systemDictionary.cpp:1727 1727 Universe::flush_dependents_on(k); #7 0x00824e09 in SystemDictionary::define_instance_class (k=..., __the_thread__=0x806cc00) at /home/elise/language/openjdk6/hotspot/src/share/vm/classfile/systemDictionary.cpp:1506 1506 add_to_hierarchy(k, CHECK); // No exception, but can block #8 0x00823df1 in SystemDictionary::resolve_from_stream (class_name=..., class_loader=..., p verify=true, __the_thread__=0x806cc00) at /home/elise/language/openjdk6/hotspot/src/share/vm/classfile/ 1138 define_instance_class(k, THREAD); #9 0x0064c2d9 in jvm_define_class_common (env=0x806cd3c, name=0xfd0eac "C", loader=0xfd0fac len=316, pd=0xfd0f98, source=0xfd0aac "file:/home/elise/language/java/sample6/", verify=1 '001', __the_t at /home/elise/language/openjdk6/hotspot/src/share/vm/prims/jvm.cpp:864 864 CHECK_NULL); #10 0x0064c7d6 in JVM_DefineClassWithSource (env=0x806cd3c, name=0xfd0eac "C", loader=0xfd0f len=316, pd=0xfd0f98, source=0xfd0aac "file:/home/elise/language/java/sample6/") at /home/elise/language/openjdk6/hotspot/src/share/vm/prims/jvm.cpp:884 884 return jvm_define_class_common(env, name, loader, buf, len, pd, source, true, THREAD); #11 0x00ff7942 in Java_java_lang_ClassLoader_defineClass1 (env=0x806cd3c, loader=0xfd0fac, n length=316, pd=0xfd0f98, source=0xfd0f94) at ../../../src/share/native/java/lang/ClassLoader.c:151 151 result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource); @todo DepStream::check_dependency_impl() code/dependencies.cpp invokenの際は、unique_concreate_method CHAで再度チェックしている klassOop Dependencies::DepStream::check_dependency_impl(DepChange* changes) { assert_locked_or_safepoint(Compile_lock); klassOop witness = NULL; switch (type()) { case evol_method: witness = check_evol_method(method_argument(0)); break; case leaf_type: witness = check_leaf_type(context_type()); break; case abstract_with_unique_concrete_subtype: witness = check_abstract_with_unique_concrete_subtype(context_type(), type_argument(1), changes); break; case abstract_with_no_concrete_subtype: witness = check_abstract_with_no_concrete_subtype(context_type(), changes); break; case concrete_with_no_concrete_subtype: witness = check_concrete_with_no_concrete_subtype(context_type(), changes); break; case unique_concrete_method: witness = check_unique_concrete_method(context_type(), 17
  • 22. プロファイラ method_argument(1), changes); break; case abstract_with_exclusive_concrete_subtypes_2: witness = check_abstract_with_exclusive_concrete_subtypes(context_type(), type_argument(1), type_argument(2), changes); break; case exclusive_concrete_methods_2: witness = check_exclusive_concrete_methods(context_type(), method_argument(1), method_argument(2), changes); break; case no_finalizable_subclasses: witness = check_has_no_finalizable_subclasses(context_type(), changes); break; default: witness = NULL; ShouldNotReachHere(); break; } deoptimizeも、thread並列で行うが、実際にコードを置換する際には全体をmutexで止める dependenceからDeoptimizeを呼び出す場所 // Flushes compiled methods dependent on dependee. void Universe::flush_dependents_on(instanceKlassHandle dependee) { assert_lock_strong(Compile_lock); if (CodeCache::number_of_nmethods_with_dependencies() == 0) return; // CodeCache can only be updated by a thread_in_VM and they will all be // stopped dring the safepoint so CodeCache will be safe to update without // holding the CodeCache_lock. DepChange changes(dependee); // Compute the dependent nmethods if (CodeCache::mark_for_deoptimization(changes) > 0) { //<----- koko // At least one nmethod has been marked for deoptimization VM_Deoptimize op; VMThread::execute(&op); } } dependenciesのルールから、VM_deoptimizeがキックされ、 dependenciesに引っかかった要素をdeoptimizeする deoptimizeも、2種類あり、mutexで止めた際に、実行中でないなら、oopsのcodeを書き換える抱け。 もし実行中だったら、frameを書き換えて、JITコンパイルしたコードからintepreter実行に切り替える プロファイラ C1コンパイラでは、 プロファイルした情報を活用する部分と、 C1コンパイラが生成したコードにプロファイルする命令を埋め込む部分がある。 プロファイル系のオプション 18
  • 23. HIR から LIR への変換 product(bool, C1ProfileCalls, true, "Profile calls when generating code for updating MDOs") // dead product(bool, C1ProfileVirtualCalls, true, "Profile virtual calls when generating code for updating MDOs") product(bool, C1ProfileInlinedCalls, true, "Profile inlined calls when generating code for updating MDOs") product(bool, C1ProfileBranches, true, "Profile branches when generating code for updating MDOs") product(bool, C1ProfileCheckcasts, true, "Profile checkcasts when generating code for updating MDOs") 主にプロファイルはインタプリタが行っているが、 C1コンパイラがJITコンパイルしたコードにも埋め込み可能になっている。 JITコンパイルしたコードに埋め込む場合、2回目、3回目のJITコンパイルが行われるはず 複数回のJITコンパイルの条件は不明。。 プロファイルの様子は、TemplateIntepreterの解説に期待 HIR から LIR への変換 HIRからLIRへの変換はLIRGeneratorが行う。 visitorでHIRを走査し、HIRに対して複数のLIRへ分解する LIRは仮想レジスタを無限に持つことを仮定し、レジスタ割り付けで実レジスタを割り振る void LIRGenerator::block_do(BlockBegin* block) block_do_prolog(block); __ branch_destination(block->label()); <-- label設定 set_block(block); for (Instruction* instr = block; instr != NULL; instr = instr->next()) { if (instr->is_pinned()) do_root(instr); } set_block(NULL); block_do_epilog(block); void LIRGenerator::do_IfOp(IfOp* x) // Code for : x->x() {x->cond()} x->y() ? x->tval() : x->fval() LIRItem left(x->x(), this); LIRItem right(x->y(), this); left.load_item(); if (can_inline_as_constant(right.value())) { right.dont_load_item(); } else { right.load_item(); } LIRItem t_val(x->tval(), this); LIRItem f_val(x->fval(), this); t_val.dont_load_item(); f_val.dont_load_item(); 19
  • 24. C1コンパイラのHIR最適化 LIR_Opr reg = rlock_result(x); __ cmp(lir_cond(x->cond()), left.result(), right.result()); __ cmove(lir_cond(x->cond()), t_val.result(), f_val.result(), reg, as_BasicType(x->x()->type())); } invokeの処理なんかは複雑で面白いかもしれない C1コンパイラのHIR最適化 HIR Optimizationは、BytecodeからHIRへ変換終わった後に行う c1_Compilation.cpp::build_hir() _hir->optimize(); IR::optimize() opt.eliminate_conditional_expressions(); opt.eliminate_blocks(); opt.eliminate_null_checks(); eliminate_conditional_expressions @todo 時間があればコードを追うこと CE_Eliminator::block_do()が本体 ブロックの終端のifを取得 ifはint型かobject型か判定 true block false block true_instruction false_instruction a = (b > c) ? b : c; BB: if ... then BBn false BBm BBn: const n goto BBs BBm: const m goto BBs BBs: phi [][] CEE Java: public static int CETest(int ret, int n,int m) { ret += (n < m) ? n : m; return ret; } CEE HIR B62: i179 = i103 - i76 i180 = i178 - i151 v186 = if i179 > i180 then B73 else B72 <-- replace i186 = ifop (i179 > i180) ixx, iyy; <-- add goto B74 B73: <-- delete v188 = goto B74 <-- delete 20
  • 25. GlobalValueNumbering B72: <-- delete v187 = goto B74 <-- delete B74: i189 = [i179,i180] <-- replace v190 = goto B70 B70: i191 = i151 + i189 GlobalValueNumbering @todo 時間があればコードを追うこと c1_ValueMap.hpp::GlobalValueNumbering(IR* ir) ShortLoopOptimizer short_loop_optimizer(this); for (int i = 1; i < num_blocks; i++) { BlockBegin* block = blocks->at(i); ... if (num_preds == 1) { // nothing to do here } else if (block->is_set(BlockBegin::linear_scan_loop_header_flag)) { // block has incoming backward branches -> try to optimize short loops if (!short_loop_optimizer.process(block)) { <-- ループは特別に処理 // loop is too complicated, so kill all memory loads because there might be // stores to them in the loop current_map()->kill_memory(); } } else { // only incoming forward branches that are already processed for (int j = 0; j < num_preds; j++) { BlockBegin* pred = block->pred_at(j); ValueMap* pred_map = value_map_of(pred); if (pred_map != NULL) { // propagate killed values of the predecessor to this block current_map()->kill_map(value_map_of(pred)); } else { // kill all memory loads because predecessor not yet processed // (this can happen with non-natural loops and OSR-compiles) current_map()->kill_memory(); } } } if (block->is_set(BlockBegin::exception_entry_flag)) { current_map()->kill_exception(); } TRACE_VALUE_NUMBERING(tty->print("value map before processing block: "); current_map()->print()); // visit all instructions of this block for (Value instr = block->next(); instr != NULL; instr = instr->next()) { assert(!instr->has_subst(), "substitution already set"); // check if instruction kills any values instr->visit(this); 21
  • 26. EscapeAnalysis if (instr->hash() != 0) { Value f = current_map()->find_insert(instr); <-- ここがキモ if (f != instr) { assert(!f->has_subst(), "can't have a substitution"); instr->set_subst(f); subst_count++; } } } // remember value map for successors set_value_map_of(block, current_map()); } EscapeAnalysis c1コンパイラからは呼ばれません!!! wimmerの資料によるとclientからも呼ばれるようだが、昔のJDKもしくはSun JDKだけなのかもしれない。 Serverだとbreakを確認できた。 Sharkだとifdef切ってるけど、多分動かないんだろうと推測 C1コンパイラのLIR最適化 EdgeMoveOptimizer c1_LinearScan.cpp::EdgeMoveOptimizer::optimize(BlockList* code) EdgeMoveOptimizer optimizer = EdgeMoveOptimizer(); // ignore the first block in the list (index 0 is not processed) for (int i = code->length() - 1; i >= 1; i--) { BlockBegin* block = code->at(i); if (block->number_of_preds() > 1 && !block->is_set(BlockBegin::exception_entry_flag)) { optimizer.optimize_moves_at_block_end(block); } if (block->number_of_sux() == 2) { optimizer.optimize_moves_at_block_begin(block); } } preds > 1 --> ブロックへのjumpが複数ある場合 CFGの合流ブロックとか、loopのheaderとか code sink みたいな処理 sux == 2 --> ブロックからのjumpが複数ある場合 分岐とか、loopのback_edgeとか code hoist みたいな処理 ControlFlowOptimizer c1_LiearScan.cpp::ControlFlowOptimize::optimize(BlockList* code) ControlFlowOptimizer optimizer = ControlFlowOptimizer(); // push the OSR entry block to the end so that we're not jumping over it. 22
  • 27. sample code factIf BlockBegin* osr_entry = code->at(0)->end()->as_Base()->osr_entry(); if (osr_entry) { int index = osr_entry->linear_scan_number(); assert(code->at(index) == osr_entry, "wrong index"); code->remove_at(index); code->append(osr_entry); } optimizer.reorder_short_loops(code); optimizer.delete_empty_blocks(code); optimizer.delete_unnecessary_jumps(code); optimizer.delete_jumps_to_return(code); reorder_short_loops() 下記のようなケースをpost jumpっぽくする end_block B4 (V) [35, 50] -> B3 dom B3 sux: B3 pred: B3 __bci__use__tid____instr____________________________________ 35 1 i19 31 38 1 i20 i15 * i19 41 2 i21 1 . 41 1 i22 i16 + i21 . 44 1 i23 a11[i16] (C) . 45 1 i24 i20 + i23 . 47 1 i26 i17 + i21 . 50 0 27 goto B3 (safepoint) header_block B3 (LHbV) [28, 32] -> B5 B4 dom B1 sux: B5 B4 pred: B1 B4 __bci__use__tid____instr____________________________________ . 32 0 18 if i17 >= i12 then B5 else B4 delete_unnecessary_jumps() last_branchが次のブロックへの飛び先だったらdelete cmp branch1 branch2の場合、branch1が次のブロックへのjumpだったら、 branch1を書き換えて、condの 条件を反転 branch2を削除 sample code factIf 入力ソースコードfactIf public static int factIf(int n) { int p; if (n > 1) { p = n * factIf(n - 1); } else { p = 1; } return p; } factIf Bytecode public static int factIf(int): Code: 0: iload_0 1: iconst_1 23
  • 28. sample code factIf 2: if_icmple 17 5: iload_0 6: iload_0 7: iconst_1 8: isub 9: invokestatic #3; //Method factIf:(I)I 12: imul 13: istore_1 14: goto 19 17: iconst_1 18: istore_1 19: iload_1 20: ireturn factIf HIR: static jint Fact.factIf(jint) B9: i4 = method parameter v32 = std entry B0 B0: i5 = 1 v6 = if i4 <= i5 then B2 else B1 B1: i7 = 1 i8 = i4 - i7 v15 = if i8 <= i7 then B7 else B6 B7: i21 = 1 v22 = goto B8 B6: i16 = 1 i17 = i8 - i16 i18 = invokestatic(i17) Fact.factIf(I)I i19 = i8 * i18 v20 = goto B8 B8: i23 = [i19,i21] v24 = goto B4 B4: i25 = i4 * i23 v26 = goto B3 B2: i27 = 1 v28 = goto B3 B3: i29 = [i25,i27] i30 = ireturn i29 factIf HIR CFG factIf HIR DFG 24
  • 29. sample code factIf factIf Optimized HIR static jint Fact.factIf(jint) B9: i4 = method parameter v32 = std entry B0 B0: i5 = 1 v6 = if i4 <= i5 then B2 else B1 B1: // deleted i7 = 1 i8 = i4 - i7 v15 = if i8 <= i7 then B7 else B6 B7: // deleted i21 = 1 v22 = goto B8 B6: // deleted i16 = 1 i17 = i8 - i5 // replaced i17 = i8 - i16 i18 = invokestatic(i17) Fact.factIf(I)I i19 = i8 * i18 v20 = goto B8 B8: i23 = [i19,i5] // replaced i23 = [i19,i21] // deleted v24 = goto B4 // deleted B4: i25 = i4 * i23 v26 = goto B3 B2: // deleted i27 = 1 v28 = goto B3 B3: i29 = [i25,i5] // replaced i29 = [i25,i27] i30 = ireturn i29 基本的には、HIRからLIRへシーケンシャルに変換する BBの入り口処理とかは遣るけどさ factIf translate HIR to LIR # # # # label B9 std_entry move ecx R41 branch AL B0 label B0 cmp R41 1 branch LE B2 branch AL B1 label B1 move R41 R42 25
  • 30. sample code factIf sub R42 1 R42 cmp R42 1 branch LE B7 branch AL B6 label B6 move R42 R43 sub R43 1 R43 move R43 ecx static call [static jint Fact.factIf(jint)] result eax bci:9 move eax R44 move R44 R45 mul R45 R42 R45 move R45 R46 branch AL B8 label B7 move 1 R46 branch AL B8 label B8 move R46 R47 mul R47 R41 move R47 R48 branch AL B3 label B2 move 1 B48 branch AL B3 label B3 move R48 eax return eax 26
  • 31. sample code factIf B9: std_entry move ecx R41 branch AL B0 B0: cmp R41 1 branch LE B2 branch AL B1 B1: move R41 R42 sub R42 1 R42 cmp R42 1 branch LE B7 branch AL B6 B6: move R42 R43 sub R43 1 R43 move R43 ecx B7: static call [static jint Fact.factIf(jint)] result eax bci:9 move 1 R46 move eax R44 branch AL B8 move R44 R45 mul R45 R42 R45 move R45 R46 branch AL B8 B8: B2: move R46 R47 move 1 B48 mul R47 R41 branch AL B3 move R47 R48 branch AL B3 B3: move R48 eax return eax LinearScanレジスタ割り付け 27
  • 32. sample code factFor LIRでも色々冗長な命令を削る Before Code Generation # # # # # label B9 std_entry // deleted move ecx R41 // deleted branch AL B0 label B0 cmp ecx 1 // replaced cmp R41 1 branch LE B2 // deleted branch AL B1 label B1 move ecx esi // replaced move R41 R42 sub esi 1 esi // replaced sub R42 1 R42 cmp esi 1 // replaced cmp R42 1 move ecx stack:2 // add branch LE B7 // deleted branch AL B6 label B6 move esi edi // replaced move R42 R43 sub edi 1 edi // replaced sub R43 1 R43 move edi ecx // replaced move R43 ecx move esi stack:1 // add static call [static jint Fact.factIf(jint)] result eax bci:9 move stack:1 esi // add // deleted move eax R44 // deleted move R44 R45 mul eax esi eax // replaced mul R45 R42 R45 // deleted move R45 R46 branch AL B8 label B7 move 1 eax // replaced move 1 R46 // deleted branch AL B8 label B8 move stack:2 ecx // add // deleted move R46 R47 mul eax ecx eax // replaced mul R47 R41 // deleted move R47 R48 // deleted branch AL B3 return eax // add label B2 move 1 eax // replaced move 1 B48 // deleted branch AL B3 label B3 // deleted move R48 eax return eax sample code factFor 入力ソースコードfactFor public static int factFor(int n) { int p = 1; for (int i = 1; i <= n; i++) { 28
  • 33. sample code factFor p = p * i; } return p; } factFor Bytecode public static int factFor(int); Code: 0: iconst_1 1: istore_1 2: iconst_1 3: istore_2 4: iload_2 5: iload_0 6: if_icmpgt 19 9: iload_1 10: iload_2 11: imul 12: istore_1 13: iinc 2, 1 16: goto 4 19: iload_1 20: ireturn factFor HIR static jint Fact.factFor(jint) B4: i4 = method parameter v17 = std entry B0 B0: i5 = 1 v7 = goto B1 B1: i8 = [i5, i11] i9 = [i5, i13] v10 = if i9 > i4 then B3 else B2 B2: i11 = i8 * i9 i12 = 1 i13 = i9 + i12 v14 = goto B1 B3: i15 = ireturn i8 factFor HIR CFG factFor HIR DFG factFor Optimized HIR 29
  • 34. sample code factFor static jint Fact.factFor(jint) B4: i4 = method parameter v17 = std entry B0 B0: i5 = 1 v7 = goto B1 B1: i8 = [i5, i11] i9 = [i5, i13] v10 = if i9 > i4 then B3 else B2 B2: i11 = i8 * i9 // deleted i12 = 1 i13 = i9 + i5 // replaced i13 = i9 + i12 v14 = goto B1 B3: i15 = ireturn i8 factFor translate HIR to LIR # # # # label B4 std_entry move ecx R41 branch AL B0 label B0 move 1 R43 move 1 R42 branch AL B1 label B1 cmp R43 R41 branch GT B3 branch AL B2 label B2 move R42 R44 mul R44 R43 R44 move R43 R45 add R45 1 R45 safepoint bci:16 move R45 R43 move R44 R42 branch AL B1 label B3 move R42 eax return eax 30
  • 35. sample code factFor B4 std_entry move ecx R41 branch AL B0 B0 move 1 R43 move 1 R42 branch AL B1 B1 cmp R43 R41 branch GT B3 branch AL B2 B2 move R42 R44 mul R44 R43 R44 B3 move R43 R45 move R42 eax add R45 1 R45 return eax safepoint bci:16 move R45 R43 move R44 R42 branch AL B1 LenearScanレジスタ割り付け Before Code Generation # # # # label B4 std_entry // deleted move ecx R41 // deleted branch AL B0 label B0 move 1 eax // replaced move 1 R43 move 1 esi // replaced move 1 R42 branch AL B1 31
  • 36. 参考文献 label B2 // deleted move R42 R44 mul esi eax esi // replaced mul R44 R43 R44 // deleted move R43 R45 add eax 1 eax // replaced add R45 1 R45 safepoint bci:16 // deleted move R45 R43 // deleted move R44 R42 // deleted branch AL B1 label B1 cmp eax ecx // replaced cmp R43 R41 // deleted branch GT B3 branch LE B2 // replaced branch AL B2 label B3 move esi eax // replaced move R42 eax return eax 参考文献 SSA Form for the Java HotSpot™ Client Compiler Christian Wimmer April 2009 Sun Microsystems, Inc. Institute for System Software Johannes Kepler University Linz, Austria Department of Computer Science University of California, Irvine Linear Scan Register Allocation Christian Wimmer Linear Scan Register Allocation for the Java HotSpot™ Client Compiler A thesis submitted in partial satisfaction of the requirements for the degree of Master of Science (Diplom-Ingenieur) Design of the Java HotSpotTM Client Compiler for Java 6 Design of the Java HotSpotTM Client Compiler for Java 6 THOMAS KOTZMANN, CHRISTIAN WIMMER and HANSPETER MO¨ SSENBO¨ CK Johannes Kepler University Linz and THOMAS RODRIGUEZ, KENNETH RUSSELL, and DAVID COX Sun Microsystems, Inc. Escape Analysis in the Context of Dynamic Compilation and Deoptimization Thomas Kotzmann Escape Analysis in the Context of Dynamic Compilation and Deoptimization A PhD thesis submitted in partial satisfaction of the requirements for the degree of Doctor of Technical Sciences Institute for System Software Johannes Kepler University Linz 32
  • 37. Indices and tables Indices and tables • genindex • modindex • search 33