--- /dev/null 2019-01-28 17:46:07.000000000 +0800 +++ new/src/share/vm/jfr/leakprofiler/checkpoint/rootResolver.cpp 2019-01-28 17:46:07.000000000 +0800 @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "jfr/leakprofiler/utilities/unifiedOop.hpp" +#include "jfr/leakprofiler/checkpoint/rootResolver.hpp" +#include "memory/iterator.hpp" +#include "oops/klass.hpp" +#include "oops/markOop.hpp" +#include "oops/oop.hpp" +#include "prims/jvmtiThreadState.hpp" +#include "prims/privilegedStack.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/vframe_hp.hpp" +#include "services/management.hpp" +#include "utilities/growableArray.hpp" + +class ReferenceLocateClosure : public OopClosure { + protected: + RootCallback& _callback; + RootCallbackInfo _info; + bool _complete; + + void do_oop_shared(const void* ref); + + public: + ReferenceLocateClosure(RootCallback& callback, + OldObjectRoot::System system, + OldObjectRoot::Type type, + const void* context) : _callback(callback), + _info(), + _complete(false) { + _info._high = NULL; + _info._low = NULL; + _info._system = system; + _info._type = type; + _info._context = context; + } + + virtual void do_oop(oop* ref); + virtual void do_oop(narrowOop* ref); + + bool complete() const { + return _complete; + } +}; + +void ReferenceLocateClosure::do_oop_shared(const void* ref) { + assert(ref != NULL, "invariant"); + if (!_complete) { + _info._high = ref; + _complete = _callback.process(_info); + } +} + +void ReferenceLocateClosure::do_oop(oop* ref) { + do_oop_shared(ref); +} + +void ReferenceLocateClosure::do_oop(narrowOop* ref) { + do_oop_shared(ref); +} + +class ReferenceToRootClosure : public StackObj { + private: + RootCallback& _callback; + RootCallbackInfo _info; + bool _complete; + + bool do_cldg_roots(); + bool do_object_synchronizer_roots(); + bool do_universe_roots(); + bool do_jni_handle_roots(); + bool do_jvmti_roots(); + bool do_system_dictionary_roots(); + bool do_management_roots(); + bool do_string_table_roots(); + + bool do_roots(); + + public: + ReferenceToRootClosure(RootCallback& callback) : _callback(callback), + _info(), + _complete(false) { + _info._high = NULL; + _info._low = NULL; + _info._context = NULL; + _info._system = OldObjectRoot::_system_undetermined; + _info._type = OldObjectRoot::_type_undetermined; + + assert_locked_or_safepoint(Threads_lock); + do_roots(); + } + + bool complete() const { + return _complete; + } +}; + +bool ReferenceToRootClosure::do_cldg_roots() { + assert(!complete(), "invariant"); + ReferenceLocateClosure rlc(_callback, OldObjectRoot::_class_loader_data, OldObjectRoot::_type_undetermined, NULL); + CLDToOopClosure cldt_closure(&rlc); + ClassLoaderDataGraph::always_strong_cld_do(&cldt_closure); + return rlc.complete(); +} + +bool ReferenceToRootClosure::do_object_synchronizer_roots() { + assert(!complete(), "invariant"); + ReferenceLocateClosure rlc(_callback, OldObjectRoot::_object_synchronizer, OldObjectRoot::_type_undetermined, NULL); + ObjectSynchronizer::oops_do(&rlc); + return rlc.complete(); +} + +bool ReferenceToRootClosure::do_universe_roots() { + assert(!complete(), "invariant"); + ReferenceLocateClosure rlc(_callback, OldObjectRoot::_universe, OldObjectRoot::_type_undetermined, NULL); + Universe::oops_do(&rlc); + return rlc.complete(); +} + +bool ReferenceToRootClosure::do_jni_handle_roots() { + assert(!complete(), "invariant"); + ReferenceLocateClosure rlc(_callback, OldObjectRoot::_global_jni_handles, OldObjectRoot::_global_jni_handle, NULL); + JNIHandles::oops_do(&rlc); + return rlc.complete(); +} + +bool ReferenceToRootClosure::do_jvmti_roots() { + assert(!complete(), "invariant"); + ReferenceLocateClosure rlc(_callback, OldObjectRoot::_jvmti, OldObjectRoot::_global_jni_handle, NULL); + JvmtiExport::oops_do(&rlc); + return rlc.complete(); +} + +bool ReferenceToRootClosure::do_system_dictionary_roots() { + assert(!complete(), "invariant"); + ReferenceLocateClosure rlc(_callback, OldObjectRoot::_system_dictionary, OldObjectRoot::_type_undetermined, NULL); + SystemDictionary::oops_do(&rlc); + return rlc.complete(); +} + +bool ReferenceToRootClosure::do_management_roots() { + assert(!complete(), "invariant"); + ReferenceLocateClosure rlc(_callback, OldObjectRoot::_management, OldObjectRoot::_type_undetermined, NULL); + Management::oops_do(&rlc); + return rlc.complete(); +} + +bool ReferenceToRootClosure::do_string_table_roots() { + assert(!complete(), "invariant"); + ReferenceLocateClosure rlc(_callback, OldObjectRoot::_string_table, OldObjectRoot::_type_undetermined, NULL); + StringTable::oops_do(&rlc); + return rlc.complete(); +} + + +bool ReferenceToRootClosure::do_roots() { + assert(!complete(), "invariant"); + assert(OldObjectRoot::_system_undetermined == _info._system, "invariant"); + assert(OldObjectRoot::_type_undetermined == _info._type, "invariant"); + + if (do_cldg_roots()) { + _complete = true; + return true; + } + + if (do_object_synchronizer_roots()) { + _complete = true; + return true; + } + + if (do_universe_roots()) { + _complete = true; + return true; + } + + if (do_jni_handle_roots()) { + _complete = true; + return true; + } + + if (do_jvmti_roots()) { + _complete = true; + return true; + } + + if (do_system_dictionary_roots()) { + _complete = true; + return true; + } + + if (do_management_roots()) { + _complete = true; + return true; + } + + if (do_string_table_roots()) { + _complete = true; + return true; + } + + + return false; +} + +class ReferenceToThreadRootClosure : public StackObj { + private: + RootCallback& _callback; + bool _complete; + + bool do_java_threads_oops(JavaThread* jt); + bool do_thread_roots(JavaThread* jt); + bool do_thread_stack_fast(JavaThread* jt); + bool do_thread_stack_detailed(JavaThread* jt); + bool do_thread_jni_handles(JavaThread* jt); + bool do_thread_handle_area(JavaThread* jt); + + public: + ReferenceToThreadRootClosure(RootCallback& callback) :_callback(callback), _complete(false) { + assert_locked_or_safepoint(Threads_lock); + JavaThread *jt = Threads::first(); + while (jt) { + if (do_thread_roots(jt)) { + return; + } + + jt = jt->next(); + } + } + + bool complete() const { + return _complete; + } +}; + +bool ReferenceToThreadRootClosure::do_thread_handle_area(JavaThread* jt) { + assert(jt != NULL, "invariant"); + assert(!complete(), "invariant"); + ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_handle_area, jt); + jt->handle_area()->oops_do(&rcl); + return rcl.complete(); +} + +bool ReferenceToThreadRootClosure::do_thread_jni_handles(JavaThread* jt) { + assert(jt != NULL, "invariant"); + assert(!complete(), "invariant"); + + ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_local_jni_handle, jt); + jt->active_handles()->oops_do(&rcl); + return rcl.complete(); +} + +bool ReferenceToThreadRootClosure::do_thread_stack_fast(JavaThread* jt) { + assert(jt != NULL, "invariant"); + assert(!complete(), "invariant"); + + if (_callback.entries() == 0) { + _complete = true; + return true; + } + + RootCallbackInfo info; + info._high = NULL; + info._low = NULL; + info._context = jt; + info._system = OldObjectRoot::_threads; + info._type = OldObjectRoot::_stack_variable; + + for (int i = 0; i < _callback.entries(); ++i) { + const address adr = (address)_callback.at(i); + if (jt->is_in_usable_stack(adr)) { + info._high = adr; + _complete = _callback.process(info); + if (_complete) { + return true; + } + } + } + assert(!complete(), "invariant"); + return false; +} + +bool ReferenceToThreadRootClosure::do_thread_stack_detailed(JavaThread* jt) { + assert(jt != NULL, "invariant"); + assert(!complete(), "invariant"); + + ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_stack_variable, jt); + + if (jt->has_last_Java_frame()) { + PrivilegedElement* const pelem = jt->privileged_stack_top(); + if (pelem != NULL) { + pelem->oops_do(&rcl); + if (rcl.complete()) { + return true; + } + } + + // traverse the registered growable array gc_array + // can't do this as it is not reachable from outside + + // Traverse the monitor chunks + MonitorChunk* chunk = jt->monitor_chunks(); + for (; chunk != NULL; chunk = chunk->next()) { + chunk->oops_do(&rcl); + } + + if (rcl.complete()) { + return true; + } + + // Traverse the execution stack + for (StackFrameStream fst(jt); !fst.is_done(); fst.next()) { + fst.current()->oops_do(&rcl, NULL, NULL, fst.register_map()); + } + + } // last java frame + + if (rcl.complete()) { + return true; + } + + GrowableArray* const list = jt->deferred_locals(); + if (list != NULL) { + for (int i = 0; i < list->length(); i++) { + list->at(i)->oops_do(&rcl); + } + } + + if (rcl.complete()) { + return true; + } + + // Traverse instance variables at the end since the GC may be moving things + // around using this function + /* + * // can't reach these oop* from the outside + f->do_oop((oop*) &_threadObj); + f->do_oop((oop*) &_vm_result); + f->do_oop((oop*) &_exception_oop); + f->do_oop((oop*) &_pending_async_exception); + */ + + JvmtiThreadState* const jvmti_thread_state = jt->jvmti_thread_state(); + if (jvmti_thread_state != NULL) { + jvmti_thread_state->oops_do(&rcl); + } + + return rcl.complete(); +} + +bool ReferenceToThreadRootClosure::do_java_threads_oops(JavaThread* jt) { + assert(jt != NULL, "invariant"); + assert(!complete(), "invariant"); + + ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_global_jni_handle, jt); + jt->oops_do(&rcl, NULL, NULL); + return rcl.complete(); +} + +bool ReferenceToThreadRootClosure::do_thread_roots(JavaThread* jt) { + assert(jt != NULL, "invariant"); + + if (do_thread_stack_fast(jt)) { + _complete = true; + return true; + } + + if (do_thread_jni_handles(jt)) { + _complete = true; + return true; + } + + if (do_thread_handle_area(jt)) { + _complete = true; + return true; + } + + if (do_thread_stack_detailed(jt)) { + _complete = true; + return true; + } + + return false; +} + +class RootResolverMarkScope : public MarkingCodeBlobClosure::MarkScope { +}; + +void RootResolver::resolve(RootCallback& callback) { + + // Need to clear cld claim bit before starting + ClassLoaderDataGraph::clear_claimed_marks(); + RootResolverMarkScope mark_scope; + + // thread local roots + ReferenceToThreadRootClosure rtrc(callback); + if (rtrc.complete()) { + return; + } + // system global roots + ReferenceToRootClosure rrc(callback); +}