# HG changeset patch # User kvn # Date 1265071789 28800 # Node ID 87684f1a88b5c70482c47fbd38329085663f6bb5 # Parent 5fcfaa1ad96fbe899ab4d49466d95e57e863f670 6614597: Performance variability in jvm2008 xml.validation Summary: Fix incorrect marking of methods as not compilable. Reviewed-by: never diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/cpu/sparc/vm/interp_masm_sparc.cpp --- a/src/cpu/sparc/vm/interp_masm_sparc.cpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp Mon Feb 01 16:49:49 2010 -0800 @@ -1681,11 +1681,8 @@ // If no method data exists, go to profile_continue. test_method_data_pointer(profile_continue); - // We are making a call. Increment the count. - increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); - // Record the receiver type. - record_klass_in_profile(receiver, scratch); + record_klass_in_profile(receiver, scratch, true); // The method data pointer needs to be updated to reflect the new target. update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); @@ -1695,9 +1692,13 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper( Register receiver, Register scratch, - int start_row, Label& done) { - if (TypeProfileWidth == 0) + int start_row, Label& done, bool is_virtual_call) { + if (TypeProfileWidth == 0) { + if (is_virtual_call) { + increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); + } return; + } int last_row = VirtualCallData::row_limit() - 1; assert(start_row <= last_row, "must be work left to do"); @@ -1714,6 +1715,7 @@ // See if the receiver is receiver[n]. int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); test_mdp_data_at(recvr_offset, receiver, next_test, scratch); + // delayed()->tst(scratch); // The receiver is receiver[n]. Increment count[n]. int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); @@ -1723,20 +1725,31 @@ bind(next_test); if (test_for_null_also) { + Label found_null; // Failed the equality check on receiver[n]... Test for null. if (start_row == last_row) { // The only thing left to do is handle the null case. - brx(Assembler::notZero, false, Assembler::pt, done); - delayed()->nop(); + if (is_virtual_call) { + brx(Assembler::zero, false, Assembler::pn, found_null); + delayed()->nop(); + // Receiver did not match any saved receiver and there is no empty row for it. + // Increment total counter to indicate polimorphic case. + increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); + ba(false, done); + delayed()->nop(); + bind(found_null); + } else { + brx(Assembler::notZero, false, Assembler::pt, done); + delayed()->nop(); + } break; } // Since null is rare, make it be the branch-taken case. - Label found_null; brx(Assembler::zero, false, Assembler::pn, found_null); delayed()->nop(); // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, scratch, start_row + 1, done); + record_klass_in_profile_helper(receiver, scratch, start_row + 1, done, is_virtual_call); // Found a null. Keep searching for a matching receiver, // but remember that this is an empty (unused) slot. @@ -1753,16 +1766,18 @@ int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); mov(DataLayout::counter_increment, scratch); set_mdp_data_at(count_offset, scratch); - ba(false, done); - delayed()->nop(); + if (start_row > 0) { + ba(false, done); + delayed()->nop(); + } } void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, - Register scratch) { + Register scratch, bool is_virtual_call) { assert(ProfileInterpreter, "must be profiling"); Label done; - record_klass_in_profile_helper(receiver, scratch, 0, done); + record_klass_in_profile_helper(receiver, scratch, 0, done, is_virtual_call); bind (done); } @@ -1840,7 +1855,7 @@ mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); // Record the object type. - record_klass_in_profile(klass, scratch); + record_klass_in_profile(klass, scratch, false); } // The method data pointer needs to be updated. diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/cpu/sparc/vm/interp_masm_sparc.hpp --- a/src/cpu/sparc/vm/interp_masm_sparc.hpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/cpu/sparc/vm/interp_masm_sparc.hpp Mon Feb 01 16:49:49 2010 -0800 @@ -290,9 +290,9 @@ void test_mdp_data_at(int offset, Register value, Label& not_equal_continue, Register scratch); - void record_klass_in_profile(Register receiver, Register scratch); + void record_klass_in_profile(Register receiver, Register scratch, bool is_virtual_call); void record_klass_in_profile_helper(Register receiver, Register scratch, - int start_row, Label& done); + int start_row, Label& done, bool is_virtual_call); void update_mdp_by_offset(int offset_of_disp, Register scratch); void update_mdp_by_offset(Register reg, int offset_of_disp, diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Mon Feb 01 16:49:49 2010 -0800 @@ -3209,7 +3209,6 @@ Register mdo = op->mdo()->as_register(); __ movoop(mdo, md->constant_encoding()); Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); - __ addl(counter_addr, DataLayout::counter_increment); Bytecodes::Code bc = method->java_code_at_bci(bci); // Perform additional virtual call profiling for invokevirtual and // invokeinterface bytecodes @@ -3276,14 +3275,18 @@ __ jcc(Assembler::notEqual, next_test); __ movptr(recv_addr, recv); __ movl(Address(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))), DataLayout::counter_increment); - if (i < (VirtualCallData::row_limit() - 1)) { - __ jmp(update_done); - } + __ jmp(update_done); __ bind(next_test); } + // Receiver did not match any saved receiver and there is no empty row for it. + // Increment total counter to indicate polimorphic case. + __ addl(counter_addr, DataLayout::counter_increment); __ bind(update_done); } + } else { + // Static call + __ addl(counter_addr, DataLayout::counter_increment); } } diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/cpu/x86/vm/interp_masm_x86_32.cpp --- a/src/cpu/x86/vm/interp_masm_x86_32.cpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp Mon Feb 01 16:49:49 2010 -0800 @@ -1239,17 +1239,19 @@ // If no method data exists, go to profile_continue. test_method_data_pointer(mdp, profile_continue); - // We are making a call. Increment the count. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - Label skip_receiver_profile; if (receiver_can_be_null) { + Label not_null; testptr(receiver, receiver); - jcc(Assembler::zero, skip_receiver_profile); + jccb(Assembler::notZero, not_null); + // We are making a call. Increment the count for null receiver. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + jmp(skip_receiver_profile); + bind(not_null); } // Record the receiver type. - record_klass_in_profile(receiver, mdp, reg2); + record_klass_in_profile(receiver, mdp, reg2, true); bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. @@ -1263,10 +1265,14 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper( Register receiver, Register mdp, - Register reg2, - int start_row, Label& done) { - if (TypeProfileWidth == 0) + Register reg2, int start_row, + Label& done, bool is_virtual_call) { + if (TypeProfileWidth == 0) { + if (is_virtual_call) { + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + } return; + } int last_row = VirtualCallData::row_limit() - 1; assert(start_row <= last_row, "must be work left to do"); @@ -1294,19 +1300,28 @@ bind(next_test); if (row == start_row) { + Label found_null; // Failed the equality check on receiver[n]... Test for null. testptr(reg2, reg2); if (start_row == last_row) { // The only thing left to do is handle the null case. - jcc(Assembler::notZero, done); + if (is_virtual_call) { + jccb(Assembler::zero, found_null); + // Receiver did not match any saved receiver and there is no empty row for it. + // Increment total counter to indicate polimorphic case. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + jmp(done); + bind(found_null); + } else { + jcc(Assembler::notZero, done); + } break; } // Since null is rare, make it be the branch-taken case. - Label found_null; jcc(Assembler::zero, found_null); // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done); + record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); // Found a null. Keep searching for a matching receiver, // but remember that this is an empty (unused) slot. @@ -1323,16 +1338,18 @@ int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); movptr(reg2, (int32_t)DataLayout::counter_increment); set_mdp_data_at(mdp, count_offset, reg2); - jmp(done); + if (start_row > 0) { + jmp(done); + } } void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, - Register mdp, - Register reg2) { + Register mdp, Register reg2, + bool is_virtual_call) { assert(ProfileInterpreter, "must be profiling"); Label done; - record_klass_in_profile_helper(receiver, mdp, reg2, 0, done); + record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call); bind (done); } @@ -1425,7 +1442,7 @@ mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); // Record the object type. - record_klass_in_profile(klass, mdp, reg2); + record_klass_in_profile(klass, mdp, reg2, false); assert(reg2 == rdi, "we know how to fix this blown reg"); restore_locals(); // Restore EDI } diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/cpu/x86/vm/interp_masm_x86_32.hpp --- a/src/cpu/x86/vm/interp_masm_x86_32.hpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_32.hpp Mon Feb 01 16:49:49 2010 -0800 @@ -213,10 +213,10 @@ Label& not_equal_continue); void record_klass_in_profile(Register receiver, Register mdp, - Register reg2); + Register reg2, bool is_virtual_call); void record_klass_in_profile_helper(Register receiver, Register mdp, - Register reg2, - int start_row, Label& done); + Register reg2, int start_row, + Label& done, bool is_virtual_call); void update_mdp_by_offset(Register mdp_in, int offset_of_offset); void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/cpu/x86/vm/interp_masm_x86_64.cpp --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Mon Feb 01 16:49:49 2010 -0800 @@ -1262,17 +1262,19 @@ // If no method data exists, go to profile_continue. test_method_data_pointer(mdp, profile_continue); - // We are making a call. Increment the count. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - Label skip_receiver_profile; if (receiver_can_be_null) { + Label not_null; testptr(receiver, receiver); - jcc(Assembler::zero, skip_receiver_profile); + jccb(Assembler::notZero, not_null); + // We are making a call. Increment the count for null receiver. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + jmp(skip_receiver_profile); + bind(not_null); } // Record the receiver type. - record_klass_in_profile(receiver, mdp, reg2); + record_klass_in_profile(receiver, mdp, reg2, true); bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. @@ -1296,10 +1298,14 @@ // See below for example code. void InterpreterMacroAssembler::record_klass_in_profile_helper( Register receiver, Register mdp, - Register reg2, - int start_row, Label& done) { - if (TypeProfileWidth == 0) + Register reg2, int start_row, + Label& done, bool is_virtual_call) { + if (TypeProfileWidth == 0) { + if (is_virtual_call) { + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + } return; + } int last_row = VirtualCallData::row_limit() - 1; assert(start_row <= last_row, "must be work left to do"); @@ -1327,19 +1333,28 @@ bind(next_test); if (test_for_null_also) { + Label found_null; // Failed the equality check on receiver[n]... Test for null. testptr(reg2, reg2); if (start_row == last_row) { // The only thing left to do is handle the null case. - jcc(Assembler::notZero, done); + if (is_virtual_call) { + jccb(Assembler::zero, found_null); + // Receiver did not match any saved receiver and there is no empty row for it. + // Increment total counter to indicate polimorphic case. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + jmp(done); + bind(found_null); + } else { + jcc(Assembler::notZero, done); + } break; } // Since null is rare, make it be the branch-taken case. - Label found_null; jcc(Assembler::zero, found_null); // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done); + record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); // Found a null. Keep searching for a matching receiver, // but remember that this is an empty (unused) slot. @@ -1356,7 +1371,9 @@ int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); movl(reg2, DataLayout::counter_increment); set_mdp_data_at(mdp, count_offset, reg2); - jmp(done); + if (start_row > 0) { + jmp(done); + } } // Example state machine code for three profile rows: @@ -1368,7 +1385,7 @@ // if (row[1].rec != NULL) { // // degenerate decision tree, rooted at row[2] // if (row[2].rec == rec) { row[2].incr(); goto done; } -// if (row[2].rec != NULL) { goto done; } // overflow +// if (row[2].rec != NULL) { count.incr(); goto done; } // overflow // row[2].init(rec); goto done; // } else { // // remember row[1] is empty @@ -1381,14 +1398,15 @@ // if (row[2].rec == rec) { row[2].incr(); goto done; } // row[0].init(rec); goto done; // } +// done: void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, - Register mdp, - Register reg2) { + Register mdp, Register reg2, + bool is_virtual_call) { assert(ProfileInterpreter, "must be profiling"); Label done; - record_klass_in_profile_helper(receiver, mdp, reg2, 0, done); + record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call); bind (done); } @@ -1484,7 +1502,7 @@ mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); // Record the object type. - record_klass_in_profile(klass, mdp, reg2); + record_klass_in_profile(klass, mdp, reg2, false); } update_mdp_by_constant(mdp, mdp_delta); diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/cpu/x86/vm/interp_masm_x86_64.hpp --- a/src/cpu/x86/vm/interp_masm_x86_64.hpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp Mon Feb 01 16:49:49 2010 -0800 @@ -222,10 +222,10 @@ Label& not_equal_continue); void record_klass_in_profile(Register receiver, Register mdp, - Register reg2); + Register reg2, bool is_virtual_call); void record_klass_in_profile_helper(Register receiver, Register mdp, - Register reg2, - int start_row, Label& done); + Register reg2, int start_row, + Label& done, bool is_virtual_call); void update_mdp_by_offset(Register mdp_in, int offset_of_offset); void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/share/vm/ci/ciMethod.cpp Mon Feb 01 16:49:49 2010 -0800 @@ -436,15 +436,20 @@ // we will set result._method also. } // Determine call site's morphism. - // The call site count could be == (receivers_count_total + 1) - // not only in the case of a polymorphic call but also in the case - // when a method data snapshot is taken after the site count was updated - // but before receivers counters were updated. - if (morphism == result._limit) { - // There were no array klasses and morphism <= MorphismLimit. - if (morphism < ciCallProfile::MorphismLimit || - morphism == ciCallProfile::MorphismLimit && - (receivers_count_total+1) >= count) { + // The call site count is 0 with known morphism (onlt 1 or 2 receivers) + // or < 0 in the case of a type check failured for checkcast, aastore, instanceof. + // The call site count is > 0 in the case of a polymorphic virtual call. + if (morphism > 0 && morphism == result._limit) { + // The morphism <= MorphismLimit. + if ((morphism < ciCallProfile::MorphismLimit) || + (morphism == ciCallProfile::MorphismLimit && count == 0)) { +#ifdef ASSERT + if (count > 0) { + tty->print_cr("bci: %d", bci); + this->print_codes(); + assert(false, "this call site should not be polymorphic"); + } +#endif result._morphism = morphism; } } @@ -452,10 +457,8 @@ // zero or less, presume that this is a typecheck profile and // do nothing. Otherwise, increase count to be the sum of all // receiver's counts. - if (count > 0) { - if (count < receivers_count_total) { - count = receivers_count_total; - } + if (count >= 0) { + count += receivers_count_total; } } result._count = count; diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/share/vm/code/dependencies.cpp --- a/src/share/vm/code/dependencies.cpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/share/vm/code/dependencies.cpp Mon Feb 01 16:49:49 2010 -0800 @@ -843,13 +843,15 @@ if (occasional_print || final_stats) { // Every now and then dump a little info about dependency searching. if (xtty != NULL) { - xtty->elem("deps_find_witness calls='%d' steps='%d' recursions='%d' singles='%d'", + ttyLocker ttyl; + xtty->elem("deps_find_witness calls='%d' steps='%d' recursions='%d' singles='%d'", deps_find_witness_calls, deps_find_witness_steps, deps_find_witness_recursions, deps_find_witness_singles); } if (final_stats || (TraceDependencies && WizardMode)) { + ttyLocker ttyl; tty->print_cr("Dependency check (find_witness) " "calls=%d, steps=%d (avg=%.1f), recursions=%d, singles=%d", deps_find_witness_calls, diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/share/vm/code/nmethod.cpp Mon Feb 01 16:49:49 2010 -0800 @@ -1117,7 +1117,6 @@ if (_method->code() == this) { _method->clear_code(); // Break a cycle } - inc_decompile_count(); // Last chance to make a mark on the MDO _method = NULL; // Clear the method of this dead nmethod } // Make the class unloaded - i.e., change state and notify sweeper @@ -1177,15 +1176,17 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { assert(state == zombie || state == not_entrant, "must be zombie or not_entrant"); - // If the method is already zombie there is nothing to do - if (is_zombie()) { - return false; - } + bool was_alive = false; // Make sure the nmethod is not flushed in case of a safepoint in code below. nmethodLocker nml(this); { + // If the method is already zombie there is nothing to do + if (is_zombie()) { + return false; + } + // invalidate osr nmethod before acquiring the patching lock since // they both acquire leaf locks and we don't want a deadlock. // This logic is equivalent to the logic below for patching the @@ -1223,6 +1224,8 @@ assert(state == not_entrant, "other cases may need to be handled differently"); } + was_alive = is_in_use(); // Read state under lock + // Change state flags.state = state; @@ -1249,8 +1252,11 @@ mark_as_seen_on_stack(); } - // It's a true state change, so mark the method as decompiled. - inc_decompile_count(); + if (was_alive) { + // It's a true state change, so mark the method as decompiled. + // Do it only for transition from alive. + inc_decompile_count(); + } // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event // and it hasn't already been reported for this nmethod then report it now. diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/share/vm/oops/methodDataOop.hpp --- a/src/share/vm/oops/methodDataOop.hpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/share/vm/oops/methodDataOop.hpp Mon Feb 01 16:49:49 2010 -0800 @@ -1391,6 +1391,9 @@ } void inc_decompile_count() { _nof_decompiles += 1; + if (decompile_count() > (uint)PerMethodRecompilationCutoff) { + method()->set_not_compilable(); + } } // Support for code generation diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/share/vm/oops/methodOop.cpp --- a/src/share/vm/oops/methodOop.cpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/share/vm/oops/methodOop.cpp Mon Feb 01 16:49:49 2010 -0800 @@ -575,12 +575,6 @@ return true; } - methodDataOop mdo = method_data(); - if (mdo != NULL - && (uint)mdo->decompile_count() > (uint)PerMethodRecompilationCutoff) { - // Since (uint)-1 is large, -1 really means 'no cutoff'. - return true; - } #ifdef COMPILER2 if (is_tier1_compile(comp_level)) { if (is_not_tier1_compilable()) { @@ -594,6 +588,15 @@ // call this when compiler finds that this method is not compilable void methodOopDesc::set_not_compilable(int comp_level) { + if (PrintCompilation) { + ttyLocker ttyl; + tty->print("made not compilable "); + this->print_short_name(tty); + int size = this->code_size(); + if (size > 0) + tty->print(" (%d bytes)", size); + tty->cr(); + } if ((TraceDeoptimization || LogCompilation) && (xtty != NULL)) { ttyLocker ttyl; xtty->begin_elem("make_not_compilable thread='%d'", (int) os::current_thread_id()); diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/share/vm/opto/doCall.cpp Mon Feb 01 16:49:49 2010 -0800 @@ -182,26 +182,16 @@ } } CallGenerator* miss_cg; + Deoptimization::DeoptReason reason = (profile.morphism() == 2) ? + Deoptimization::Reason_bimorphic : + Deoptimization::Reason_class_check; if (( profile.morphism() == 1 || (profile.morphism() == 2 && next_hit_cg != NULL) ) && - - !too_many_traps(Deoptimization::Reason_class_check) - - // Check only total number of traps per method to allow - // the transition from monomorphic to bimorphic case between - // compilations without falling into virtual call. - // A monomorphic case may have the class_check trap flag is set - // due to the time gap between the uncommon trap processing - // when flags are set in MDO and the call site bytecode execution - // in Interpreter when MDO counters are updated. - // There was also class_check trap in monomorphic case due to - // the bug 6225440. - + !too_many_traps(jvms->method(), jvms->bci(), reason) ) { // Generate uncommon trap for class check failure path // in case of monomorphic or bimorphic virtual call site. - miss_cg = CallGenerator::for_uncommon_trap(call_method, - Deoptimization::Reason_class_check, + miss_cg = CallGenerator::for_uncommon_trap(call_method, reason, Deoptimization::Action_maybe_recompile); } else { // Generate virtual call for class check failure path diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/share/vm/opto/parseHelper.cpp --- a/src/share/vm/opto/parseHelper.cpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/share/vm/opto/parseHelper.cpp Mon Feb 01 16:49:49 2010 -0800 @@ -414,8 +414,6 @@ void Parse::profile_call(Node* receiver) { if (!method_data_update()) return; - profile_generic_call(); - switch (bc()) { case Bytecodes::_invokevirtual: case Bytecodes::_invokeinterface: @@ -424,6 +422,7 @@ case Bytecodes::_invokestatic: case Bytecodes::_invokedynamic: case Bytecodes::_invokespecial: + profile_generic_call(); break; default: fatal("unexpected call bytecode"); } @@ -444,13 +443,16 @@ void Parse::profile_receiver_type(Node* receiver) { assert(method_data_update(), "must be generating profile code"); - // Skip if we aren't tracking receivers - if (TypeProfileWidth < 1) return; - ciMethodData* md = method()->method_data(); assert(md != NULL, "expected valid ciMethodData"); ciProfileData* data = md->bci_to_data(bci()); assert(data->is_ReceiverTypeData(), "need ReceiverTypeData here"); + + // Skip if we aren't tracking receivers + if (TypeProfileWidth < 1) { + increment_md_counter_at(md, data, CounterData::count_offset()); + return; + } ciReceiverTypeData* rdata = (ciReceiverTypeData*)data->as_ReceiverTypeData(); Node* method_data = method_data_addressing(md, rdata, in_ByteSize(0)); diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/share/vm/opto/runtime.cpp --- a/src/share/vm/opto/runtime.cpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/share/vm/opto/runtime.cpp Mon Feb 01 16:49:49 2010 -0800 @@ -706,6 +706,11 @@ // vc->set_receiver_count(empty_row, DataLayout::counter_increment); int count_off = ReceiverTypeData::receiver_count_cell_index(empty_row); *(mdp + count_off) = DataLayout::counter_increment; + } else { + // Receiver did not match any saved receiver and there is no empty row for it. + // Increment total counter to indicate polimorphic case. + intptr_t* count_p = (intptr_t*)(((byte*)(data)) + in_bytes(CounterData::count_offset())); + *count_p += DataLayout::counter_increment; } JRT_END diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/share/vm/runtime/deoptimization.cpp Mon Feb 01 16:49:49 2010 -0800 @@ -1338,13 +1338,14 @@ // Whether the interpreter is producing MDO data or not, we also need // to use the MDO to detect hot deoptimization points and control // aggressive optimization. + bool inc_recompile_count = false; + ProfileData* pdata = NULL; if (ProfileTraps && update_trap_state && trap_mdo.not_null()) { assert(trap_mdo() == get_method_data(thread, trap_method, false), "sanity"); uint this_trap_count = 0; bool maybe_prior_trap = false; bool maybe_prior_recompile = false; - ProfileData* pdata - = query_update_method_data(trap_mdo, trap_bci, reason, + pdata = query_update_method_data(trap_mdo, trap_bci, reason, //outputs: this_trap_count, maybe_prior_trap, @@ -1380,18 +1381,7 @@ // Detect repeated recompilation at the same BCI, and enforce a limit. if (make_not_entrant && maybe_prior_recompile) { // More than one recompile at this point. - trap_mdo->inc_overflow_recompile_count(); - if (maybe_prior_trap - && ((uint)trap_mdo->overflow_recompile_count() - > (uint)PerBytecodeRecompilationCutoff)) { - // Give up on the method containing the bad BCI. - if (trap_method() == nm->method()) { - make_not_compilable = true; - } else { - trap_method->set_not_compilable(); - // But give grace to the enclosing nm->method(). - } - } + inc_recompile_count = maybe_prior_trap; } } else { // For reasons which are not recorded per-bytecode, we simply @@ -1418,7 +1408,17 @@ reset_counters = true; } - if (make_not_entrant && pdata != NULL) { + } + + // Take requested actions on the method: + + // Recompile + if (make_not_entrant) { + if (!nm->make_not_entrant()) { + return; // the call did not change nmethod's state + } + + if (pdata != NULL) { // Record the recompilation event, if any. int tstate0 = pdata->trap_state(); int tstate1 = trap_state_set_recompiled(tstate0, true); @@ -1427,7 +1427,19 @@ } } - // Take requested actions on the method: + if (inc_recompile_count) { + trap_mdo->inc_overflow_recompile_count(); + if ((uint)trap_mdo->overflow_recompile_count() > + (uint)PerBytecodeRecompilationCutoff) { + // Give up on the method containing the bad BCI. + if (trap_method() == nm->method()) { + make_not_compilable = true; + } else { + trap_method->set_not_compilable(); + // But give grace to the enclosing nm->method(). + } + } + } // Reset invocation counters if (reset_counters) { @@ -1437,13 +1449,8 @@ reset_invocation_counter(trap_scope); } - // Recompile - if (make_not_entrant) { - nm->make_not_entrant(); - } - // Give up compiling - if (make_not_compilable) { + if (make_not_compilable && !nm->method()->is_not_compilable()) { assert(make_not_entrant, "consistent"); nm->method()->set_not_compilable(); } @@ -1516,9 +1523,11 @@ if (tstate1 != tstate0) pdata->set_trap_state(tstate1); } else { - if (LogCompilation && xtty != NULL) + if (LogCompilation && xtty != NULL) { + ttyLocker ttyl; // Missing MDP? Leave a small complaint in the log. xtty->elem("missing_mdp bci='%d'", trap_bci); + } } } @@ -1672,6 +1681,7 @@ "class_check", "array_check", "intrinsic", + "bimorphic", "unloaded", "uninitialized", "unreached", diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/share/vm/runtime/deoptimization.hpp --- a/src/share/vm/runtime/deoptimization.hpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/share/vm/runtime/deoptimization.hpp Mon Feb 01 16:49:49 2010 -0800 @@ -33,12 +33,15 @@ enum DeoptReason { Reason_many = -1, // indicates presence of several reasons Reason_none = 0, // indicates absence of a relevant deopt. + // Next 7 reasons are recorded per bytecode in DataLayout::trap_bits Reason_null_check, // saw unexpected null or zero divisor (@bci) Reason_null_assert, // saw unexpected non-null or non-zero (@bci) Reason_range_check, // saw unexpected array index (@bci) Reason_class_check, // saw unexpected object class (@bci) Reason_array_check, // saw unexpected array class (aastore @bci) Reason_intrinsic, // saw unexpected operand to intrinsic (@bci) + Reason_bimorphic, // saw unexpected object class in bimorphic inlining (@bci) + Reason_unloaded, // unloaded class or constant pool entry Reason_uninitialized, // bad class state (uninitialized) Reason_unreached, // code is not reached, compiler @@ -49,7 +52,7 @@ Reason_predicate, // compiler generated predicate failed Reason_LIMIT, // Note: Keep this enum in sync. with _trap_reason_name. - Reason_RECORDED_LIMIT = Reason_unloaded // some are not recorded per bc + Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc // Note: Reason_RECORDED_LIMIT should be < 8 to fit into 3 bits of // DataLayout::trap_bits. This dependency is enforced indirectly // via asserts, to avoid excessive direct header-to-header dependencies. @@ -279,7 +282,7 @@ int trap_state); static bool reason_is_recorded_per_bytecode(DeoptReason reason) { - return reason > Reason_none && reason < Reason_RECORDED_LIMIT; + return reason > Reason_none && reason <= Reason_RECORDED_LIMIT; } static DeoptReason reason_recorded_per_bytecode_if_any(DeoptReason reason) { diff -r 5fcfaa1ad96f -r 87684f1a88b5 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Mon Feb 01 23:18:47 2010 +0100 +++ b/src/share/vm/runtime/globals.hpp Mon Feb 01 16:49:49 2010 -0800 @@ -2864,7 +2864,7 @@ product(intx, PerMethodRecompilationCutoff, 400, \ "After recompiling N times, stay in the interpreter (-1=>'Inf')") \ \ - product(intx, PerBytecodeRecompilationCutoff, 100, \ + product(intx, PerBytecodeRecompilationCutoff, 200, \ "Per-BCI limit on repeated recompilation (-1=>'Inf')") \ \ product(intx, PerMethodTrapLimit, 100, \