仮想マシンのバイトコードインタプリタとドッキング

私の心はどのようにJVM仮想バットクラスのバイトコードで、疑問になっていますか?または入力されていない
時にJIT最適化の段階を、インタプリタはどのようにお尻がありますか?

おそらく説明

新たに生成されたコードを呼び出すために、関数ポインタを介して関数として命令のセットは、この空間に充填されているヒープのアプリケーション空間によってC ++コードのホットスポット。666それは、すごい超クールされていないではありません。

キーコード

generate_call_stub

 address generate_call_stub(address& return_address) { // TODO: 需要一路仔细调试  c++方法  返回无符号char
    assert((int)frame::entry_frame_after_call_words == -(int)rsp_after_call_off + 1 &&
           (int)frame::entry_frame_call_wrapper_offset == (int)call_wrapper_off,
           "adjust this code");
    StubCodeMark mark(this, "StubRoutines", "call_stub");
//    address start = __ pc(); // SimonNote: 这个方法最终返回的就是这个start  宏展开 : _masm->pc()
    address start = _masm-> pc(); // SimonNote: _code_section 的end 是pc() 也是此处的start

    // same as in generate_catch_exception()!
    const Address rsp_after_call(rbp, rsp_after_call_off * wordSize); // 这些adress都是准备工作  真正在内存区域生成汇编指令的事情是在下面的做的

    const Address call_wrapper  (rbp, call_wrapper_off   * wordSize);
    const Address result        (rbp, result_off         * wordSize);
    const Address result_type   (rbp, result_type_off    * wordSize);
    const Address method        (rbp, method_off         * wordSize);
    const Address entry_point   (rbp, entry_point_off    * wordSize);
    const Address parameters    (rbp, parameters_off     * wordSize);
    const Address parameter_size(rbp, parameter_size_off * wordSize);

    // same as in generate_catch_exception()!
    const Address thread        (rbp, thread_off         * wordSize);

    const Address r15_save(rbp, r15_off * wordSize);
    const Address r14_save(rbp, r14_off * wordSize);
    const Address r13_save(rbp, r13_off * wordSize);
    const Address r12_save(rbp, r12_off * wordSize);
    const Address rbx_save(rbp, rbx_off * wordSize);

    // stub code
    __ enter();  //SimonNote: macroAssembler_x86.cpp MacroAssembler::enter()   push(rbp); mov(rbp, rsp); 真正在内存区域生成汇编指令!其实就是把指令等opcode写入内存区域
    __ subptr(rsp, -rsp_after_call_off * wordSize);

    // save register parameters
#ifndef _WIN64
    __ movptr(parameters,   c_rarg5); // parameters
    __ movptr(entry_point,  c_rarg4); // entry_point
#endif

    __ movptr(method,       c_rarg3); // method
    __ movl(result_type,  c_rarg2);   // result type
    __ movptr(result,       c_rarg1); // result
    __ movptr(call_wrapper, c_rarg0); // call wrapper

    // save regs belonging to calling function
    __ movptr(rbx_save, rbx);
    __ movptr(r12_save, r12);
    __ movptr(r13_save, r13);
    __ movptr(r14_save, r14);
    __ movptr(r15_save, r15);
#ifdef _WIN64
    for (int i = 6; i <= 15; i++) {
      __ movdqu(xmm_save(i), as_XMMRegister(i));
    }

    const Address rdi_save(rbp, rdi_off * wordSize);
    const Address rsi_save(rbp, rsi_off * wordSize);

    __ movptr(rsi_save, rsi);
    __ movptr(rdi_save, rdi);
#else
    const Address mxcsr_save(rbp, mxcsr_off * wordSize);
    {
      Label skip_ldmx;
      __ stmxcsr(mxcsr_save);
      __ movl(rax, mxcsr_save);
      __ andl(rax, MXCSR_MASK);    // Only check control and mask bits
      ExternalAddress mxcsr_std(StubRoutines::addr_mxcsr_std());
      __ cmp32(rax, mxcsr_std);
      __ jcc(Assembler::equal, skip_ldmx);
      __ ldmxcsr(mxcsr_std);
      __ bind(skip_ldmx);
    }
#endif

    // Load up thread register
    __ movptr(r15_thread, thread);
    __ reinit_heapbase();

#ifdef ASSERT
    // make sure we have no pending exceptions
    {
      Label L;
      __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD);
      __ jcc(Assembler::equal, L);
      __ stop("StubRoutines::call_stub: entered with pending exception");
      __ bind(L);
    }
