2007-12-01 00:00:00 +00:00
|
|
|
/*
|
2015-02-13 14:37:35 +01:00
|
|
|
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
2007-12-01 00:00:00 +00:00
|
|
|
* 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.
|
|
|
|
*
|
2010-05-27 19:08:38 -07:00
|
|
|
* 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.
|
2007-12-01 00:00:00 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2010-11-23 13:22:55 -08:00
|
|
|
#include "precompiled.hpp"
|
|
|
|
#include "classfile/systemDictionary.hpp"
|
2015-02-13 14:37:35 +01:00
|
|
|
#include "gc_interface/collectedHeap.hpp"
|
2010-11-23 13:22:55 -08:00
|
|
|
#include "memory/universe.inline.hpp"
|
|
|
|
#include "prims/jvmtiGetLoadedClasses.hpp"
|
|
|
|
#include "runtime/thread.hpp"
|
2015-02-13 14:37:35 +01:00
|
|
|
#include "utilities/stack.inline.hpp"
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
|
2013-10-24 10:02:02 +02:00
|
|
|
// The closure for GetLoadedClasses
|
|
|
|
class LoadedClassesClosure : public KlassClosure {
|
|
|
|
private:
|
|
|
|
Stack<jclass, mtInternal> _classStack;
|
|
|
|
JvmtiEnv* _env;
|
|
|
|
|
|
|
|
public:
|
|
|
|
LoadedClassesClosure(JvmtiEnv* env) {
|
|
|
|
_env = env;
|
|
|
|
}
|
|
|
|
|
|
|
|
void do_klass(Klass* k) {
|
|
|
|
// Collect all jclasses
|
|
|
|
_classStack.push((jclass) _env->jni_reference(k->java_mirror()));
|
|
|
|
}
|
|
|
|
|
|
|
|
int extract(jclass* result_list) {
|
|
|
|
// The size of the Stack will be 0 after extract, so get it here
|
|
|
|
int count = (int)_classStack.size();
|
|
|
|
int i = count;
|
|
|
|
|
|
|
|
// Pop all jclasses, fill backwards
|
|
|
|
while (!_classStack.is_empty()) {
|
|
|
|
result_list[--i] = _classStack.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the number of elements written
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return current size of the Stack
|
|
|
|
int get_count() {
|
|
|
|
return (int)_classStack.size();
|
|
|
|
}
|
|
|
|
};
|
2007-12-01 00:00:00 +00:00
|
|
|
|
2013-10-24 10:02:02 +02:00
|
|
|
// The closure for GetClassLoaderClasses
|
2007-12-01 00:00:00 +00:00
|
|
|
class JvmtiGetLoadedClassesClosure : public StackObj {
|
|
|
|
// Since the SystemDictionary::classes_do callback
|
|
|
|
// doesn't pass a closureData pointer,
|
|
|
|
// we use a thread-local slot to hold a pointer to
|
|
|
|
// a stack allocated instance of this structure.
|
|
|
|
private:
|
|
|
|
jobject _initiatingLoader;
|
|
|
|
int _count;
|
|
|
|
Handle* _list;
|
|
|
|
int _index;
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Getting and setting the thread local pointer
|
|
|
|
static JvmtiGetLoadedClassesClosure* get_this() {
|
|
|
|
JvmtiGetLoadedClassesClosure* result = NULL;
|
|
|
|
JavaThread* thread = JavaThread::current();
|
|
|
|
result = thread->get_jvmti_get_loaded_classes_closure();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
static void set_this(JvmtiGetLoadedClassesClosure* that) {
|
|
|
|
JavaThread* thread = JavaThread::current();
|
|
|
|
thread->set_jvmti_get_loaded_classes_closure(that);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
// Constructor/Destructor
|
|
|
|
JvmtiGetLoadedClassesClosure() {
|
|
|
|
JvmtiGetLoadedClassesClosure* that = get_this();
|
|
|
|
assert(that == NULL, "JvmtiGetLoadedClassesClosure in use");
|
|
|
|
_initiatingLoader = NULL;
|
|
|
|
_count = 0;
|
|
|
|
_list = NULL;
|
|
|
|
_index = 0;
|
|
|
|
set_this(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
JvmtiGetLoadedClassesClosure(jobject initiatingLoader) {
|
|
|
|
JvmtiGetLoadedClassesClosure* that = get_this();
|
|
|
|
assert(that == NULL, "JvmtiGetLoadedClassesClosure in use");
|
|
|
|
_initiatingLoader = initiatingLoader;
|
|
|
|
_count = 0;
|
|
|
|
_list = NULL;
|
|
|
|
_index = 0;
|
|
|
|
set_this(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
~JvmtiGetLoadedClassesClosure() {
|
|
|
|
JvmtiGetLoadedClassesClosure* that = get_this();
|
|
|
|
assert(that != NULL, "JvmtiGetLoadedClassesClosure not found");
|
|
|
|
set_this(NULL);
|
|
|
|
_initiatingLoader = NULL;
|
|
|
|
_count = 0;
|
|
|
|
if (_list != NULL) {
|
|
|
|
FreeHeap(_list);
|
|
|
|
_list = NULL;
|
|
|
|
}
|
|
|
|
_index = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Accessors.
|
|
|
|
jobject get_initiatingLoader() {
|
|
|
|
return _initiatingLoader;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_count() {
|
|
|
|
return _count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_count(int value) {
|
|
|
|
_count = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
Handle* get_list() {
|
|
|
|
return _list;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_list(Handle* value) {
|
|
|
|
_list = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_index() {
|
|
|
|
return _index;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_index(int value) {
|
|
|
|
_index = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
Handle get_element(int index) {
|
|
|
|
if ((_list != NULL) && (index < _count)) {
|
|
|
|
return _list[index];
|
|
|
|
} else {
|
|
|
|
assert(false, "empty get_element");
|
|
|
|
return Handle();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_element(int index, Handle value) {
|
|
|
|
if ((_list != NULL) && (index < _count)) {
|
|
|
|
_list[index] = value;
|
|
|
|
} else {
|
|
|
|
assert(false, "bad set_element");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Other predicates
|
|
|
|
bool available() {
|
|
|
|
return (_list != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ASSERT
|
|
|
|
// For debugging.
|
|
|
|
void check(int limit) {
|
|
|
|
for (int i = 0; i < limit; i += 1) {
|
|
|
|
assert(Universe::heap()->is_in(get_element(i)()), "check fails");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Public methods that get called within the scope of the closure
|
|
|
|
void allocate() {
|
2012-06-28 17:03:16 -04:00
|
|
|
_list = NEW_C_HEAP_ARRAY(Handle, _count, mtInternal);
|
2007-12-01 00:00:00 +00:00
|
|
|
assert(_list != NULL, "Out of memory");
|
|
|
|
if (_list == NULL) {
|
|
|
|
_count = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void extract(JvmtiEnv *env, jclass* result) {
|
|
|
|
for (int index = 0; index < _count; index += 1) {
|
|
|
|
result[index] = (jclass) env->jni_reference(get_element(index));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
6964458: Reimplement class meta-data storage to use native memory
Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes
Co-authored-by: Stefan Karlsson <stefan.karlsson@oracle.com>
Co-authored-by: Mikael Gerdin <mikael.gerdin@oracle.com>
Co-authored-by: Tom Rodriguez <tom.rodriguez@oracle.com>
Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland
2012-09-01 13:25:18 -04:00
|
|
|
static void increment_with_loader(Klass* k, ClassLoaderData* loader_data) {
|
2007-12-01 00:00:00 +00:00
|
|
|
JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
|
6964458: Reimplement class meta-data storage to use native memory
Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes
Co-authored-by: Stefan Karlsson <stefan.karlsson@oracle.com>
Co-authored-by: Mikael Gerdin <mikael.gerdin@oracle.com>
Co-authored-by: Tom Rodriguez <tom.rodriguez@oracle.com>
Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland
2012-09-01 13:25:18 -04:00
|
|
|
oop class_loader = loader_data->class_loader();
|
|
|
|
if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) {
|
2012-11-12 16:15:05 -05:00
|
|
|
for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) {
|
2007-12-01 00:00:00 +00:00
|
|
|
that->set_count(that->get_count() + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
6964458: Reimplement class meta-data storage to use native memory
Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes
Co-authored-by: Stefan Karlsson <stefan.karlsson@oracle.com>
Co-authored-by: Mikael Gerdin <mikael.gerdin@oracle.com>
Co-authored-by: Tom Rodriguez <tom.rodriguez@oracle.com>
Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland
2012-09-01 13:25:18 -04:00
|
|
|
static void prim_array_increment_with_loader(Klass* array, ClassLoaderData* loader_data) {
|
2007-12-01 00:00:00 +00:00
|
|
|
JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
|
6964458: Reimplement class meta-data storage to use native memory
Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes
Co-authored-by: Stefan Karlsson <stefan.karlsson@oracle.com>
Co-authored-by: Mikael Gerdin <mikael.gerdin@oracle.com>
Co-authored-by: Tom Rodriguez <tom.rodriguez@oracle.com>
Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland
2012-09-01 13:25:18 -04:00
|
|
|
oop class_loader = loader_data->class_loader();
|
|
|
|
if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) {
|
2007-12-01 00:00:00 +00:00
|
|
|
that->set_count(that->get_count() + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
6964458: Reimplement class meta-data storage to use native memory
Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes
Co-authored-by: Stefan Karlsson <stefan.karlsson@oracle.com>
Co-authored-by: Mikael Gerdin <mikael.gerdin@oracle.com>
Co-authored-by: Tom Rodriguez <tom.rodriguez@oracle.com>
Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland
2012-09-01 13:25:18 -04:00
|
|
|
static void add_with_loader(Klass* k, ClassLoaderData* loader_data) {
|
2007-12-01 00:00:00 +00:00
|
|
|
JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
|
|
|
|
if (that->available()) {
|
6964458: Reimplement class meta-data storage to use native memory
Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes
Co-authored-by: Stefan Karlsson <stefan.karlsson@oracle.com>
Co-authored-by: Mikael Gerdin <mikael.gerdin@oracle.com>
Co-authored-by: Tom Rodriguez <tom.rodriguez@oracle.com>
Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland
2012-09-01 13:25:18 -04:00
|
|
|
oop class_loader = loader_data->class_loader();
|
|
|
|
if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) {
|
2012-11-12 16:15:05 -05:00
|
|
|
for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) {
|
|
|
|
oop mirror = l->java_mirror();
|
2007-12-01 00:00:00 +00:00
|
|
|
that->set_element(that->get_index(), mirror);
|
|
|
|
that->set_index(that->get_index() + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// increment the count for the given basic type array class (and any
|
|
|
|
// multi-dimensional arrays). For example, for [B we check for
|
|
|
|
// [[B, [[[B, .. and the count is incremented for each one that exists.
|
6964458: Reimplement class meta-data storage to use native memory
Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes
Co-authored-by: Stefan Karlsson <stefan.karlsson@oracle.com>
Co-authored-by: Mikael Gerdin <mikael.gerdin@oracle.com>
Co-authored-by: Tom Rodriguez <tom.rodriguez@oracle.com>
Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland
2012-09-01 13:25:18 -04:00
|
|
|
static void increment_for_basic_type_arrays(Klass* k) {
|
2007-12-01 00:00:00 +00:00
|
|
|
JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
|
|
|
|
assert(that != NULL, "no JvmtiGetLoadedClassesClosure");
|
2012-11-12 16:15:05 -05:00
|
|
|
for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) {
|
2007-12-01 00:00:00 +00:00
|
|
|
that->set_count(that->get_count() + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add the basic type array class and its multi-dimensional array classes to the list
|
6964458: Reimplement class meta-data storage to use native memory
Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes
Co-authored-by: Stefan Karlsson <stefan.karlsson@oracle.com>
Co-authored-by: Mikael Gerdin <mikael.gerdin@oracle.com>
Co-authored-by: Tom Rodriguez <tom.rodriguez@oracle.com>
Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland
2012-09-01 13:25:18 -04:00
|
|
|
static void add_for_basic_type_arrays(Klass* k) {
|
2007-12-01 00:00:00 +00:00
|
|
|
JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
|
|
|
|
assert(that != NULL, "no JvmtiGetLoadedClassesClosure");
|
|
|
|
assert(that->available(), "no list");
|
2012-11-12 16:15:05 -05:00
|
|
|
for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) {
|
|
|
|
oop mirror = l->java_mirror();
|
2007-12-01 00:00:00 +00:00
|
|
|
that->set_element(that->get_index(), mirror);
|
|
|
|
that->set_index(that->get_index() + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
jvmtiError
|
|
|
|
JvmtiGetLoadedClasses::getLoadedClasses(JvmtiEnv *env, jint* classCountPtr, jclass** classesPtr) {
|
|
|
|
|
2013-10-24 10:02:02 +02:00
|
|
|
LoadedClassesClosure closure(env);
|
2007-12-01 00:00:00 +00:00
|
|
|
{
|
|
|
|
// To get a consistent list of classes we need MultiArray_lock to ensure
|
2013-10-24 10:02:02 +02:00
|
|
|
// array classes aren't created.
|
2007-12-01 00:00:00 +00:00
|
|
|
MutexLocker ma(MultiArray_lock);
|
|
|
|
|
2013-10-24 10:02:02 +02:00
|
|
|
// Iterate through all classes in ClassLoaderDataGraph
|
|
|
|
// and collect them using the LoadedClassesClosure
|
|
|
|
ClassLoaderDataGraph::loaded_classes_do(&closure);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2013-10-24 10:02:02 +02:00
|
|
|
|
|
|
|
// Return results by extracting the collected contents into a list
|
|
|
|
// allocated via JvmtiEnv
|
2007-12-01 00:00:00 +00:00
|
|
|
jclass* result_list;
|
2013-10-24 10:02:02 +02:00
|
|
|
jvmtiError error = env->Allocate(closure.get_count() * sizeof(jclass),
|
|
|
|
(unsigned char**)&result_list);
|
|
|
|
|
|
|
|
if (error == JVMTI_ERROR_NONE) {
|
|
|
|
int count = closure.extract(result_list);
|
|
|
|
*classCountPtr = count;
|
|
|
|
*classesPtr = result_list;
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2013-10-24 10:02:02 +02:00
|
|
|
return error;
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
jvmtiError
|
|
|
|
JvmtiGetLoadedClasses::getClassLoaderClasses(JvmtiEnv *env, jobject initiatingLoader,
|
|
|
|
jint* classCountPtr, jclass** classesPtr) {
|
|
|
|
// Since SystemDictionary::classes_do only takes a function pointer
|
|
|
|
// and doesn't call back with a closure data pointer,
|
|
|
|
// we can only pass static methods.
|
|
|
|
JvmtiGetLoadedClassesClosure closure(initiatingLoader);
|
|
|
|
{
|
|
|
|
// To get a consistent list of classes we need MultiArray_lock to ensure
|
|
|
|
// array classes aren't created, and SystemDictionary_lock to ensure that
|
|
|
|
// classes aren't added to the system dictionary,
|
|
|
|
MutexLocker ma(MultiArray_lock);
|
|
|
|
MutexLocker sd(SystemDictionary_lock);
|
|
|
|
// First, count the classes in the system dictionary which have this loader recorded
|
|
|
|
// as an initiating loader. For basic type arrays this information is not recorded
|
|
|
|
// so GetClassLoaderClasses will return all of the basic type arrays. This is okay
|
|
|
|
// because the defining loader for basic type arrays is always the boot class loader
|
|
|
|
// and these classes are "visible" to all loaders.
|
|
|
|
SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::increment_with_loader);
|
|
|
|
Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::increment_for_basic_type_arrays);
|
|
|
|
// Next, fill in the classes
|
|
|
|
closure.allocate();
|
|
|
|
SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::add_with_loader);
|
|
|
|
Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::add_for_basic_type_arrays);
|
|
|
|
// Drop the SystemDictionary_lock, so the results could be wrong from here,
|
|
|
|
// but we still have a snapshot.
|
|
|
|
}
|
|
|
|
// Post results
|
|
|
|
jclass* result_list;
|
|
|
|
jvmtiError err = env->Allocate(closure.get_count() * sizeof(jclass),
|
|
|
|
(unsigned char**)&result_list);
|
|
|
|
if (err != JVMTI_ERROR_NONE) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
closure.extract(env, result_list);
|
|
|
|
*classCountPtr = closure.get_count();
|
|
|
|
*classesPtr = result_list;
|
|
|
|
return JVMTI_ERROR_NONE;
|
|
|
|
}
|