Wed, 16 Dec 2009 22:15:12 -0800
5057818: codecache full and compiler disabled in bigapps fastdebug run
Reviewed-by: kvn
src/share/vm/code/nmethod.cpp | file | annotate | diff | comparison | revisions | |
src/share/vm/code/nmethod.hpp | file | annotate | diff | comparison | revisions |
1.1 --- a/src/share/vm/code/nmethod.cpp Wed Dec 16 12:48:04 2009 +0100 1.2 +++ b/src/share/vm/code/nmethod.cpp Wed Dec 16 22:15:12 2009 -0800 1.3 @@ -414,9 +414,8 @@ 1.4 } 1.5 1.6 const char* nmethod::compile_kind() const { 1.7 - if (method() == NULL) return "unloaded"; 1.8 - if (is_native_method()) return "c2n"; 1.9 if (is_osr_method()) return "osr"; 1.10 + if (method() != NULL && is_native_method()) return "c2n"; 1.11 return NULL; 1.12 } 1.13 1.14 @@ -1127,6 +1126,9 @@ 1.15 } 1.16 flags.state = unloaded; 1.17 1.18 + // Log the unloading. 1.19 + log_state_change(); 1.20 + 1.21 // The methodOop is gone at this point 1.22 assert(_method == NULL, "Tautology"); 1.23 1.24 @@ -1137,8 +1139,6 @@ 1.25 1.26 void nmethod::invalidate_osr_method() { 1.27 assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); 1.28 - if (_entry_bci != InvalidOSREntryBci) 1.29 - inc_decompile_count(); 1.30 // Remove from list of active nmethods 1.31 if (method() != NULL) 1.32 instanceKlass::cast(method()->method_holder())->remove_osr_nmethod(this); 1.33 @@ -1146,59 +1146,63 @@ 1.34 _entry_bci = InvalidOSREntryBci; 1.35 } 1.36 1.37 -void nmethod::log_state_change(int state) const { 1.38 +void nmethod::log_state_change() const { 1.39 if (LogCompilation) { 1.40 if (xtty != NULL) { 1.41 ttyLocker ttyl; // keep the following output all in one block 1.42 - xtty->begin_elem("make_not_entrant %sthread='" UINTX_FORMAT "'", 1.43 - (state == zombie ? "zombie='1' " : ""), 1.44 - os::current_thread_id()); 1.45 + if (flags.state == unloaded) { 1.46 + xtty->begin_elem("make_unloaded thread='" UINTX_FORMAT "'", 1.47 + os::current_thread_id()); 1.48 + } else { 1.49 + xtty->begin_elem("make_not_entrant thread='" UINTX_FORMAT "'%s", 1.50 + os::current_thread_id(), 1.51 + (flags.state == zombie ? " zombie='1'" : "")); 1.52 + } 1.53 log_identity(xtty); 1.54 xtty->stamp(); 1.55 xtty->end_elem(); 1.56 } 1.57 } 1.58 - if (PrintCompilation) { 1.59 - print_on(tty, state == zombie ? "made zombie " : "made not entrant "); 1.60 + if (PrintCompilation && flags.state != unloaded) { 1.61 + print_on(tty, flags.state == zombie ? "made zombie " : "made not entrant "); 1.62 tty->cr(); 1.63 } 1.64 } 1.65 1.66 // Common functionality for both make_not_entrant and make_zombie 1.67 -void nmethod::make_not_entrant_or_zombie(int state) { 1.68 +bool nmethod::make_not_entrant_or_zombie(int state) { 1.69 assert(state == zombie || state == not_entrant, "must be zombie or not_entrant"); 1.70 1.71 - // Code for an on-stack-replacement nmethod is removed when a class gets unloaded. 1.72 - // They never become zombie/non-entrant, so the nmethod sweeper will never remove 1.73 - // them. Instead the entry_bci is set to InvalidOSREntryBci, so the osr nmethod 1.74 - // will never be used anymore. That the nmethods only gets removed when class unloading 1.75 - // happens, make life much simpler, since the nmethods are not just going to disappear 1.76 - // out of the blue. 1.77 - if (is_osr_method()) { 1.78 - if (osr_entry_bci() != InvalidOSREntryBci) { 1.79 - // only log this once 1.80 - log_state_change(state); 1.81 - } 1.82 - invalidate_osr_method(); 1.83 - return; 1.84 + // If the method is already zombie there is nothing to do 1.85 + if (is_zombie()) { 1.86 + return false; 1.87 } 1.88 1.89 - // If the method is already zombie or set to the state we want, nothing to do 1.90 - if (is_zombie() || (state == not_entrant && is_not_entrant())) { 1.91 - return; 1.92 - } 1.93 - 1.94 - log_state_change(state); 1.95 - 1.96 // Make sure the nmethod is not flushed in case of a safepoint in code below. 1.97 nmethodLocker nml(this); 1.98 1.99 { 1.100 + // invalidate osr nmethod before acquiring the patching lock since 1.101 + // they both acquire leaf locks and we don't want a deadlock. 1.102 + // This logic is equivalent to the logic below for patching the 1.103 + // verified entry point of regular methods. 1.104 + if (is_osr_method()) { 1.105 + // this effectively makes the osr nmethod not entrant 1.106 + invalidate_osr_method(); 1.107 + } 1.108 + 1.109 // Enter critical section. Does not block for safepoint. 1.110 MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag); 1.111 + 1.112 + if (flags.state == state) { 1.113 + // another thread already performed this transition so nothing 1.114 + // to do, but return false to indicate this. 1.115 + return false; 1.116 + } 1.117 + 1.118 // The caller can be calling the method statically or through an inline 1.119 // cache call. 1.120 - if (!is_not_entrant()) { 1.121 + if (!is_osr_method() && !is_not_entrant()) { 1.122 NativeJump::patch_verified_entry(entry_point(), verified_entry_point(), 1.123 SharedRuntime::get_handle_wrong_method_stub()); 1.124 assert (NativeJump::instruction_size == nmethod::_zombie_instruction_size, ""); 1.125 @@ -1217,6 +1221,10 @@ 1.126 1.127 // Change state 1.128 flags.state = state; 1.129 + 1.130 + // Log the transition once 1.131 + log_state_change(); 1.132 + 1.133 } // leave critical region under Patching_lock 1.134 1.135 if (state == not_entrant) { 1.136 @@ -1240,7 +1248,6 @@ 1.137 // It's a true state change, so mark the method as decompiled. 1.138 inc_decompile_count(); 1.139 1.140 - 1.141 // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event 1.142 // and it hasn't already been reported for this nmethod then report it now. 1.143 // (the event may have been reported earilier if the GC marked it for unloading). 1.144 @@ -1268,7 +1275,7 @@ 1.145 1.146 // Check whether method got unloaded at a safepoint before this, 1.147 // if so we can skip the flushing steps below 1.148 - if (method() == NULL) return; 1.149 + if (method() == NULL) return true; 1.150 1.151 // Remove nmethod from method. 1.152 // We need to check if both the _code and _from_compiled_code_entry_point 1.153 @@ -1282,6 +1289,8 @@ 1.154 HandleMark hm; 1.155 method()->clear_code(); 1.156 } 1.157 + 1.158 + return true; 1.159 } 1.160 1.161
2.1 --- a/src/share/vm/code/nmethod.hpp Wed Dec 16 12:48:04 2009 +0100 2.2 +++ b/src/share/vm/code/nmethod.hpp Wed Dec 16 22:15:12 2009 -0800 2.3 @@ -252,7 +252,9 @@ 2.4 void* operator new(size_t size, int nmethod_size); 2.5 2.6 const char* reloc_string_for(u_char* begin, u_char* end); 2.7 - void make_not_entrant_or_zombie(int state); 2.8 + // Returns true if this thread changed the state of the nmethod or 2.9 + // false if another thread performed the transition. 2.10 + bool make_not_entrant_or_zombie(int state); 2.11 void inc_decompile_count(); 2.12 2.13 // used to check that writes to nmFlags are done consistently. 2.14 @@ -375,10 +377,12 @@ 2.15 bool is_zombie() const { return flags.state == zombie; } 2.16 bool is_unloaded() const { return flags.state == unloaded; } 2.17 2.18 - // Make the nmethod non entrant. The nmethod will continue to be alive. 2.19 - // It is used when an uncommon trap happens. 2.20 - void make_not_entrant() { make_not_entrant_or_zombie(not_entrant); } 2.21 - void make_zombie() { make_not_entrant_or_zombie(zombie); } 2.22 + // Make the nmethod non entrant. The nmethod will continue to be 2.23 + // alive. It is used when an uncommon trap happens. Returns true 2.24 + // if this thread changed the state of the nmethod or false if 2.25 + // another thread performed the transition. 2.26 + bool make_not_entrant() { return make_not_entrant_or_zombie(not_entrant); } 2.27 + bool make_zombie() { return make_not_entrant_or_zombie(zombie); } 2.28 2.29 // used by jvmti to track if the unload event has been reported 2.30 bool unload_reported() { return _unload_reported; } 2.31 @@ -563,7 +567,7 @@ 2.32 // Logging 2.33 void log_identity(xmlStream* log) const; 2.34 void log_new_nmethod() const; 2.35 - void log_state_change(int state) const; 2.36 + void log_state_change() const; 2.37 2.38 // Prints a comment for one native instruction (reloc info, pc desc) 2.39 void print_code_comment_on(outputStream* st, int column, address begin, address end);