comparison src/share/vm/prims/jvmtiGetLoadedClasses.cpp @ 12995:e64f1fe9756b

8024423: JVMTI: GetLoadedClasses doesn't enumerate anonymous classes Summary: Rewrite of the getLoadedClasses() method implementation to include anonymous classes. Reviewed-by: coleenp, sspitsyn
author farvidsson
date Thu, 24 Oct 2013 10:02:02 +0200
parents 070d523b96a7
children de6a9e811145
comparison
equal deleted inserted replaced
12950:b658cfe35857 12995:e64f1fe9756b
27 #include "memory/universe.inline.hpp" 27 #include "memory/universe.inline.hpp"
28 #include "prims/jvmtiGetLoadedClasses.hpp" 28 #include "prims/jvmtiGetLoadedClasses.hpp"
29 #include "runtime/thread.hpp" 29 #include "runtime/thread.hpp"
30 30
31 31
32 32 // The closure for GetLoadedClasses
33 // The closure for GetLoadedClasses and GetClassLoaderClasses 33 class LoadedClassesClosure : public KlassClosure {
34 private:
35 Stack<jclass, mtInternal> _classStack;
36 JvmtiEnv* _env;
37
38 public:
39 LoadedClassesClosure(JvmtiEnv* env) {
40 _env = env;
41 }
42
43 void do_klass(Klass* k) {
44 // Collect all jclasses
45 _classStack.push((jclass) _env->jni_reference(k->java_mirror()));
46 }
47
48 int extract(jclass* result_list) {
49 // The size of the Stack will be 0 after extract, so get it here
50 int count = (int)_classStack.size();
51 int i = count;
52
53 // Pop all jclasses, fill backwards
54 while (!_classStack.is_empty()) {
55 result_list[--i] = _classStack.pop();
56 }
57
58 // Return the number of elements written
59 return count;
60 }
61
62 // Return current size of the Stack
63 int get_count() {
64 return (int)_classStack.size();
65 }
66 };
67
68 // The closure for GetClassLoaderClasses
34 class JvmtiGetLoadedClassesClosure : public StackObj { 69 class JvmtiGetLoadedClassesClosure : public StackObj {
35 // Since the SystemDictionary::classes_do callback 70 // Since the SystemDictionary::classes_do callback
36 // doesn't pass a closureData pointer, 71 // doesn't pass a closureData pointer,
37 // we use a thread-local slot to hold a pointer to 72 // we use a thread-local slot to hold a pointer to
38 // a stack allocated instance of this structure. 73 // a stack allocated instance of this structure.
163 for (int index = 0; index < _count; index += 1) { 198 for (int index = 0; index < _count; index += 1) {
164 result[index] = (jclass) env->jni_reference(get_element(index)); 199 result[index] = (jclass) env->jni_reference(get_element(index));
165 } 200 }
166 } 201 }
167 202
168 // Finally, the static methods that are the callbacks
169 static void increment(Klass* k) {
170 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
171 if (that->get_initiatingLoader() == NULL) {
172 for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) {
173 that->set_count(that->get_count() + 1);
174 }
175 } else if (k != NULL) {
176 // if initiating loader not null, just include the instance with 1 dimension
177 that->set_count(that->get_count() + 1);
178 }
179 }
180
181 static void increment_with_loader(Klass* k, ClassLoaderData* loader_data) { 203 static void increment_with_loader(Klass* k, ClassLoaderData* loader_data) {
182 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); 204 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
183 oop class_loader = loader_data->class_loader(); 205 oop class_loader = loader_data->class_loader();
184 if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) { 206 if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) {
185 for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) { 207 for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) {
191 static void prim_array_increment_with_loader(Klass* array, ClassLoaderData* loader_data) { 213 static void prim_array_increment_with_loader(Klass* array, ClassLoaderData* loader_data) {
192 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); 214 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
193 oop class_loader = loader_data->class_loader(); 215 oop class_loader = loader_data->class_loader();
194 if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) { 216 if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) {
195 that->set_count(that->get_count() + 1); 217 that->set_count(that->get_count() + 1);
196 }
197 }
198
199 static void add(Klass* k) {
200 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
201 if (that->available()) {
202 if (that->get_initiatingLoader() == NULL) {
203 for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) {
204 oop mirror = l->java_mirror();
205 that->set_element(that->get_index(), mirror);
206 that->set_index(that->get_index() + 1);
207 }
208 } else if (k != NULL) {
209 // if initiating loader not null, just include the instance with 1 dimension
210 oop mirror = k->java_mirror();
211 that->set_element(that->get_index(), mirror);
212 that->set_index(that->get_index() + 1);
213 }
214 } 218 }
215 } 219 }
216 220
217 static void add_with_loader(Klass* k, ClassLoaderData* loader_data) { 221 static void add_with_loader(Klass* k, ClassLoaderData* loader_data) {
218 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); 222 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
253 }; 257 };
254 258
255 259
256 jvmtiError 260 jvmtiError
257 JvmtiGetLoadedClasses::getLoadedClasses(JvmtiEnv *env, jint* classCountPtr, jclass** classesPtr) { 261 JvmtiGetLoadedClasses::getLoadedClasses(JvmtiEnv *env, jint* classCountPtr, jclass** classesPtr) {
258 // Since SystemDictionary::classes_do only takes a function pointer 262
259 // and doesn't call back with a closure data pointer, 263 LoadedClassesClosure closure(env);
260 // we can only pass static methods.
261
262 JvmtiGetLoadedClassesClosure closure;
263 { 264 {
264 // To get a consistent list of classes we need MultiArray_lock to ensure 265 // To get a consistent list of classes we need MultiArray_lock to ensure
265 // array classes aren't created, and SystemDictionary_lock to ensure that 266 // array classes aren't created.
266 // classes aren't added to the system dictionary,
267 MutexLocker ma(MultiArray_lock); 267 MutexLocker ma(MultiArray_lock);
268 MutexLocker sd(SystemDictionary_lock); 268
269 269 // Iterate through all classes in ClassLoaderDataGraph
270 // First, count the classes 270 // and collect them using the LoadedClassesClosure
271 SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::increment); 271 ClassLoaderDataGraph::loaded_classes_do(&closure);
272 Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::increment); 272 }
273 // Next, fill in the classes 273
274 closure.allocate(); 274 // Return results by extracting the collected contents into a list
275 SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::add); 275 // allocated via JvmtiEnv
276 Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::add);
277 // Drop the SystemDictionary_lock, so the results could be wrong from here,
278 // but we still have a snapshot.
279 }
280 // Post results
281 jclass* result_list; 276 jclass* result_list;
282 jvmtiError err = env->Allocate(closure.get_count() * sizeof(jclass), 277 jvmtiError error = env->Allocate(closure.get_count() * sizeof(jclass),
283 (unsigned char**)&result_list); 278 (unsigned char**)&result_list);
284 if (err != JVMTI_ERROR_NONE) { 279
285 return err; 280 if (error == JVMTI_ERROR_NONE) {
286 } 281 int count = closure.extract(result_list);
287 closure.extract(env, result_list); 282 *classCountPtr = count;
288 *classCountPtr = closure.get_count(); 283 *classesPtr = result_list;
289 *classesPtr = result_list; 284 }
290 return JVMTI_ERROR_NONE; 285 return error;
291 } 286 }
292 287
293 jvmtiError 288 jvmtiError
294 JvmtiGetLoadedClasses::getClassLoaderClasses(JvmtiEnv *env, jobject initiatingLoader, 289 JvmtiGetLoadedClasses::getClassLoaderClasses(JvmtiEnv *env, jobject initiatingLoader,
295 jint* classCountPtr, jclass** classesPtr) { 290 jint* classCountPtr, jclass** classesPtr) {