aoqi@0: /* aoqi@0: * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #include "precompiled.hpp" aoqi@0: #include "classfile/systemDictionary.hpp" aoqi@0: #include "memory/universe.inline.hpp" aoqi@0: #include "prims/jvmtiGetLoadedClasses.hpp" aoqi@0: #include "runtime/thread.hpp" aoqi@0: aoqi@0: aoqi@0: // The closure for GetLoadedClasses aoqi@0: class LoadedClassesClosure : public KlassClosure { aoqi@0: private: aoqi@0: Stack _classStack; aoqi@0: JvmtiEnv* _env; aoqi@0: aoqi@0: public: aoqi@0: LoadedClassesClosure(JvmtiEnv* env) { aoqi@0: _env = env; aoqi@0: } aoqi@0: aoqi@0: void do_klass(Klass* k) { aoqi@0: // Collect all jclasses aoqi@0: _classStack.push((jclass) _env->jni_reference(k->java_mirror())); aoqi@0: } aoqi@0: aoqi@0: int extract(jclass* result_list) { aoqi@0: // The size of the Stack will be 0 after extract, so get it here aoqi@0: int count = (int)_classStack.size(); aoqi@0: int i = count; aoqi@0: aoqi@0: // Pop all jclasses, fill backwards aoqi@0: while (!_classStack.is_empty()) { aoqi@0: result_list[--i] = _classStack.pop(); aoqi@0: } aoqi@0: aoqi@0: // Return the number of elements written aoqi@0: return count; aoqi@0: } aoqi@0: aoqi@0: // Return current size of the Stack aoqi@0: int get_count() { aoqi@0: return (int)_classStack.size(); aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: // The closure for GetClassLoaderClasses aoqi@0: class JvmtiGetLoadedClassesClosure : public StackObj { aoqi@0: // Since the SystemDictionary::classes_do callback aoqi@0: // doesn't pass a closureData pointer, aoqi@0: // we use a thread-local slot to hold a pointer to aoqi@0: // a stack allocated instance of this structure. aoqi@0: private: aoqi@0: jobject _initiatingLoader; aoqi@0: int _count; aoqi@0: Handle* _list; aoqi@0: int _index; aoqi@0: aoqi@0: private: aoqi@0: // Getting and setting the thread local pointer aoqi@0: static JvmtiGetLoadedClassesClosure* get_this() { aoqi@0: JvmtiGetLoadedClassesClosure* result = NULL; aoqi@0: JavaThread* thread = JavaThread::current(); aoqi@0: result = thread->get_jvmti_get_loaded_classes_closure(); aoqi@0: return result; aoqi@0: } aoqi@0: static void set_this(JvmtiGetLoadedClassesClosure* that) { aoqi@0: JavaThread* thread = JavaThread::current(); aoqi@0: thread->set_jvmti_get_loaded_classes_closure(that); aoqi@0: } aoqi@0: aoqi@0: public: aoqi@0: // Constructor/Destructor aoqi@0: JvmtiGetLoadedClassesClosure() { aoqi@0: JvmtiGetLoadedClassesClosure* that = get_this(); aoqi@0: assert(that == NULL, "JvmtiGetLoadedClassesClosure in use"); aoqi@0: _initiatingLoader = NULL; aoqi@0: _count = 0; aoqi@0: _list = NULL; aoqi@0: _index = 0; aoqi@0: set_this(this); aoqi@0: } aoqi@0: aoqi@0: JvmtiGetLoadedClassesClosure(jobject initiatingLoader) { aoqi@0: JvmtiGetLoadedClassesClosure* that = get_this(); aoqi@0: assert(that == NULL, "JvmtiGetLoadedClassesClosure in use"); aoqi@0: _initiatingLoader = initiatingLoader; aoqi@0: _count = 0; aoqi@0: _list = NULL; aoqi@0: _index = 0; aoqi@0: set_this(this); aoqi@0: } aoqi@0: aoqi@0: ~JvmtiGetLoadedClassesClosure() { aoqi@0: JvmtiGetLoadedClassesClosure* that = get_this(); aoqi@0: assert(that != NULL, "JvmtiGetLoadedClassesClosure not found"); aoqi@0: set_this(NULL); aoqi@0: _initiatingLoader = NULL; aoqi@0: _count = 0; aoqi@0: if (_list != NULL) { aoqi@0: FreeHeap(_list); aoqi@0: _list = NULL; aoqi@0: } aoqi@0: _index = 0; aoqi@0: } aoqi@0: aoqi@0: // Accessors. aoqi@0: jobject get_initiatingLoader() { aoqi@0: return _initiatingLoader; aoqi@0: } aoqi@0: aoqi@0: int get_count() { aoqi@0: return _count; aoqi@0: } aoqi@0: aoqi@0: void set_count(int value) { aoqi@0: _count = value; aoqi@0: } aoqi@0: aoqi@0: Handle* get_list() { aoqi@0: return _list; aoqi@0: } aoqi@0: aoqi@0: void set_list(Handle* value) { aoqi@0: _list = value; aoqi@0: } aoqi@0: aoqi@0: int get_index() { aoqi@0: return _index; aoqi@0: } aoqi@0: aoqi@0: void set_index(int value) { aoqi@0: _index = value; aoqi@0: } aoqi@0: aoqi@0: Handle get_element(int index) { aoqi@0: if ((_list != NULL) && (index < _count)) { aoqi@0: return _list[index]; aoqi@0: } else { aoqi@0: assert(false, "empty get_element"); aoqi@0: return Handle(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void set_element(int index, Handle value) { aoqi@0: if ((_list != NULL) && (index < _count)) { aoqi@0: _list[index] = value; aoqi@0: } else { aoqi@0: assert(false, "bad set_element"); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Other predicates aoqi@0: bool available() { aoqi@0: return (_list != NULL); aoqi@0: } aoqi@0: aoqi@0: #ifdef ASSERT aoqi@0: // For debugging. aoqi@0: void check(int limit) { aoqi@0: for (int i = 0; i < limit; i += 1) { aoqi@0: assert(Universe::heap()->is_in(get_element(i)()), "check fails"); aoqi@0: } aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: // Public methods that get called within the scope of the closure aoqi@0: void allocate() { aoqi@0: _list = NEW_C_HEAP_ARRAY(Handle, _count, mtInternal); aoqi@0: assert(_list != NULL, "Out of memory"); aoqi@0: if (_list == NULL) { aoqi@0: _count = 0; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void extract(JvmtiEnv *env, jclass* result) { aoqi@0: for (int index = 0; index < _count; index += 1) { aoqi@0: result[index] = (jclass) env->jni_reference(get_element(index)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: static void increment_with_loader(Klass* k, ClassLoaderData* loader_data) { aoqi@0: JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); aoqi@0: oop class_loader = loader_data->class_loader(); aoqi@0: if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) { aoqi@0: for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) { aoqi@0: that->set_count(that->get_count() + 1); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: static void prim_array_increment_with_loader(Klass* array, ClassLoaderData* loader_data) { aoqi@0: JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); aoqi@0: oop class_loader = loader_data->class_loader(); aoqi@0: if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) { aoqi@0: that->set_count(that->get_count() + 1); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: static void add_with_loader(Klass* k, ClassLoaderData* loader_data) { aoqi@0: JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); aoqi@0: if (that->available()) { aoqi@0: oop class_loader = loader_data->class_loader(); aoqi@0: if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) { aoqi@0: for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) { aoqi@0: oop mirror = l->java_mirror(); aoqi@0: that->set_element(that->get_index(), mirror); aoqi@0: that->set_index(that->get_index() + 1); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // increment the count for the given basic type array class (and any aoqi@0: // multi-dimensional arrays). For example, for [B we check for aoqi@0: // [[B, [[[B, .. and the count is incremented for each one that exists. aoqi@0: static void increment_for_basic_type_arrays(Klass* k) { aoqi@0: JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); aoqi@0: assert(that != NULL, "no JvmtiGetLoadedClassesClosure"); aoqi@0: for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) { aoqi@0: that->set_count(that->get_count() + 1); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // add the basic type array class and its multi-dimensional array classes to the list aoqi@0: static void add_for_basic_type_arrays(Klass* k) { aoqi@0: JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); aoqi@0: assert(that != NULL, "no JvmtiGetLoadedClassesClosure"); aoqi@0: assert(that->available(), "no list"); aoqi@0: for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) { aoqi@0: oop mirror = l->java_mirror(); aoqi@0: that->set_element(that->get_index(), mirror); aoqi@0: that->set_index(that->get_index() + 1); aoqi@0: } aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: aoqi@0: jvmtiError aoqi@0: JvmtiGetLoadedClasses::getLoadedClasses(JvmtiEnv *env, jint* classCountPtr, jclass** classesPtr) { aoqi@0: aoqi@0: LoadedClassesClosure closure(env); aoqi@0: { aoqi@0: // To get a consistent list of classes we need MultiArray_lock to ensure aoqi@0: // array classes aren't created. aoqi@0: MutexLocker ma(MultiArray_lock); aoqi@0: aoqi@0: // Iterate through all classes in ClassLoaderDataGraph aoqi@0: // and collect them using the LoadedClassesClosure aoqi@0: ClassLoaderDataGraph::loaded_classes_do(&closure); aoqi@0: } aoqi@0: aoqi@0: // Return results by extracting the collected contents into a list aoqi@0: // allocated via JvmtiEnv aoqi@0: jclass* result_list; aoqi@0: jvmtiError error = env->Allocate(closure.get_count() * sizeof(jclass), aoqi@0: (unsigned char**)&result_list); aoqi@0: aoqi@0: if (error == JVMTI_ERROR_NONE) { aoqi@0: int count = closure.extract(result_list); aoqi@0: *classCountPtr = count; aoqi@0: *classesPtr = result_list; aoqi@0: } aoqi@0: return error; aoqi@0: } aoqi@0: aoqi@0: jvmtiError aoqi@0: JvmtiGetLoadedClasses::getClassLoaderClasses(JvmtiEnv *env, jobject initiatingLoader, aoqi@0: jint* classCountPtr, jclass** classesPtr) { aoqi@0: // Since SystemDictionary::classes_do only takes a function pointer aoqi@0: // and doesn't call back with a closure data pointer, aoqi@0: // we can only pass static methods. aoqi@0: JvmtiGetLoadedClassesClosure closure(initiatingLoader); aoqi@0: { aoqi@0: // To get a consistent list of classes we need MultiArray_lock to ensure aoqi@0: // array classes aren't created, and SystemDictionary_lock to ensure that aoqi@0: // classes aren't added to the system dictionary, aoqi@0: MutexLocker ma(MultiArray_lock); aoqi@0: MutexLocker sd(SystemDictionary_lock); aoqi@0: // First, count the classes in the system dictionary which have this loader recorded aoqi@0: // as an initiating loader. For basic type arrays this information is not recorded aoqi@0: // so GetClassLoaderClasses will return all of the basic type arrays. This is okay aoqi@0: // because the defining loader for basic type arrays is always the boot class loader aoqi@0: // and these classes are "visible" to all loaders. aoqi@0: SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::increment_with_loader); aoqi@0: Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::increment_for_basic_type_arrays); aoqi@0: // Next, fill in the classes aoqi@0: closure.allocate(); aoqi@0: SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::add_with_loader); aoqi@0: Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::add_for_basic_type_arrays); aoqi@0: // Drop the SystemDictionary_lock, so the results could be wrong from here, aoqi@0: // but we still have a snapshot. aoqi@0: } aoqi@0: // Post results aoqi@0: jclass* result_list; aoqi@0: jvmtiError err = env->Allocate(closure.get_count() * sizeof(jclass), aoqi@0: (unsigned char**)&result_list); aoqi@0: if (err != JVMTI_ERROR_NONE) { aoqi@0: return err; aoqi@0: } aoqi@0: closure.extract(env, result_list); aoqi@0: *classCountPtr = closure.get_count(); aoqi@0: *classesPtr = result_list; aoqi@0: return JVMTI_ERROR_NONE; aoqi@0: }