#endif

    // pass parameters if any
    BLOCK_COMMENT("pass parameters if any");
    Label parameters_done;
    __ movl(c_rarg3, parameter_size);
    __ testl(c_rarg3, c_rarg3);
    __ jcc(Assembler::zero, parameters_done);

    Label loop;
    __ movptr(c_rarg2, parameters);       // parameter pointer
    __ movl(c_rarg1, c_rarg3);            // parameter counter is in c_rarg1
    __ BIND(loop);
    __ movptr(rax, Address(c_rarg2, 0));// get parameter
    __ addptr(c_rarg2, wordSize);       // advance to next parameter
    __ decrementl(c_rarg1);             // decrement counter
    __ push(rax);                       // pass parameter
    __ jcc(Assembler::notZero, loop);

    // call Java function
    __ BIND(parameters_done);
    __ movptr(rbx, method);             // get Method*
    __ movptr(c_rarg1, entry_point);    // get entry_point
    __ mov(r13, rsp);                   // set sender sp
    BLOCK_COMMENT("call Java function");
    __ call(c_rarg1);

    BLOCK_COMMENT("call_stub_return_address:");
    return_address = __ pc();

    // store result depending on type (everything that is not
    // T_OBJECT, T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT)
    __ movptr(c_rarg0, result);
    Label is_long, is_float, is_double, exit;
    __ movl(c_rarg1, result_type);
    __ cmpl(c_rarg1, T_OBJECT);
    __ jcc(Assembler::equal, is_long);
    __ cmpl(c_rarg1, T_LONG);
    __ jcc(Assembler::equal, is_long);
    __ cmpl(c_rarg1, T_FLOAT);
    __ jcc(Assembler::equal, is_float);
    __ cmpl(c_rarg1, T_DOUBLE);
    __ jcc(Assembler::equal, is_double);

    // handle T_INT case
    __ movl(Address(c_rarg0, 0), rax);

    __ BIND(exit);

    // pop parameters
    __ lea(rsp, rsp_after_call);

#ifdef ASSERT
    // verify that threads correspond
    {
      Label L, S;
      __ cmpptr(r15_thread, thread);
      __ jcc(Assembler::notEqual, S);
      __ get_thread(rbx);
      __ cmpptr(r15_thread, rbx);
      __ jcc(Assembler::equal, L);
      __ bind(S);
      __ jcc(Assembler::equal, L);
      __ stop("StubRoutines::call_stub: threads must correspond");
      __ bind(L);
    }
#endif

    // restore regs belonging to calling function
#ifdef _WIN64
    for (int i = 15; i >= 6; i--) {
      __ movdqu(as_XMMRegister(i), xmm_save(i));
    }
#endif
    __ movptr(r15, r15_save);
    __ movptr(r14, r14_save);
    __ movptr(r13, r13_save);
    __ movptr(r12, r12_save);
    __ movptr(rbx, rbx_save);

#ifdef _WIN64
    __ movptr(rdi, rdi_save);
    __ movptr(rsi, rsi_save);
#else
    __ ldmxcsr(mxcsr_save);
#endif

    // restore rsp
    __ addptr(rsp, -rsp_after_call_off * wordSize);

    // return
    __ pop(rbp);
    __ ret(0);

    // handle return types different from T_INT
    __ BIND(is_long);
    __ movq(Address(c_rarg0, 0), rax);
    __ jmp(exit);

    __ BIND(is_float);
    __ movflt(Address(c_rarg0, 0), xmm0);
    __ jmp(exit);

    __ BIND(is_double);
    __ movdbl(Address(c_rarg0, 0), xmm0);
    __ jmp(exit);

    return start;
  }

初期化関数を開始する上でJVMはこれを呼び出します。この関数は次のようにその型が定義され、アドレスを返します。

typedef unsigned char u_char;
typedef u_char*       address;

住所について

C ++は、これはunsigned char型のポインタに変換することができるオブジェクトです。値のアドレスは、このアドレスの目的です。「C ++オブジェクトが、このunsigned char型のポインタに変換されます」サンプルプログラムを参照してください。

