/* * Copyright (c) 2014, 2018, 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 "classfile/stringTable.hpp" //#include "gc_interface/strongRootsScope.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_aot_loader_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_aot_loader_roots() { // assert(!complete(), "invariant"); // ReferenceLocateClosure rcl(_callback, OldObjectRoot::_aot, OldObjectRoot::_type_undetermined, NULL); // AOTLoader::oops_do(&rcl); // return rcl.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; } // if (do_aot_loader_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); for (JavaThread *thread = Threads::first(); thread != NULL; thread = thread->next()) { if (do_thread_roots(thread)) { return; } } } 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()) { // XXX set CLDClosure to NULL 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); }