# HG changeset patch # User iveresov # Date 1284405049 25200 # Node ID cfc616b49f589e9fa7d511d0b34f9f05687b70f3 # Parent 6f5143b00f4c770edbb9ac3b691b17e2f49bfbfe 6919069: client compiler needs to capture more profile information for tiered work Summary: Added profiling of instanceof and aastore. Reviewed-by: kvn, jrose, never diff -r 6f5143b00f4c -r cfc616b49f58 hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Sat Sep 11 15:21:37 2010 -0700 +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Mon Sep 13 12:10:49 2010 -0700 @@ -2471,8 +2471,25 @@ } } -void LIR_Assembler::emit_checkcast(LIR_OpTypeCheck *op) { - assert(op->code() == lir_checkcast, "Invalid operation"); + +void LIR_Assembler::setup_md_access(ciMethod* method, int bci, + ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias) { + md = method->method_data(); + if (md == NULL) { + bailout("out of memory building methodDataOop"); + return; + } + data = md->bci_to_data(bci); + assert(data != NULL, "need data for checkcast"); + assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); + if (!Assembler::is_simm13(md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes())) { + // The offset is large so bias the mdo by the base of the slot so + // that the ld can use simm13s to reference the slots of the data + mdo_offset_bias = md->byte_offset_of_slot(data, DataLayout::header_offset()); + } +} + +void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) { // we always need a stub for the failure case. CodeStub* stub = op->stub(); Register obj = op->object()->as_register(); @@ -2494,25 +2511,10 @@ if (op->should_profile()) { ciMethod* method = op->profiled_method(); assert(method != NULL, "Should have method"); - int bci = op->profiled_bci(); - md = method->method_data(); - if (md == NULL) { - bailout("out of memory building methodDataOop"); - return; - } - data = md->bci_to_data(bci); - assert(data != NULL, "need data for checkcast"); - assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for checkcast"); - if (!Assembler::is_simm13(md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes())) { - // The offset is large so bias the mdo by the base of the slot so - // that the ld can use simm13s to reference the slots of the data - mdo_offset_bias = md->byte_offset_of_slot(data, DataLayout::header_offset()); - } - - // We need two temporaries to perform this operation on SPARC, - // so to keep things simple we perform a redundant test here - Label profile_done; - __ br_notnull(obj, false, Assembler::pn, profile_done); + setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias); + + Label not_null; + __ br_notnull(obj, false, Assembler::pn, not_null); __ delayed()->nop(); Register mdo = k_RInfo; Register data_val = Rtmp1; @@ -2525,13 +2527,17 @@ __ ldub(flags_addr, data_val); __ or3(data_val, BitData::null_seen_byte_constant(), data_val); __ stb(data_val, flags_addr); - __ bind(profile_done); + __ ba(false, *obj_is_null); + __ delayed()->nop(); + __ bind(not_null); + } else { + __ br_null(obj, false, Assembler::pn, *obj_is_null); + __ delayed()->nop(); } - Label profile_cast_failure; - - Label done, done_null; - // Where to go in case of cast failure - Label *failure_target = op->should_profile() ? &profile_cast_failure : stub->entry(); + + Label profile_cast_failure, profile_cast_success; + Label *failure_target = op->should_profile() ? &profile_cast_failure : failure; + Label *success_target = op->should_profile() ? &profile_cast_success : success; // patching may screw with our temporaries on sparc, // so let's do it before loading the class @@ -2541,8 +2547,6 @@ jobject2reg_with_patching(k_RInfo, op->info_for_patch()); } assert(obj != k_RInfo, "must be different"); - __ br_null(obj, false, Assembler::pn, done_null); - __ delayed()->nop(); // get object class // not a safepoint as obj null check happens earlier @@ -2559,12 +2563,12 @@ need_slow_path = false; // perform the fast part of the checking logic __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, noreg, - (need_slow_path ? &done : NULL), + (need_slow_path ? success_target : NULL), failure_target, NULL, RegisterOrConstant(k->super_check_offset())); } else { // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, &done, + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, success_target, failure_target, NULL); } if (need_slow_path) { @@ -2575,27 +2579,24 @@ __ cmp(G3, 0); __ br(Assembler::equal, false, Assembler::pn, *failure_target); __ delayed()->nop(); + // Fall through to success case } } - __ bind(done); if (op->should_profile()) { Register mdo = klass_RInfo, recv = k_RInfo, tmp1 = Rtmp1; assert_different_registers(obj, mdo, recv, tmp1); - + __ bind(profile_cast_success); jobject2reg(md->constant_encoding(), mdo); if (mdo_offset_bias > 0) { __ set(mdo_offset_bias, tmp1); __ add(mdo, tmp1, mdo); } - Label update_done; load(Address(obj, oopDesc::klass_offset_in_bytes()), recv, T_OBJECT); - type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &update_done); + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, success); // Jump over the failure case - __ ba(false, update_done); + __ ba(false, *success); __ delayed()->nop(); - - // Cast failure case __ bind(profile_cast_failure); jobject2reg(md->constant_encoding(), mdo); @@ -2607,17 +2608,13 @@ __ ld_ptr(data_addr, tmp1); __ sub(tmp1, DataLayout::counter_increment, tmp1); __ st_ptr(tmp1, data_addr); - __ ba(false, *stub->entry()); + __ ba(false, *failure); __ delayed()->nop(); - - __ bind(update_done); } - - __ bind(done_null); - __ mov(obj, dst); + __ ba(false, *success); + __ delayed()->nop(); } - void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { LIR_Code code = op->code(); if (code == lir_store_check) { @@ -2628,88 +2625,106 @@ Register Rtmp1 = op->tmp3()->as_register(); __ verify_oop(value); - CodeStub* stub = op->stub(); - Label done; - __ br_null(value, false, Assembler::pn, done); - __ delayed()->nop(); + // check if it needs to be profiled + ciMethodData* md; + ciProfileData* data; + int mdo_offset_bias = 0; + if (op->should_profile()) { + ciMethod* method = op->profiled_method(); + assert(method != NULL, "Should have method"); + setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias); + } + Label profile_cast_success, profile_cast_failure, done; + Label *success_target = op->should_profile() ? &profile_cast_success : &done; + Label *failure_target = op->should_profile() ? &profile_cast_failure : stub->entry(); + + if (op->should_profile()) { + Label not_null; + __ br_notnull(value, false, Assembler::pn, not_null); + __ delayed()->nop(); + Register mdo = k_RInfo; + Register data_val = Rtmp1; + jobject2reg(md->constant_encoding(), mdo); + if (mdo_offset_bias > 0) { + __ set(mdo_offset_bias, data_val); + __ add(mdo, data_val, mdo); + } + Address flags_addr(mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias); + __ ldub(flags_addr, data_val); + __ or3(data_val, BitData::null_seen_byte_constant(), data_val); + __ stb(data_val, flags_addr); + __ ba(false, done); + __ delayed()->nop(); + __ bind(not_null); + } else { + __ br_null(value, false, Assembler::pn, done); + __ delayed()->nop(); + } load(array, oopDesc::klass_offset_in_bytes(), k_RInfo, T_OBJECT, op->info_for_exception()); load(value, oopDesc::klass_offset_in_bytes(), klass_RInfo, T_OBJECT, NULL); // get instance klass load(k_RInfo, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc), k_RInfo, T_OBJECT, NULL); // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, &done, stub->entry(), NULL); + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, success_target, failure_target, NULL); // call out-of-line instance of __ check_klass_subtype_slow_path(...): assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); __ delayed()->nop(); __ cmp(G3, 0); - __ br(Assembler::equal, false, Assembler::pn, *stub->entry()); + __ br(Assembler::equal, false, Assembler::pn, *failure_target); __ delayed()->nop(); + // fall through to the success case + + if (op->should_profile()) { + Register mdo = klass_RInfo, recv = k_RInfo, tmp1 = Rtmp1; + assert_different_registers(value, mdo, recv, tmp1); + __ bind(profile_cast_success); + jobject2reg(md->constant_encoding(), mdo); + if (mdo_offset_bias > 0) { + __ set(mdo_offset_bias, tmp1); + __ add(mdo, tmp1, mdo); + } + load(Address(value, oopDesc::klass_offset_in_bytes()), recv, T_OBJECT); + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &done); + __ ba(false, done); + __ delayed()->nop(); + // Cast failure case + __ bind(profile_cast_failure); + jobject2reg(md->constant_encoding(), mdo); + if (mdo_offset_bias > 0) { + __ set(mdo_offset_bias, tmp1); + __ add(mdo, tmp1, mdo); + } + Address data_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias); + __ ld_ptr(data_addr, tmp1); + __ sub(tmp1, DataLayout::counter_increment, tmp1); + __ st_ptr(tmp1, data_addr); + __ ba(false, *stub->entry()); + __ delayed()->nop(); + } __ bind(done); + } else if (code == lir_checkcast) { + Register obj = op->object()->as_register(); + Register dst = op->result_opr()->as_register(); + Label success; + emit_typecheck_helper(op, &success, op->stub()->entry(), &success); + __ bind(success); + __ mov(obj, dst); } else if (code == lir_instanceof) { Register obj = op->object()->as_register(); - Register k_RInfo = op->tmp1()->as_register(); - Register klass_RInfo = op->tmp2()->as_register(); Register dst = op->result_opr()->as_register(); - Register Rtmp1 = op->tmp3()->as_register(); - ciKlass* k = op->klass(); - - Label done; - if (obj == k_RInfo) { - k_RInfo = klass_RInfo; - klass_RInfo = obj; - } - // patching may screw with our temporaries on sparc, - // so let's do it before loading the class - if (k->is_loaded()) { - jobject2reg(k->constant_encoding(), k_RInfo); - } else { - jobject2reg_with_patching(k_RInfo, op->info_for_patch()); - } - assert(obj != k_RInfo, "must be different"); - __ br_null(obj, true, Assembler::pn, done); - __ delayed()->set(0, dst); - - // get object class - // not a safepoint as obj null check happens earlier - load(obj, oopDesc::klass_offset_in_bytes(), klass_RInfo, T_OBJECT, NULL); - if (op->fast_check()) { - __ cmp(k_RInfo, klass_RInfo); - __ brx(Assembler::equal, true, Assembler::pt, done); - __ delayed()->set(1, dst); - __ set(0, dst); - __ bind(done); - } else { - bool need_slow_path = true; - if (k->is_loaded()) { - if (k->super_check_offset() != sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()) - need_slow_path = false; - // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, O7, noreg, - (need_slow_path ? &done : NULL), - (need_slow_path ? &done : NULL), NULL, - RegisterOrConstant(k->super_check_offset()), - dst); - } else { - assert(dst != klass_RInfo && dst != k_RInfo, "need 3 registers"); - // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, O7, dst, - &done, &done, NULL, - RegisterOrConstant(-1), - dst); - } - if (need_slow_path) { - // call out-of-line instance of __ check_klass_subtype_slow_path(...): - assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); - __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - __ mov(G3, dst); - } - __ bind(done); - } + Label success, failure, done; + emit_typecheck_helper(op, &success, &failure, &failure); + __ bind(failure); + __ set(0, dst); + __ ba(false, done); + __ delayed()->nop(); + __ bind(success); + __ set(1, dst); + __ bind(done); } else { ShouldNotReachHere(); } diff -r 6f5143b00f4c -r cfc616b49f58 hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp Sat Sep 11 15:21:37 2010 -0700 +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.hpp Mon Sep 13 12:10:49 2010 -0700 @@ -75,6 +75,9 @@ void type_profile_helper(Register mdo, int mdo_offset_bias, ciMethodData *md, ciProfileData *data, Register recv, Register tmp1, Label* update_done); + // Setup pointers to MDO, MDO slot, also compute offset bias to access the slot. + void setup_md_access(ciMethod* method, int bci, + ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias); public: void pack64(LIR_Opr src, LIR_Opr dst); void unpack64(LIR_Opr src, LIR_Opr dst); diff -r 6f5143b00f4c -r cfc616b49f58 hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Sat Sep 11 15:21:37 2010 -0700 +++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Mon Sep 13 12:10:49 2010 -0700 @@ -1047,7 +1047,9 @@ LIR_Opr tmp1 = FrameMap::G1_oop_opr; LIR_Opr tmp2 = FrameMap::G3_oop_opr; LIR_Opr tmp3 = FrameMap::G4_oop_opr; - __ instanceof(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3, x->direct_compare(), patching_info); + __ instanceof(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3, + x->direct_compare(), patching_info, + x->profiled_method(), x->profiled_bci()); } diff -r 6f5143b00f4c -r cfc616b49f58 hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Sat Sep 11 15:21:37 2010 -0700 +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Mon Sep 13 12:10:49 2010 -0700 @@ -1624,7 +1624,7 @@ __ jccb(Assembler::notEqual, next_test); Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i))); __ addptr(data_addr, DataLayout::counter_increment); - __ jmpb(*update_done); + __ jmp(*update_done); __ bind(next_test); } @@ -1636,13 +1636,12 @@ __ jccb(Assembler::notEqual, next_test); __ movptr(recv_addr, recv); __ movptr(Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i))), DataLayout::counter_increment); - __ jmpb(*update_done); + __ jmp(*update_done); __ bind(next_test); } } -void LIR_Assembler::emit_checkcast(LIR_OpTypeCheck *op) { - assert(op->code() == lir_checkcast, "Invalid operation"); +void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) { // we always need a stub for the failure case. CodeStub* stub = op->stub(); Register obj = op->object()->as_register(); @@ -1666,14 +1665,12 @@ return; } data = md->bci_to_data(bci); - assert(data != NULL, "need data for checkcast"); - assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for checkcast"); + assert(data != NULL, "need data for type check"); + assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); } - Label profile_cast_failure; - - Label done, done_null; - // Where to go in case of cast failure - Label *failure_target = op->should_profile() ? &profile_cast_failure : stub->entry(); + Label profile_cast_success, profile_cast_failure; + Label *success_target = op->should_profile() ? &profile_cast_success : success; + Label *failure_target = op->should_profile() ? &profile_cast_failure : failure; if (obj == k_RInfo) { k_RInfo = dst; @@ -1699,23 +1696,23 @@ __ cmpptr(obj, (int32_t)NULL_WORD); if (op->should_profile()) { - Label profile_done; - __ jccb(Assembler::notEqual, profile_done); - // Object is null; update methodDataOop + Label not_null; + __ jccb(Assembler::notEqual, not_null); + // Object is null; update MDO and exit Register mdo = klass_RInfo; __ movoop(mdo, md->constant_encoding()); Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::header_offset())); int header_bits = DataLayout::flag_mask_to_header_mask(BitData::null_seen_byte_constant()); __ orl(data_addr, header_bits); - __ jmp(done_null); - __ bind(profile_done); + __ jmp(*obj_is_null); + __ bind(not_null); } else { - __ jcc(Assembler::equal, done_null); + __ jcc(Assembler::equal, *obj_is_null); } __ verify_oop(obj); if (op->fast_check()) { - // get object classo + // get object class // not a safepoint as obj null check happens earlier if (k->is_loaded()) { #ifdef _LP64 @@ -1727,6 +1724,7 @@ __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); } __ jcc(Assembler::notEqual, *failure_target); + // successful cast, fall through to profile or jump } else { // get object class // not a safepoint as obj null check happens earlier @@ -1740,16 +1738,17 @@ #endif // _LP64 if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() != k->super_check_offset()) { __ jcc(Assembler::notEqual, *failure_target); + // successful cast, fall through to profile or jump } else { // See if we get an immediate positive hit - __ jcc(Assembler::equal, done); + __ jcc(Assembler::equal, *success_target); // check for self #ifdef _LP64 __ cmpptr(klass_RInfo, k_RInfo); #else __ cmpoop(klass_RInfo, k->constant_encoding()); #endif // _LP64 - __ jcc(Assembler::equal, done); + __ jcc(Assembler::equal, *success_target); __ push(klass_RInfo); #ifdef _LP64 @@ -1763,10 +1762,11 @@ // result is a boolean __ cmpl(klass_RInfo, 0); __ jcc(Assembler::equal, *failure_target); + // successful cast, fall through to profile or jump } } else { // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, &done, failure_target, NULL); + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, NULL); // call out-of-line instance of __ check_klass_subtype_slow_path(...): __ push(klass_RInfo); __ push(k_RInfo); @@ -1776,32 +1776,28 @@ // result is a boolean __ cmpl(k_RInfo, 0); __ jcc(Assembler::equal, *failure_target); + // successful cast, fall through to profile or jump } } - __ bind(done); - if (op->should_profile()) { Register mdo = klass_RInfo, recv = k_RInfo; + __ bind(profile_cast_success); __ movoop(mdo, md->constant_encoding()); __ movptr(recv, Address(obj, oopDesc::klass_offset_in_bytes())); Label update_done; - type_profile_helper(mdo, md, data, recv, &update_done); - __ jmpb(update_done); + type_profile_helper(mdo, md, data, recv, success); + __ jmp(*success); __ bind(profile_cast_failure); __ movoop(mdo, md->constant_encoding()); Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); __ subptr(counter_addr, DataLayout::counter_increment); - __ jmp(*stub->entry()); - - __ bind(update_done); + __ jmp(*failure); } - __ bind(done_null); - if (dst != obj) { - __ mov(dst, obj); - } + __ jmp(*success); } + void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { LIR_Code code = op->code(); if (code == lir_store_check) { @@ -1812,9 +1808,44 @@ Register Rtmp1 = op->tmp3()->as_register(); CodeStub* stub = op->stub(); - Label done; + + // check if it needs to be profiled + ciMethodData* md; + ciProfileData* data; + + if (op->should_profile()) { + ciMethod* method = op->profiled_method(); + assert(method != NULL, "Should have method"); + int bci = op->profiled_bci(); + md = method->method_data(); + if (md == NULL) { + bailout("out of memory building methodDataOop"); + return; + } + data = md->bci_to_data(bci); + assert(data != NULL, "need data for type check"); + assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); + } + Label profile_cast_success, profile_cast_failure, done; + Label *success_target = op->should_profile() ? &profile_cast_success : &done; + Label *failure_target = op->should_profile() ? &profile_cast_failure : stub->entry(); + __ cmpptr(value, (int32_t)NULL_WORD); - __ jcc(Assembler::equal, done); + if (op->should_profile()) { + Label not_null; + __ jccb(Assembler::notEqual, not_null); + // Object is null; update MDO and exit + Register mdo = klass_RInfo; + __ movoop(mdo, md->constant_encoding()); + Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::header_offset())); + int header_bits = DataLayout::flag_mask_to_header_mask(BitData::null_seen_byte_constant()); + __ orl(data_addr, header_bits); + __ jmp(done); + __ bind(not_null); + } else { + __ jcc(Assembler::equal, done); + } + add_debug_info_for_null_check_here(op->info_for_exception()); __ movptr(k_RInfo, Address(array, oopDesc::klass_offset_in_bytes())); __ movptr(klass_RInfo, Address(value, oopDesc::klass_offset_in_bytes())); @@ -1822,7 +1853,7 @@ // get instance klass __ movptr(k_RInfo, Address(k_RInfo, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc))); // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, &done, stub->entry(), NULL); + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, NULL); // call out-of-line instance of __ check_klass_subtype_slow_path(...): __ push(klass_RInfo); __ push(k_RInfo); @@ -1831,94 +1862,51 @@ __ pop(k_RInfo); // result is a boolean __ cmpl(k_RInfo, 0); - __ jcc(Assembler::equal, *stub->entry()); - __ bind(done); - } else if (code == lir_instanceof) { - Register obj = op->object()->as_register(); - Register k_RInfo = op->tmp1()->as_register(); - Register klass_RInfo = op->tmp2()->as_register(); - Register dst = op->result_opr()->as_register(); - ciKlass* k = op->klass(); - - Label done; - Label zero; - Label one; - if (obj == k_RInfo) { - k_RInfo = klass_RInfo; - klass_RInfo = obj; + __ jcc(Assembler::equal, *failure_target); + // fall through to the success case + + if (op->should_profile()) { + Register mdo = klass_RInfo, recv = k_RInfo; + __ bind(profile_cast_success); + __ movoop(mdo, md->constant_encoding()); + __ movptr(recv, Address(value, oopDesc::klass_offset_in_bytes())); + Label update_done; + type_profile_helper(mdo, md, data, recv, &done); + __ jmpb(done); + + __ bind(profile_cast_failure); + __ movoop(mdo, md->constant_encoding()); + Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); + __ subptr(counter_addr, DataLayout::counter_increment); + __ jmp(*stub->entry()); } - // patching may screw with our temporaries on sparc, - // so let's do it before loading the class - if (!k->is_loaded()) { - jobject2reg_with_patching(k_RInfo, op->info_for_patch()); - } else { - LP64_ONLY(__ movoop(k_RInfo, k->constant_encoding())); - } - assert(obj != k_RInfo, "must be different"); - - __ verify_oop(obj); - if (op->fast_check()) { - __ cmpptr(obj, (int32_t)NULL_WORD); - __ jcc(Assembler::equal, zero); - // get object class - // not a safepoint as obj null check happens earlier - if (LP64_ONLY(false &&) k->is_loaded()) { - NOT_LP64(__ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->constant_encoding())); - k_RInfo = noreg; - } else { - __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); - + + __ bind(done); + } else + if (code == lir_checkcast) { + Register obj = op->object()->as_register(); + Register dst = op->result_opr()->as_register(); + Label success; + emit_typecheck_helper(op, &success, op->stub()->entry(), &success); + __ bind(success); + if (dst != obj) { + __ mov(dst, obj); } - __ jcc(Assembler::equal, one); - } else { - // get object class - // not a safepoint as obj null check happens earlier - __ cmpptr(obj, (int32_t)NULL_WORD); - __ jcc(Assembler::equal, zero); - __ movptr(klass_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); - -#ifndef _LP64 - if (k->is_loaded()) { - // See if we get an immediate positive hit - __ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->constant_encoding()); - __ jcc(Assembler::equal, one); - if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() == k->super_check_offset()) { - // check for self - __ cmpoop(klass_RInfo, k->constant_encoding()); - __ jcc(Assembler::equal, one); - __ push(klass_RInfo); - __ pushoop(k->constant_encoding()); - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); - __ pop(klass_RInfo); - __ pop(dst); - __ jmp(done); - } + } else + if (code == lir_instanceof) { + Register obj = op->object()->as_register(); + Register dst = op->result_opr()->as_register(); + Label success, failure, done; + emit_typecheck_helper(op, &success, &failure, &failure); + __ bind(failure); + __ xorptr(dst, dst); + __ jmpb(done); + __ bind(success); + __ movptr(dst, 1); + __ bind(done); + } else { + ShouldNotReachHere(); } - else // next block is unconditional if LP64: -#endif // LP64 - { - assert(dst != klass_RInfo && dst != k_RInfo, "need 3 registers"); - - // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, dst, &one, &zero, NULL); - // call out-of-line instance of __ check_klass_subtype_slow_path(...): - __ push(klass_RInfo); - __ push(k_RInfo); - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); - __ pop(klass_RInfo); - __ pop(dst); - __ jmp(done); - } - } - __ bind(zero); - __ xorptr(dst, dst); - __ jmp(done); - __ bind(one); - __ movptr(dst, 1); - __ bind(done); - } else { - ShouldNotReachHere(); - } } diff -r 6f5143b00f4c -r cfc616b49f58 hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Sat Sep 11 15:21:37 2010 -0700 +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Mon Sep 13 12:10:49 2010 -0700 @@ -1156,10 +1156,10 @@ patching_info = state_for(x, x->state_before()); } obj.load_item(); - LIR_Opr tmp = new_register(objectType); __ instanceof(reg, obj.result(), x->klass(), - tmp, new_register(objectType), LIR_OprFact::illegalOpr, - x->direct_compare(), patching_info); + new_register(objectType), new_register(objectType), + !x->klass()->is_loaded() ? new_register(objectType) : LIR_OprFact::illegalOpr, + x->direct_compare(), patching_info, x->profiled_method(), x->profiled_bci()); } diff -r 6f5143b00f4c -r cfc616b49f58 hotspot/src/share/vm/c1/c1_Canonicalizer.cpp --- a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp Sat Sep 11 15:21:37 2010 -0700 +++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp Mon Sep 13 12:10:49 2010 -0700 @@ -673,6 +673,8 @@ } else if (l->as_InstanceOf() != NULL) { // NOTE: Code permanently disabled for now since it leaves the old InstanceOf // instruction in the graph (it is pinned). Need to fix this at some point. + // It should also be left in the graph when generating a profiled method version or Goto + // has to know that it was an InstanceOf. return; // pattern: If ((obj instanceof klass) cond rc) => simplify to: IfInstanceOf or: Goto InstanceOf* inst = l->as_InstanceOf(); diff -r 6f5143b00f4c -r cfc616b49f58 hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Sat Sep 11 15:21:37 2010 -0700 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Mon Sep 13 12:10:49 2010 -0700 @@ -967,6 +967,17 @@ StoreIndexed* result = new StoreIndexed(array, index, length, type, value, lock_stack()); append(result); _memory->store_value(value); + + if (type == T_OBJECT && is_profiling()) { + // Note that we'd collect profile data in this method if we wanted it. + compilation()->set_would_profile(true); + + if (profile_checkcasts()) { + result->set_profiled_method(method()); + result->set_profiled_bci(bci()); + result->set_should_profile(true); + } + } } @@ -1852,6 +1863,17 @@ InstanceOf* i = new InstanceOf(klass, apop(), state_before); ipush(append_split(i)); i->set_direct_compare(direct_compare(klass)); + + if (is_profiling()) { + // Note that we'd collect profile data in this method if we wanted it. + compilation()->set_would_profile(true); + + if (profile_checkcasts()) { + i->set_profiled_method(method()); + i->set_profiled_bci(bci()); + i->set_should_profile(true); + } + } } diff -r 6f5143b00f4c -r cfc616b49f58 hotspot/src/share/vm/c1/c1_Instruction.hpp --- a/hotspot/src/share/vm/c1/c1_Instruction.hpp Sat Sep 11 15:21:37 2010 -0700 +++ b/hotspot/src/share/vm/c1/c1_Instruction.hpp Mon Sep 13 12:10:49 2010 -0700 @@ -906,11 +906,13 @@ private: Value _value; + ciMethod* _profiled_method; + int _profiled_bci; public: // creation StoreIndexed(Value array, Value index, Value length, BasicType elt_type, Value value, ValueStack* lock_stack) : AccessIndexed(array, index, length, elt_type, lock_stack) - , _value(value) + , _value(value), _profiled_method(NULL), _profiled_bci(0) { set_flag(NeedsWriteBarrierFlag, (as_ValueType(elt_type)->is_object())); set_flag(NeedsStoreCheckFlag, (as_ValueType(elt_type)->is_object())); @@ -923,7 +925,13 @@ IRScope* scope() const; // the state's scope bool needs_write_barrier() const { return check_flag(NeedsWriteBarrierFlag); } bool needs_store_check() const { return check_flag(NeedsStoreCheckFlag); } - + // Helpers for methodDataOop profiling + void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } + void set_profiled_method(ciMethod* method) { _profiled_method = method; } + void set_profiled_bci(int bci) { _profiled_bci = bci; } + bool should_profile() const { return check_flag(ProfileMDOFlag); } + ciMethod* profiled_method() const { return _profiled_method; } + int profiled_bci() const { return _profiled_bci; } // generic virtual void input_values_do(ValueVisitor* f) { AccessIndexed::input_values_do(f); f->visit(&_value); } }; @@ -1297,9 +1305,14 @@ Value _obj; ValueStack* _state_before; + ciMethod* _profiled_method; + int _profiled_bci; + public: // creation - TypeCheck(ciKlass* klass, Value obj, ValueType* type, ValueStack* state_before) : StateSplit(type), _klass(klass), _obj(obj), _state_before(state_before) { + TypeCheck(ciKlass* klass, Value obj, ValueType* type, ValueStack* state_before) + : StateSplit(type), _klass(klass), _obj(obj), _state_before(state_before), + _profiled_method(NULL), _profiled_bci(0) { ASSERT_VALUES set_direct_compare(false); } @@ -1318,20 +1331,22 @@ virtual bool can_trap() const { return true; } virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_obj); } virtual void other_values_do(ValueVisitor* f); + + // Helpers for methodDataOop profiling + void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } + void set_profiled_method(ciMethod* method) { _profiled_method = method; } + void set_profiled_bci(int bci) { _profiled_bci = bci; } + bool should_profile() const { return check_flag(ProfileMDOFlag); } + ciMethod* profiled_method() const { return _profiled_method; } + int profiled_bci() const { return _profiled_bci; } }; LEAF(CheckCast, TypeCheck) - private: - ciMethod* _profiled_method; - int _profiled_bci; - public: // creation CheckCast(ciKlass* klass, Value obj, ValueStack* state_before) - : TypeCheck(klass, obj, objectType, state_before) - , _profiled_method(NULL) - , _profiled_bci(0) {} + : TypeCheck(klass, obj, objectType, state_before) {} void set_incompatible_class_change_check() { set_flag(ThrowIncompatibleClassChangeErrorFlag, true); @@ -1340,17 +1355,8 @@ return check_flag(ThrowIncompatibleClassChangeErrorFlag); } - // Helpers for methodDataOop profiling - void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } - void set_profiled_method(ciMethod* method) { _profiled_method = method; } - void set_profiled_bci(int bci) { _profiled_bci = bci; } - bool should_profile() const { return check_flag(ProfileMDOFlag); } - ciMethod* profiled_method() const { return _profiled_method; } - int profiled_bci() const { return _profiled_bci; } - ciType* declared_type() const; ciType* exact_type() const; - }; diff -r 6f5143b00f4c -r cfc616b49f58 hotspot/src/share/vm/c1/c1_LIR.cpp --- a/hotspot/src/share/vm/c1/c1_LIR.cpp Sat Sep 11 15:21:37 2010 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIR.cpp Mon Sep 13 12:10:49 2010 -0700 @@ -1019,11 +1019,7 @@ } void LIR_OpTypeCheck::emit_code(LIR_Assembler* masm) { - if (code() == lir_checkcast) { - masm->emit_checkcast(this); - } else { - masm->emit_opTypeCheck(this); - } + masm->emit_opTypeCheck(this); if (stub()) { masm->emit_code_stub(stub()); } @@ -1380,8 +1376,14 @@ append(c); } -void LIR_List::instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_patch) { - append(new LIR_OpTypeCheck(lir_instanceof, result, object, klass, tmp1, tmp2, tmp3, fast_check, NULL, info_for_patch, NULL)); +void LIR_List::instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_patch, ciMethod* profiled_method, int profiled_bci) { + LIR_OpTypeCheck* c = new LIR_OpTypeCheck(lir_instanceof, result, object, klass, tmp1, tmp2, tmp3, fast_check, NULL, info_for_patch, NULL); + if (profiled_method != NULL) { + c->set_profiled_method(profiled_method); + c->set_profiled_bci(profiled_bci); + c->set_should_profile(true); + } + append(c); } diff -r 6f5143b00f4c -r cfc616b49f58 hotspot/src/share/vm/c1/c1_LIR.hpp --- a/hotspot/src/share/vm/c1/c1_LIR.hpp Sat Sep 11 15:21:37 2010 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp Mon Sep 13 12:10:49 2010 -0700 @@ -2041,7 +2041,7 @@ void fpop_raw() { append(new LIR_Op0(lir_fpop_raw)); } - void instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_patch); + void instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_patch, ciMethod* profiled_method, int profiled_bci); void store_check(LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception); void checkcast (LIR_Opr result, LIR_Opr object, ciKlass* klass, diff -r 6f5143b00f4c -r cfc616b49f58 hotspot/src/share/vm/c1/c1_LIRAssembler.hpp --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp Sat Sep 11 15:21:37 2010 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp Mon Sep 13 12:10:49 2010 -0700 @@ -187,7 +187,7 @@ void emit_alloc_obj(LIR_OpAllocObj* op); void emit_alloc_array(LIR_OpAllocArray* op); void emit_opTypeCheck(LIR_OpTypeCheck* op); - void emit_checkcast(LIR_OpTypeCheck* op); + void emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null); void emit_compare_and_swap(LIR_OpCompareAndSwap* op); void emit_lock(LIR_OpLock* op); void emit_call(LIR_OpJavaCall* op);