アドレス)(= _masm-> PCを起動し ; // SimonNote:_code_section エンドPC(である)ここもスタートです
_masm

_masmについて

__マクロで、展開が_masm->である
にして:: StubCodeGenerator機能stubCodeGenerator.cppで_masm変数の初期化StubCodeGenerator

StubCodeGenerator::StubCodeGenerator(CodeBuffer* code, bool print_code) {
  _masm = new MacroAssembler(code);
  _first_stub = _last_stub = NULL;
  _print_code = print_code;
}

初期化_masmのコールスタックについての投稿

StubCodeGenerator::StubCodeGenerator() at stubCodeGenerator.cpp:72 0x7ffff69d60d8   
ICacheStubGenerator::ICacheStubGenerator() at icache.hpp:91 0x7ffff65da534  
AbstractICache::initialize() at icache.cpp:39 0x7ffff65da324    
icache_init() at icache.cpp:105 0x7ffff65da4f0  
CodeCache::initialize() at codeCache.cpp:572 0x7ffff63d09f8 
codeCache_init() at codeCache.cpp:582 0x7ffff63d0a34    
init_globals() at init.cpp:98 0x7ffff65e93c5    
Threads::create_vm() at thread.cpp:3,424 0x7ffff6a471c8 
JNI_CreateJavaVM() at jni.cpp:5,166 0x7ffff66a156d  
InitializeJVM() at java.c:1,145 0x7ffff7bc1b1f  
JavaMain() at java.c:371 0x7ffff7bbf9e8 
start_thread() at pthread_create.c:463 0x7ffff73ab6db   
clone() at clone.S:95 0x7ffff78e888f    

これは、見やすいですいくつかのスタックを上げ:
_masm(MacroAssembler必要なコードがCodeBuffer、である
彼らはBufferBlob必要CodeBuffer
ボイドAbstractICacheのicache.cppでこのロジックを::初期化()で

void AbstractICache::initialize() {
  // Making this stub must be FIRST use of assembler
  ResourceMark rm;

  BufferBlob* b = BufferBlob::create("flush_icache_stub", ICache::stub_size);
  CodeBuffer c(b);

  ICacheStubGenerator g(&c);
  g.generate_icache_flush(&_flush_icache_stub);

  // The first use of flush_icache_stub must apply it to itself.
  // The StubCodeMark destructor in generate_icache_flush will
  // call Assembler::flush, which in turn will call invalidate_range,
  // which will in turn call the flush stub.  Thus we don't need an
  // explicit call to invalidate_range here.  This assumption is
  // checked in invalidate_range.
}

BufferBlob * B = BufferBlob ::( "flush_icache_stub"、命令キャッシュ:: stub_size)を作成し、作られたスペースの割り当てを、次言います。

スペースの割り当て

スタック割り当て

HeapBlock::allocated_space() at heap.hpp:54 0x7ffff65c26e4  
CodeHeap::allocate() at heap.cpp:219 0x7ffff65c1a25 
CodeCache::allocate() at codeCache.cpp:186 0x7ffff63cf5d8   
BufferBlob::operator new() at codeBlob.cpp:249 0x7ffff63c8a0b   
BufferBlob::create() at codeBlob.cpp:218 0x7ffff63c884e 
AbstractICache::initialize() at icache.cpp:36 0x7ffff65da2eb    
icache_init() at icache.cpp:105 0x7ffff65da4f0  
CodeCache::initialize() at codeCache.cpp:572 0x7ffff63d09f8 
codeCache_init() at codeCache.cpp:582 0x7ffff63d0a34    
init_globals() at init.cpp:98 0x7ffff65e93c5    
Threads::create_vm() at thread.cpp:3,424 0x7ffff6a471c8 
JNI_CreateJavaVM() at jni.cpp:5,166 0x7ffff66a156d  
InitializeJVM() at java.c:1,145 0x7ffff7bc1b1f  
JavaMain() at java.c:371 0x7ffff7bbf9e8 
start_thread() at pthread_create.c:463 0x7ffff73ab6db   
clone() at clone.S:95 0x7ffff78e888f    

彼女は理解していないコードを理解するのに役立つだけで私の同僚を見て、ありました:

BufferBlob* BufferBlob::create(const char* name, int buffer_size) {
  ThreadInVMfromUnknown __tiv;  // get to VM state in case we block on CodeCache_lock

  BufferBlob* blob = NULL;
  unsigned int size = sizeof(BufferBlob);
  // align the size to CodeEntryAlignment
  size = align_code_offset(size);
  size += round_to(buffer_size, oopSize);
  assert(name != NULL, "must provide a name");
  {
    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
    blob = new (size) BufferBlob(name, size); // 这行是什么意思?怎么有这种写法?
  }
  // Track memory usage statistic after releasing CodeCache_lock
  MemoryService::track_code_cache_memory_usage();

  return blob;
}

BufferBlobの*ブロブ=新しい(サイズ) BufferBlob(名前、サイズ); このようなアプローチは、「C ++プログラミング言語、第四に、配置新しい文言である版」 説明するのが新しいオーバーロード11.2.4に。:緩やかな言葉遣いの私の浅い理解に記載
する場合は、オブジェクト、メモリが指定されたアドレスに、pのサイズSZの場所のオブジェクトに割り当てられているオブジェクトを作成します 。
しかし、最も簡単な配置、新たな文言で、ここの文言は、それがリロードをしたとして、最も独創的文言があり、ほとんど差はまだあります。

void∗ buf = reinterpret_cast<void∗>(0xF00F); // significant address 
X∗ p2 = new(buf) X; // construct an X at buf;
                    // invokes: operator new(sizeof(X),buf)

// The ‘‘placement’’ operator new() is the simplest such allocator. It is defined in the standard header <new>:
void∗ operator new (size_t sz, void∗ p) noexcept;   // place object of size sz at p

オペレータ新しいsize_tの最初の引数が呼ばれたとき、転送コンパイル時にコンパイラによって決定し、それらを送信しないSZについて、ユーザーは単に上のvoid * pを送る
オペレータ新しいコードのBufferBlobの上にも大きな負荷を作りました、 (それはまた、一般的な方法、カスタムロジックメモリの割り当てであり、ポインタ割り当てを返します)。

void* BufferBlob::operator new(size_t s, unsigned size, bool is_critical) throw() {
  void* p = CodeCache::allocate(size, is_critical);
  return p;
}

アセンブリに翻訳バイトコード命令

コールスタックアセンブリ命令にバイトコードを翻訳:
新しい例に:

TemplateTable::_new() at templateTable_x86_64.cpp:3,250 0x7ffff6a39ed6  
Template::generate() at templateTable.cpp:63 0x7ffff6a267c7 
TemplateInterpreterGenerator::generate_and_dispatch() at templateInterpreter.cpp:530 0x7ffff6a1c392 
TemplateInterpreterGenerator::set_vtos_entry_points() at templateInterpreter_x86_64.cpp:2,039 0x7ffff6a25dfc    
TemplateInterpreterGenerator::set_short_entry_points() at templateInterpreter.cpp:498 0x7ffff6a1c179    
TemplateInterpreterGenerator::set_entry_points() at templateInterpreter.cpp:464 0x7ffff6a1bcb3  
TemplateInterpreterGenerator::set_entry_points_for_all_bytes() at templateInterpreter.cpp:421 0x7ffff6a1b974    
TemplateInterpreterGenerator::generate_all() at templateInterpreter.cpp:402 0x7ffff6a1b8d6  
InterpreterGenerator::InterpreterGenerator() at templateInterpreter_x86_64.cpp:2,051 0x7ffff6a25e3b 
TemplateInterpreter::initialize() at templateInterpreter.cpp:52 0x7ffff6a19aab  
interpreter_init() at interpreter.cpp:118 0x7ffff664c2fe    
init_globals() at init.cpp:107 0x7ffff65e93ef   
Threads::create_vm() at thread.cpp:3,424 0x7ffff6a471c8 
JNI_CreateJavaVM() at jni.cpp:5,166 0x7ffff66a156d  
InitializeJVM() at java.c:1,145 0x7ffff7bc1b1f  
JavaMain() at java.c:371 0x7ffff7bbf9e8 
start_thread() at pthread_create.c:463 0x7ffff73ab6db   
clone() at clone.S:95 0x7ffff78e888f    

インタプリタのコンパイルテンプレート(テンプレート通訳)とバイトコード実行を[ホットスポット内側]

参照

HotSpotのバイトコードインタプリタを実装する方法である[議論]
[議論]頼む:どのようにJavaバイトコードの実行
[議論] java_mainコンパイル入り口どこ
小さなデモの実行時のコードの操作
方法テンプレートJVMインタプリタ基づきバイトをコードジェネレータアセンブリコード?

おすすめ

転載: www.cnblogs.com/simoncook/p/11141256.html