hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp
void TemplateTable::_new() {
{- -------------------------------------------
(1) (assert) (See: TemplateTable::transition())
---------------------------------------- -}
transition(vtos, atos);
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
Label slow_case;
Label done;
Label initialize_header;
Label initialize_object; // including clearing the fields
Register RallocatedObject = Otos_i;
Register RinstanceKlass = O1;
Register Roffset = O3;
Register Rscratch = O4;
{- -------------------------------------------
(1) コード生成:
「現在実行中のメソッドに対応する constant pool を取得し,
あわせて new 対象のクラスオブジェクトに対応する tag を取得する.」
---------------------------------------- -}
__ get_2_byte_integer_at_bcp(1, Rscratch, Roffset, InterpreterMacroAssembler::Unsigned);
__ get_cpool_and_tags(Rscratch, G3_scratch);
{- -------------------------------------------
(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)
__ add(G3_scratch, typeArrayOopDesc::header_size(T_BYTE) * wordSize, G3_scratch);
__ ldub(G3_scratch, Roffset, G3_scratch);
__ cmp(G3_scratch, JVM_CONSTANT_Class);
__ br(Assembler::notEqual, false, Assembler::pn, slow_case);
__ delayed()->sll(Roffset, LogBytesPerWord, Roffset);
{- -------------------------------------------
(1) コード生成:
「new 対象のクラスオブジェクトを取得する (= constant pool から対応するエントリを取得する).」
---------------------------------------- -}
// get instanceKlass
//__ sll(Roffset, LogBytesPerWord, Roffset); // executed in delay slot
__ add(Roffset, sizeof(constantPoolOopDesc), Roffset);
__ ld_ptr(Rscratch, Roffset, RinstanceKlass);
{- -------------------------------------------
(1) コード生成:
「もし, クラスの初期化が完全に終わっていない場合には
(= ...(#TODO) が instanceKlass::fully_initialized ではない場合には),
fast-path での処理はできないので, slow_case ラベルにジャンプする.」
---------------------------------------- -}
// make sure klass is fully initialized:
__ ld(RinstanceKlass, instanceKlass::init_state_offset_in_bytes() + sizeof(oopDesc), G3_scratch);
__ cmp(G3_scratch, instanceKlass::fully_initialized);
__ br(Assembler::notEqual, false, Assembler::pn, slow_case);
__ delayed()->ld(RinstanceKlass, Klass::layout_helper_offset_in_bytes() + sizeof(oopDesc), Roffset);
{- -------------------------------------------
(1) ?? (何かコメントアウトされているが...)
---------------------------------------- -}
// get instance_size in instanceKlass (already aligned)
//__ ld(RinstanceKlass, Klass::layout_helper_offset_in_bytes() + sizeof(oopDesc), Roffset);
{- -------------------------------------------
(1) コード生成:
「もし, 対象のクラスが (abstract や interface 等) new できないものである場合には
(= Klass::_lh_instance_slow_path_bit が立っている場合には),
fast-path での処理はできないので, slow_case ラベルにジャンプする.」
---------------------------------------- -}
// make sure klass does not have has_finalizer, or is abstract, or interface or java/lang/Class
__ btst(Klass::_lh_instance_slow_path_bit, Roffset);
__ br(Assembler::notZero, false, Assembler::pn, slow_case);
__ delayed()->nop();
{- -------------------------------------------
(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 TLAB is not full enough to discard, 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) (変数宣言など)
---------------------------------------- -}
Register RoldTopValue = RallocatedObject;
Register RtopAddr = G3_scratch, RtlabWasteLimitValue = G3_scratch;
Register RnewTopValue = G1_scratch;
Register RendValue = Rscratch;
Register RfreeValue = RnewTopValue;
{- -------------------------------------------
(1.1) コード生成:
「カレントスレッドの TLAB について, 現在使用量 (top 値) と TLAB の終端値 (end 値) を取得し,
「現在使用量+確保サイズ」を計算する.」
---------------------------------------- -}
// check if we can allocate in the TLAB
__ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), RoldTopValue); // sets up RalocatedObject
__ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), RendValue);
__ add(RoldTopValue, Roffset, RnewTopValue);
{- -------------------------------------------
(1.1) コード生成:
「TLAB からの確保が可能かどうか確認し, 結果に応じて分岐する.
* 「現在使用量+確保サイズ」が終端を超えていなければ確保は成功.
ZeroTLAB オプションの価に応じて initialize_header または initialize_object ラベルにジャンプする.
なお, この場合には, TLAB の現在使用量 (top 値) を新しい値に更新する処理も行っている.
* 「現在使用量+確保サイズ」が終端を超えている場合は,
このままフォールスルーして, shared eden からの確保または slow_path での確保を行う.」
---------------------------------------- -}
// if there is enough space, we do not CAS and do not clear
__ cmp(RnewTopValue, RendValue);
if(ZeroTLAB) {
// the fields have already been cleared
__ brx(Assembler::lessEqualUnsigned, true, Assembler::pt, initialize_header);
} else {
// initialize both the header and fields
__ brx(Assembler::lessEqualUnsigned, true, Assembler::pt, initialize_object);
}
__ delayed()->st_ptr(RnewTopValue, G2_thread, in_bytes(JavaThread::tlab_top_offset()));
{- -------------------------------------------
(1.1) コード生成: (条件に応じて以下のどちらかを生成)
* shared eden からの確保が可能な場合 (= allow_shared_alloc が true の場合):
「現在の TLAB の残り容量が _refill_waste_limit の値未満であれば,
slow_case ラベルまで分岐する (この場合, 現在の TLAB は捨てることになる).
逆に _refill_waste_limit の値以上であれば,
このままフォールスルーして shared eden からの確保処理を行う (この場合, 現在の TLAB は捨てられずに残る).
ただしフォールスルーする場合は, 似たような大きさの確保が続くと今後もここで引っかかり続けるので,
_refill_waste_limit の値を少し上げておく.」
* shared eden からの確保ができない場合 (= allow_shared_alloc が false の場合):
「slow_case ラベルまで分岐する.」
---------------------------------------- -}
if (allow_shared_alloc) {
// Check if tlab should be discarded (refill_waste_limit >= free)
__ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_refill_waste_limit_offset()), RtlabWasteLimitValue);
__ sub(RendValue, RoldTopValue, RfreeValue);
#ifdef _LP64
__ srlx(RfreeValue, LogHeapWordSize, RfreeValue);
#else
__ srl(RfreeValue, LogHeapWordSize, RfreeValue);
#endif
__ cmp(RtlabWasteLimitValue, RfreeValue);
__ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, slow_case); // tlab waste is small
__ delayed()->nop();
// increment waste limit to prevent getting stuck on this slow path
__ add(RtlabWasteLimitValue, ThreadLocalAllocBuffer::refill_waste_limit_increment(), RtlabWasteLimitValue);
__ st_ptr(RtlabWasteLimitValue, G2_thread, in_bytes(JavaThread::tlab_refill_waste_limit_offset()));
} else {
// No allocation in the shared eden.
__ br(Assembler::always, false, Assembler::pt, slow_case);
__ delayed()->nop();
}
}
{- -------------------------------------------
(1) (以下は, shared eden からの確保を試みるパス.
当然だが, このコードは shared eden が利用可能な場合にしか生成されない.
なお, このパスが実行されるのは,
UseTLAB オプションが指定されていない場合, もしくは 上記の TLAB からの確保処理が失敗した場合のみ)
---------------------------------------- -}
{- -------------------------------------------
(1.1) コード生成: (allow_shared_alloc が true の場合にのみ生成)
「shared eden からの確保処理を行う.
* 確保が成功すれば, initialize_object ラベルにフォールスルー
(<= なお, TLAB からの確保時と異なり ZeroTLAB オプションの値によって飛び先が変わることはない. まぁ TLAB ではないので当たり前か)
* 確保が失敗すれば, slow_case での処理に分岐する.」
---------------------------------------- -}
// Allocation in the shared Eden
if (allow_shared_alloc) {
Register RoldTopValue = G1_scratch;
Register RtopAddr = G3_scratch;
Register RnewTopValue = RallocatedObject;
Register RendValue = Rscratch;
{- -------------------------------------------
(1.1.1) コード生成:
「ヒープの eden 領域について, 現在使用量 (top 値) を指すアドレスを取得.」
---------------------------------------- -}
__ set((intptr_t)Universe::heap()->top_addr(), RtopAddr);
{- -------------------------------------------
(1.1.1) コード生成:
「空き容量が確保量よりも小さい間は, 確保に成功するまでループ
(以下の bind(retry) から ...#TODO までがループになる)」
---------------------------------------- -}
Label retry;
__ bind(retry);
{- -------------------------------------------
(1.1.1) コード生成:
「ヒープの eden 領域について, 現在使用量 (top 値) と領域の終端値 (end 値) を取得し,
「現在使用量+確保サイズ」を計算する.」
---------------------------------------- -}
__ set((intptr_t)Universe::heap()->end_addr(), RendValue);
__ ld_ptr(RendValue, 0, RendValue);
__ ld_ptr(RtopAddr, 0, RoldTopValue);
__ add(RoldTopValue, Roffset, RnewTopValue);
{- -------------------------------------------
(1.1.1) コード生成:
「もし空き容量が確保量よりも小さい間は slow_case にジャンプ」
---------------------------------------- -}
// RnewTopValue contains the top address after the new object
// has been allocated.
__ cmp(RnewTopValue, RendValue);
__ brx(Assembler::greaterUnsigned, false, Assembler::pn, slow_case);
__ delayed()->nop();
{- -------------------------------------------
(1.1.1) コード生成:
「cas で Universe::heap()->top を書き換えることでメモリを確保する.」
---------------------------------------- -}
__ casx_under_lock(RtopAddr, RoldTopValue, RnewTopValue,
VM_Version::v9_instructions_work() ? NULL :
(address)StubRoutines::Sparc::atomic_memory_operation_lock_addr());
{- -------------------------------------------
(1.1.1) コード生成:
「もし cas が失敗していれば retry に戻ってやり直し.」
---------------------------------------- -}
// if someone beat us on the allocation, try again, otherwise continue
__ cmp(RoldTopValue, RnewTopValue);
__ brx(Assembler::notEqual, false, Assembler::pn, retry);
__ delayed()->nop();
{- -------------------------------------------
(1.1.1) コード生成:
「cas が成功していれば, MacroAssembler::incr_allocated_bytes() で統計情報を更新しておく.
(See: [here](no2114Q4Z.html) for details)」
---------------------------------------- -}
// bump total bytes allocated by this thread
// RoldTopValue and RtopAddr are dead, so can use G1 and G3
__ incr_allocated_bytes(Roffset, G1_scratch, G3_scratch);
}
{- -------------------------------------------
(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()) {
// clear object fields
__ bind(initialize_object);
__ deccc(Roffset, sizeof(oopDesc));
__ br(Assembler::zero, false, Assembler::pt, initialize_header);
__ delayed()->add(RallocatedObject, sizeof(oopDesc), G3_scratch);
// initialize remaining object fields
{ Label loop;
__ subcc(Roffset, wordSize, Roffset);
__ bind(loop);
//__ subcc(Roffset, wordSize, Roffset); // executed above loop or in delay slot
__ st_ptr(G0, G3_scratch, Roffset);
__ br(Assembler::notEqual, false, Assembler::pt, loop);
__ delayed()->subcc(Roffset, wordSize, Roffset);
}
__ br(Assembler::always, false, Assembler::pt, initialize_header);
__ delayed()->nop();
}
{- -------------------------------------------
(1) (以下は fast-path が失敗した場合の処理パス.
つまりは, slow-path の処理パス. より具体的には, slow_case ラベルの bind 箇所)
---------------------------------------- -}
{- -------------------------------------------
(1.1) コード生成:
「InterpreterRuntime::_new() を呼び出すことで確保処理を行う. その後 done ラベルまでジャンプする.」
---------------------------------------- -}
// slow case
__ bind(slow_case);
__ get_2_byte_integer_at_bcp(1, G3_scratch, O2, InterpreterMacroAssembler::Unsigned);
__ get_constant_pool(O1);
call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), O1, O2);
__ ba(false, done);
__ delayed()->nop();
{- -------------------------------------------
(1) (以下は fast-path が成功した場合の処理パス.
より具体的には, initialize_header ラベルの bind 箇所)
---------------------------------------- -}
{- -------------------------------------------
(1.1) コード生成:
「確保したオブジェクトの mark フィールド, 及び klass フィールドを初期化する.
(なお, (DTrace のフック点) でもある).
その後 done ラベルへとフォールスルーする.」
---------------------------------------- -}
// Initialize the header: mark, klass
__ bind(initialize_header);
if (UseBiasedLocking) {
__ ld_ptr(RinstanceKlass, Klass::prototype_header_offset_in_bytes() + sizeof(oopDesc), G4_scratch);
} else {
__ set((intptr_t)markOopDesc::prototype(), G4_scratch);
}
__ st_ptr(G4_scratch, RallocatedObject, oopDesc::mark_offset_in_bytes()); // mark
__ store_klass_gap(G0, RallocatedObject); // klass gap if compressed
__ store_klass(RinstanceKlass, RallocatedObject); // klass (last for cms)
{
SkipIfEqual skip_if(
_masm, G4_scratch, &DTraceAllocProbes, Assembler::zero);
// Trigger dtrace event
__ push(atos);
__ call_VM_leaf(noreg,
CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), O0);
__ pop(atos);
}
{- -------------------------------------------
(1) (以下が, 確保処理が終わった後のジャンプ先.
より具体的には, done ラベルの bind 箇所)
---------------------------------------- -}
// continue
__ bind(done);
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.