hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp
void TemplateTable::_new() {
{- -------------------------------------------
(1) (assert) (See: TemplateTable::transition())
---------------------------------------- -}
transition(vtos, atos);
{- -------------------------------------------
(1) コード生成:
「constant pool の index を rdx に取得しておく」
---------------------------------------- -}
__ get_unsigned_2_byte_index_at_bcp(rdx, 1);
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
Label slow_case;
Label done;
Label initialize_header;
Label initialize_object; // including clearing the fields
Label allocate_shared;
{- -------------------------------------------
(1) コード生成:
「現在実行中のメソッドに対応する constant pool を取得し,
あわせて new 対象のクラスオブジェクトに対応する tag を取得する.」
---------------------------------------- -}
__ get_cpool_and_tags(rsi, rax);
{- -------------------------------------------
(1) コード生成:
「new 対象のクラスが resolve 済みかどうかを確認する.
もし, resolve 済みでなければ (= constant pool の該当エントリが JVM_CONSTANT_Class でなければ (See: [here](no2935KOa.html) for details)),
fast-path での処理はできないので, slow_case ラベルにジャンプする.」
---------------------------------------- -}
// Make sure the class we're about to instantiate has been resolved.
// This is done before loading instanceKlass to be consistent with the order
// how Constant Pool is updated (see constantPoolOopDesc::klass_at_put)
const int tags_offset = typeArrayOopDesc::header_size(T_BYTE) * wordSize;
__ cmpb(Address(rax, rdx, Address::times_1, tags_offset),
JVM_CONSTANT_Class);
__ jcc(Assembler::notEqual, slow_case);
{- -------------------------------------------
(1) コード生成:
「new 対象のクラスオブジェクトを取得する (= constant pool から対応するエントリを取得する).」
---------------------------------------- -}
// get instanceKlass
__ movptr(rsi, Address(rsi, rdx,
Address::times_8, sizeof(constantPoolOopDesc)));
{- -------------------------------------------
(1) コード生成:
「もし, クラスの初期化が完全に終わっていない場合には
(= ...(#TODO) が instanceKlass::fully_initialized ではない場合には),
fast-path での処理はできないので, slow_case ラベルにジャンプする.」
---------------------------------------- -}
// make sure klass is initialized & doesn't have finalizer
// make sure klass is fully initialized
__ cmpl(Address(rsi,
instanceKlass::init_state_offset_in_bytes() +
sizeof(oopDesc)),
instanceKlass::fully_initialized);
__ jcc(Assembler::notEqual, slow_case);
{- -------------------------------------------
(1)
---------------------------------------- -}
// get instance_size in instanceKlass (scaled to a count of bytes)
__ movl(rdx,
Address(rsi,
Klass::layout_helper_offset_in_bytes() + sizeof(oopDesc)));
{- -------------------------------------------
(1) コード生成:
「もし, 対象のクラスが (abstract や interface 等) new できないものである場合には
(= Klass::_lh_instance_slow_path_bit が立っている場合には),
fast-path での処理はできないので, slow_case ラベルにジャンプする.」
---------------------------------------- -}
// test to see if it has a finalizer or is malformed in some way
__ testl(rdx, Klass::_lh_instance_slow_path_bit);
__ jcc(Assembler::notZero, slow_case);
{- -------------------------------------------
(1) (これ以降が fast-path での確保処理.
fast-path では以下のようにして確保を試みることになる.
これらが失敗した場合は, slow-path での確保処理にフォールスルーする.
(1) まず TLAB 内に確保を試みる.
(2) TLAB での確保が失敗したが, TLAB にまだ充分空きがある場合には,
現在の TLAB を捨てるのはもったいないので shared Eden 内に直接確保を試みる.)
---------------------------------------- -}
// Allocate the instance
// 1) Try to allocate in the TLAB
// 2) if fail and the object is large allocate in the shared Eden
// 3) if the above fails (or is not applicable), go to a slow case
// (creates a new TLAB, etc.)
{- -------------------------------------------
(1) (変数宣言など)
(allow_shared_alloc は, shared eden からの確保を試みるかどうかを示す.
基本的には Universe::heap()->supports_inline_contig_alloc() が true であれば試みるが,
CMSIncrementalMode の場合にだけは試みない)
---------------------------------------- -}
const bool allow_shared_alloc =
Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode;
{- -------------------------------------------
(1) コード生成: (ただし, UseTLAB オプションが指定されている場合にしか行わない)
「まず以下の if ブロックが生成するコード内で TLAB からの確保を試みる.
確保が成功すれば, initialize_header ラベルまたは initialize_object ラベルに分岐する.
(なお, initialize_header ラベルと initialize_object ラベルの違いは,
確保時にオブジェクトのフィールド部分をゼロクリアするか否か)
確保が失敗した場合は, shared eden からの確保処理にフォールスルーするか,
もしくは snow_case での確保処理を行う.」
---------------------------------------- -}
if (UseTLAB) {
{- -------------------------------------------
(1.1) コード生成:
「カレントスレッドの TLAB について, 現在使用量 (top 値) と TLAB の終端値 (end 値) を取得し,
「現在使用量+確保サイズ」を計算する.」
---------------------------------------- -}
__ movptr(rax, Address(r15_thread, in_bytes(JavaThread::tlab_top_offset())));
__ lea(rbx, Address(rax, rdx, Address::times_1));
__ cmpptr(rbx, Address(r15_thread, in_bytes(JavaThread::tlab_end_offset())));
{- -------------------------------------------
(1.1) コード生成:
「TLAB サイズより「現在使用量+確保サイズ」が大きい場合には
allocate_shared ラベルもしくは slow_case ラベルに分岐する」
---------------------------------------- -}
__ jcc(Assembler::above, allow_shared_alloc ? allocate_shared : slow_case);
{- -------------------------------------------
(1.1) コード生成:
「(TLAB サイズが「現在使用量+確保サイズ」より小さい場合には)
TLAB の現在使用量 (top 値) を新しい値に更新した後,
ZeroTLAB オプションの価に応じて initialize_header または initialize_object ラベルにジャンプする.」
---------------------------------------- -}
__ movptr(Address(r15_thread, in_bytes(JavaThread::tlab_top_offset())), rbx);
if (ZeroTLAB) {
// the fields have been already cleared
__ jmp(initialize_header);
} else {
// initialize both the header and fields
__ jmp(initialize_object);
}
}
{- -------------------------------------------
(1) (以下は, shared eden からの確保を試みるパス.
当然だが, このコードは shared eden が利用可能な場合にしか生成されない.
なお, このパスが実行されるのは,
UseTLAB オプションが指定されていない場合, もしくは 上記の TLAB からの確保処理が失敗した場合のみ)
---------------------------------------- -}
// Allocation in the shared Eden, if allowed.
//
// rdx: instance size in bytes
{- -------------------------------------------
(1.1) コード生成: (allow_shared_alloc が true の場合にのみ生成)
「shared eden からの確保処理を行う.
* 確保が成功すれば, initialize_object ラベルにフォールスルー
(<= なお, TLAB からの確保時と異なり ZeroTLAB オプションの値によって飛び先が変わることはない. まぁ TLAB ではないので当たり前か)
* 確保が失敗すれば, slow_case での処理に分岐する.」
---------------------------------------- -}
if (allow_shared_alloc) {
__ bind(allocate_shared);
ExternalAddress top((address)Universe::heap()->top_addr());
ExternalAddress end((address)Universe::heap()->end_addr());
const Register RtopAddr = rscratch1;
const Register RendAddr = rscratch2;
{- -------------------------------------------
(1.1.1) コード生成:
「ヒープの eden 領域について, 現在使用量 (top 値) を取得.」
---------------------------------------- -}
__ lea(RtopAddr, top);
__ lea(RendAddr, end);
__ movptr(rax, Address(RtopAddr, 0));
{- -------------------------------------------
(1.1.1) コード生成:
「cas で Universe::heap()->top を書き換えることでメモリを確保する. cas が失敗した場合は処理を繰り返す.
なお, 空き容量が確保量よりも小さい場合は, 諦めて slow_case にジャンプする.」
---------------------------------------- -}
// For retries rax gets set by cmpxchgq
Label retry;
__ bind(retry);
__ lea(rbx, Address(rax, rdx, Address::times_1));
__ cmpptr(rbx, Address(RendAddr, 0));
__ jcc(Assembler::above, slow_case);
// Compare rax with the top addr, and if still equal, store the new
// top addr in rbx at the address of the top addr pointer. Sets ZF if was
// equal, and clears it otherwise. Use lock prefix for atomicity on MPs.
//
// rax: object begin
// rbx: object end
// rdx: instance size in bytes
if (os::is_MP()) {
__ lock();
}
__ cmpxchgptr(rbx, Address(RtopAddr, 0));
// if someone beat us on the allocation, try again, otherwise continue
__ jcc(Assembler::notEqual, retry);
{- -------------------------------------------
(1.1.1) コード生成:
「cas が成功していれば, MacroAssembler::incr_allocated_bytes() で統計情報を更新しておく.
(See: [here](no2114Q4Z.html) for details)」
---------------------------------------- -}
__ incr_allocated_bytes(r15_thread, rdx, 0);
}
{- -------------------------------------------
(1) (以下は fast-path が成功し, かつ...#TODO 場合の処理パス.
より具体的には, initialize_object ラベルの bind 箇所)
(なお, allow_shared_alloc 変数の定義より,
allow_shared_alloc が true の場合には Universe::heap()->supports_inline_contig_alloc() も true である.
このため, 上の shared eden の確保処理パスが作られる場合には, この initialize_object ラベルの処理パスも作られる.
<= というか, 作られない場合には shared eden の処理成功時のフォールスルー先が snow_case になってしまうので,
fast_path の意味が無い)
---------------------------------------- -}
{- -------------------------------------------
(1.1) コード生成: (ただし, UseTLAB オプションが指定されている場合, または)
「確保したオブジェクトにフィールドがなければ, 単に initialize_header ラベルにフォールスルーするだけ.
フィールドがあれば, フィールドを全て 0 クリアした後, initialize_header ラベルにフォールスルーする」
---------------------------------------- -}
if (UseTLAB || Universe::heap()->supports_inline_contig_alloc()) {
// The object is initialized before the header. If the object size is
// zero, go directly to the header initialization.
__ bind(initialize_object);
__ decrementl(rdx, sizeof(oopDesc));
__ jcc(Assembler::zero, initialize_header);
// Initialize object fields
__ xorl(rcx, rcx); // use zero reg to clear memory (shorter code)
__ shrl(rdx, LogBytesPerLong); // divide by oopSize to simplify the loop
{
Label loop;
__ bind(loop);
__ movq(Address(rax, rdx, Address::times_8,
sizeof(oopDesc) - oopSize),
rcx);
__ decrementl(rdx);
__ jcc(Assembler::notZero, loop);
}
{- -------------------------------------------
(1) (以下は fast-path が成功した場合の処理パス.
より具体的には, initialize_header ラベルの bind 箇所)
---------------------------------------- -}
// initialize object header only.
{- -------------------------------------------
(1.1) コード生成:
「確保したオブジェクトの mark フィールド, 及び klass フィールドを初期化する.
(なお, (DTrace のフック点) でもある).
その後 done ラベルへとフォールスルーする.」
---------------------------------------- -}
__ bind(initialize_header);
if (UseBiasedLocking) {
__ movptr(rscratch1, Address(rsi, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()));
__ movptr(Address(rax, oopDesc::mark_offset_in_bytes()), rscratch1);
} else {
__ movptr(Address(rax, oopDesc::mark_offset_in_bytes()),
(intptr_t) markOopDesc::prototype()); // header (address 0x1)
}
__ xorl(rcx, rcx); // use zero reg to clear memory (shorter code)
__ store_klass_gap(rax, rcx); // zero klass gap for compressed oops
__ store_klass(rax, rsi); // store klass last
{
SkipIfEqual skip(_masm, &DTraceAllocProbes, false);
// Trigger dtrace event for fastpath
__ push(atos); // save the return value
__ call_VM_leaf(
CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), rax);
__ pop(atos); // restore the return value
}
__ jmp(done);
}
{- -------------------------------------------
(1) (以下は fast-path が失敗した場合の処理パス.
つまりは, slow-path の処理パス. より具体的には, slow_case ラベルの bind 箇所)
---------------------------------------- -}
// slow case
{- -------------------------------------------
(1.1) コード生成:
「InterpreterRuntime::_new() を呼び出すことで確保処理を行う. その後 done ラベルまでジャンプする.」
---------------------------------------- -}
__ bind(slow_case);
__ get_constant_pool(c_rarg1);
__ get_unsigned_2_byte_index_at_bcp(c_rarg2, 1);
call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), c_rarg1, c_rarg2);
__ verify_oop(rax);
{- -------------------------------------------
(1) (以下が, 確保処理が終わった後のジャンプ先.
より具体的には, done ラベルの bind 箇所)
---------------------------------------- -}
// continue
__ bind(done);
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.