diff -r d6dc479bcdd3 -r 5c679ec60888 src/hotspot/share/code/nmethod.cpp --- a/src/hotspot/share/code/nmethod.cpp Thu Nov 01 14:57:26 2018 +0100 +++ b/src/hotspot/share/code/nmethod.cpp Fri Nov 02 08:33:59 2018 +0100 @@ -413,7 +413,6 @@ _oops_do_mark_link = NULL; _jmethod_id = NULL; _osr_link = NULL; - _unloading_next = NULL; _scavenge_root_link = NULL; _scavenge_root_state = 0; #if INCLUDE_RTM_OPT @@ -599,6 +598,7 @@ code_buffer->copy_code_and_locs_to(this); code_buffer->copy_values_to(this); + if (ScavengeRootsInCode) { Universe::heap()->register_nmethod(this); } @@ -757,6 +757,7 @@ code_buffer->copy_values_to(this); debug_info->copy_to(this); dependencies->copy_to(this); + clear_unloading_state(); if (ScavengeRootsInCode) { Universe::heap()->register_nmethod(this); } @@ -1025,8 +1026,7 @@ mdo->inc_decompile_count(); } -void nmethod::make_unloaded(oop cause) { - +void nmethod::make_unloaded() { post_compiled_method_unload(); // This nmethod is being unloaded, make sure that dependencies @@ -1042,11 +1042,8 @@ LogStream ls(lt); ls.print("making nmethod " INTPTR_FORMAT " unloadable, Method*(" INTPTR_FORMAT - "), cause(" INTPTR_FORMAT ") ", - p2i(this), p2i(_method), p2i(cause)); - if (cause != NULL) { - cause->print_value_on(&ls); - } + ") ", + p2i(this), p2i(_method)); ls.cr(); } // Unlink the osr method, so we do not look this up again @@ -1079,12 +1076,6 @@ // Make the class unloaded - i.e., change state and notify sweeper assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - if (is_in_use()) { - // Transitioning directly from live to unloaded -- so - // we need to force a cache clean-up; remember this - // for later on. - CodeCache::set_needs_cache_clean(true); - } // Unregister must be done before the state change Universe::heap()->unregister_nmethod(this); @@ -1092,7 +1083,7 @@ _state = unloaded; // Log the unloading. - log_state_change(cause); + log_state_change(); #if INCLUDE_JVMCI // The method can only be unloaded after the pointer to the installed code @@ -1116,7 +1107,7 @@ } } -void nmethod::log_state_change(oop cause) const { +void nmethod::log_state_change() const { if (LogCompilation) { if (xtty != NULL) { ttyLocker ttyl; // keep the following output all in one block @@ -1129,9 +1120,6 @@ (_state == zombie ? " zombie='1'" : "")); } log_identity(xtty); - if (cause != NULL) { - xtty->print(" cause='%s'", cause->klass()->external_name()); - } xtty->stamp(); xtty->end_elem(); } @@ -1380,21 +1368,6 @@ } } - -// If this oop is not live, the nmethod can be unloaded. -bool nmethod::can_unload(BoolObjectClosure* is_alive, oop* root) { - assert(root != NULL, "just checking"); - oop obj = *root; - if (obj == NULL || is_alive->do_object_b(obj)) { - return false; - } - - // An nmethod might be unloaded simply because one of its constant oops has gone dead. - // No actual classes need to be unloaded in order for this to occur. - make_unloaded(obj); - return true; -} - // ------------------------------------------------------------------ // post_compiled_method_load_event // new method for install_code() path @@ -1468,70 +1441,6 @@ set_unload_reported(); } -bool nmethod::unload_if_dead_at(RelocIterator* iter_at_oop, BoolObjectClosure *is_alive) { - assert(iter_at_oop->type() == relocInfo::oop_type, "Wrong relocation type"); - - oop_Relocation* r = iter_at_oop->oop_reloc(); - // Traverse those oops directly embedded in the code. - // Other oops (oop_index>0) are seen as part of scopes_oops. - assert(1 == (r->oop_is_immediate()) + - (r->oop_addr() >= oops_begin() && r->oop_addr() < oops_end()), - "oop must be found in exactly one place"); - if (r->oop_is_immediate() && r->oop_value() != NULL) { - // Unload this nmethod if the oop is dead. - if (can_unload(is_alive, r->oop_addr())) { - return true;; - } - } - - return false; -} - -bool nmethod::do_unloading_scopes(BoolObjectClosure* is_alive) { - // Scopes - for (oop* p = oops_begin(); p < oops_end(); p++) { - if (*p == Universe::non_oop_word()) continue; // skip non-oops - if (can_unload(is_alive, p)) { - return true; - } - } - return false; -} - -bool nmethod::do_unloading_oops(address low_boundary, BoolObjectClosure* is_alive) { - // Compiled code - - // Prevent extra code cache walk for platforms that don't have immediate oops. - if (relocInfo::mustIterateImmediateOopsInCode()) { - RelocIterator iter(this, low_boundary); - while (iter.next()) { - if (iter.type() == relocInfo::oop_type) { - if (unload_if_dead_at(&iter, is_alive)) { - return true; - } - } - } - } - - return do_unloading_scopes(is_alive); -} - -#if INCLUDE_JVMCI -bool nmethod::do_unloading_jvmci() { - if (_jvmci_installed_code != NULL) { - if (JNIHandles::is_global_weak_cleared(_jvmci_installed_code)) { - if (_jvmci_installed_code_triggers_invalidation) { - // The reference to the installed code has been dropped so invalidate - // this nmethod and allow the sweeper to reclaim it. - make_not_entrant(); - } - clear_jvmci_installed_code(); - } - } - return false; -} -#endif - // Iterate over metadata calling this function. Used by RedefineClasses void nmethod::metadata_do(void f(Metadata*)) { { @@ -1579,6 +1488,34 @@ if (_method != NULL) f(_method); } + +// This is called at the end of the strong tracing/marking phase of a +// GC to unload an nmethod if it contains otherwise unreachable +// oops. + +void nmethod::do_unloading(bool unloading_occurred) { + // Make sure the oop's ready to receive visitors + assert(!is_zombie() && !is_unloaded(), + "should not call follow on zombie or unloaded nmethod"); + + if (is_unloading()) { + make_unloaded(); + } else { +#if INCLUDE_JVMCI + if (_jvmci_installed_code != NULL) { + if (JNIHandles::is_global_weak_cleared(_jvmci_installed_code)) { + if (_jvmci_installed_code_triggers_invalidation) { + make_not_entrant(); + } + clear_jvmci_installed_code(); + } + } +#endif + + unload_nmethod_caches(unloading_occurred); + } +} + void nmethod::oops_do(OopClosure* f, bool allow_zombie) { // make sure the oops ready to receive visitors assert(allow_zombie || !is_zombie(), "should not call follow on zombie nmethod");