jvmtiGetLoadedClasses.cpp revision 1472:c18cbe5936b8
1/*
2 * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25
26# include "incls/_precompiled.incl"
27# include "incls/_jvmtiGetLoadedClasses.cpp.incl"
28
29
30// The closure for GetLoadedClasses and GetClassLoaderClasses
31class JvmtiGetLoadedClassesClosure : public StackObj {
32  // Since the SystemDictionary::classes_do callback
33  // doesn't pass a closureData pointer,
34  // we use a thread-local slot to hold a pointer to
35  // a stack allocated instance of this structure.
36 private:
37  jobject _initiatingLoader;
38  int     _count;
39  Handle* _list;
40  int     _index;
41
42 private:
43  // Getting and setting the thread local pointer
44  static JvmtiGetLoadedClassesClosure* get_this() {
45    JvmtiGetLoadedClassesClosure* result = NULL;
46    JavaThread* thread = JavaThread::current();
47    result = thread->get_jvmti_get_loaded_classes_closure();
48    return result;
49  }
50  static void set_this(JvmtiGetLoadedClassesClosure* that) {
51    JavaThread* thread = JavaThread::current();
52    thread->set_jvmti_get_loaded_classes_closure(that);
53  }
54
55 public:
56  // Constructor/Destructor
57  JvmtiGetLoadedClassesClosure() {
58    JvmtiGetLoadedClassesClosure* that = get_this();
59    assert(that == NULL, "JvmtiGetLoadedClassesClosure in use");
60    _initiatingLoader = NULL;
61    _count = 0;
62    _list = NULL;
63    _index = 0;
64    set_this(this);
65  }
66
67  JvmtiGetLoadedClassesClosure(jobject initiatingLoader) {
68    JvmtiGetLoadedClassesClosure* that = get_this();
69    assert(that == NULL, "JvmtiGetLoadedClassesClosure in use");
70    _initiatingLoader = initiatingLoader;
71    _count = 0;
72    _list = NULL;
73    _index = 0;
74    set_this(this);
75  }
76
77  ~JvmtiGetLoadedClassesClosure() {
78    JvmtiGetLoadedClassesClosure* that = get_this();
79    assert(that != NULL, "JvmtiGetLoadedClassesClosure not found");
80    set_this(NULL);
81    _initiatingLoader = NULL;
82    _count = 0;
83    if (_list != NULL) {
84      FreeHeap(_list);
85      _list = NULL;
86    }
87    _index = 0;
88  }
89
90  // Accessors.
91  jobject get_initiatingLoader() {
92    return _initiatingLoader;
93  }
94
95  int get_count() {
96    return _count;
97  }
98
99  void set_count(int value) {
100    _count = value;
101  }
102
103  Handle* get_list() {
104    return _list;
105  }
106
107  void set_list(Handle* value) {
108    _list = value;
109  }
110
111  int get_index() {
112    return _index;
113  }
114
115  void set_index(int value) {
116    _index = value;
117  }
118
119  Handle get_element(int index) {
120    if ((_list != NULL) && (index < _count)) {
121      return _list[index];
122    } else {
123      assert(false, "empty get_element");
124      return Handle();
125    }
126  }
127
128  void set_element(int index, Handle value) {
129    if ((_list != NULL) && (index < _count)) {
130      _list[index] = value;
131    } else {
132      assert(false, "bad set_element");
133    }
134  }
135
136  // Other predicates
137  bool available() {
138    return (_list != NULL);
139  }
140
141#ifdef ASSERT
142  // For debugging.
143  void check(int limit) {
144    for (int i = 0; i < limit; i += 1) {
145      assert(Universe::heap()->is_in(get_element(i)()), "check fails");
146    }
147  }
148#endif
149
150  // Public methods that get called within the scope of the closure
151  void allocate() {
152    _list = NEW_C_HEAP_ARRAY(Handle, _count);
153    assert(_list != NULL, "Out of memory");
154    if (_list == NULL) {
155      _count = 0;
156    }
157  }
158
159  void extract(JvmtiEnv *env, jclass* result) {
160    for (int index = 0; index < _count; index += 1) {
161      result[index] = (jclass) env->jni_reference(get_element(index));
162    }
163  }
164
165  // Finally, the static methods that are the callbacks
166  static void increment(klassOop k) {
167    JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
168    if (that->get_initiatingLoader() == NULL) {
169      for (klassOop l = k; l != NULL; l = Klass::cast(l)->array_klass_or_null()) {
170        that->set_count(that->get_count() + 1);
171      }
172    } else if (k != NULL) {
173      // if initiating loader not null, just include the instance with 1 dimension
174      that->set_count(that->get_count() + 1);
175    }
176  }
177
178  static void increment_with_loader(klassOop k, oop loader) {
179    JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
180    if (loader == JNIHandles::resolve(that->get_initiatingLoader())) {
181      for (klassOop l = k; l != NULL; l = Klass::cast(l)->array_klass_or_null()) {
182        that->set_count(that->get_count() + 1);
183      }
184    }
185  }
186
187  static void prim_array_increment_with_loader(klassOop array, oop loader) {
188    JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
189    if (loader == JNIHandles::resolve(that->get_initiatingLoader())) {
190      that->set_count(that->get_count() + 1);
191    }
192  }
193
194  static void add(klassOop k) {
195    JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
196    if (that->available()) {
197      if (that->get_initiatingLoader() == NULL) {
198        for (klassOop l = k; l != NULL; l = Klass::cast(l)->array_klass_or_null()) {
199          oop mirror = Klass::cast(l)->java_mirror();
200          that->set_element(that->get_index(), mirror);
201          that->set_index(that->get_index() + 1);
202        }
203      } else if (k != NULL) {
204        // if initiating loader not null, just include the instance with 1 dimension
205        oop mirror = Klass::cast(k)->java_mirror();
206        that->set_element(that->get_index(), mirror);
207        that->set_index(that->get_index() + 1);
208      }
209    }
210  }
211
212  static void add_with_loader(klassOop k, oop loader) {
213    JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
214    if (that->available()) {
215      if (loader == JNIHandles::resolve(that->get_initiatingLoader())) {
216        for (klassOop l = k; l != NULL; l = Klass::cast(l)->array_klass_or_null()) {
217          oop mirror = Klass::cast(l)->java_mirror();
218          that->set_element(that->get_index(), mirror);
219          that->set_index(that->get_index() + 1);
220        }
221      }
222    }
223  }
224
225  // increment the count for the given basic type array class (and any
226  // multi-dimensional arrays). For example, for [B we check for
227  // [[B, [[[B, .. and the count is incremented for each one that exists.
228  static void increment_for_basic_type_arrays(klassOop k) {
229    JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
230    assert(that != NULL, "no JvmtiGetLoadedClassesClosure");
231    for (klassOop l = k; l != NULL; l = Klass::cast(l)->array_klass_or_null()) {
232      that->set_count(that->get_count() + 1);
233    }
234  }
235
236  // add the basic type array class and its multi-dimensional array classes to the list
237  static void add_for_basic_type_arrays(klassOop k) {
238    JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
239    assert(that != NULL, "no JvmtiGetLoadedClassesClosure");
240    assert(that->available(), "no list");
241    for (klassOop l = k; l != NULL; l = Klass::cast(l)->array_klass_or_null()) {
242      oop mirror = Klass::cast(l)->java_mirror();
243      that->set_element(that->get_index(), mirror);
244      that->set_index(that->get_index() + 1);
245    }
246  }
247};
248
249
250jvmtiError
251JvmtiGetLoadedClasses::getLoadedClasses(JvmtiEnv *env, jint* classCountPtr, jclass** classesPtr) {
252  // Since SystemDictionary::classes_do only takes a function pointer
253  // and doesn't call back with a closure data pointer,
254  // we can only pass static methods.
255
256  JvmtiGetLoadedClassesClosure closure;
257  {
258    // To get a consistent list of classes we need MultiArray_lock to ensure
259    // array classes aren't created, and SystemDictionary_lock to ensure that
260    // classes aren't added to the system dictionary,
261    MutexLocker ma(MultiArray_lock);
262    MutexLocker sd(SystemDictionary_lock);
263
264    // First, count the classes
265    SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::increment);
266    Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::increment);
267    // Next, fill in the classes
268    closure.allocate();
269    SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::add);
270    Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::add);
271    // Drop the SystemDictionary_lock, so the results could be wrong from here,
272    // but we still have a snapshot.
273  }
274  // Post results
275  jclass* result_list;
276  jvmtiError err = env->Allocate(closure.get_count() * sizeof(jclass),
277                                 (unsigned char**)&result_list);
278  if (err != JVMTI_ERROR_NONE) {
279    return err;
280  }
281  closure.extract(env, result_list);
282  *classCountPtr = closure.get_count();
283  *classesPtr = result_list;
284  return JVMTI_ERROR_NONE;
285}
286
287jvmtiError
288JvmtiGetLoadedClasses::getClassLoaderClasses(JvmtiEnv *env, jobject initiatingLoader,
289                                             jint* classCountPtr, jclass** classesPtr) {
290  // Since SystemDictionary::classes_do only takes a function pointer
291  // and doesn't call back with a closure data pointer,
292  // we can only pass static methods.
293  JvmtiGetLoadedClassesClosure closure(initiatingLoader);
294  {
295    // To get a consistent list of classes we need MultiArray_lock to ensure
296    // array classes aren't created, and SystemDictionary_lock to ensure that
297    // classes aren't added to the system dictionary,
298    MutexLocker ma(MultiArray_lock);
299    MutexLocker sd(SystemDictionary_lock);
300    // First, count the classes in the system dictionary which have this loader recorded
301    // as an initiating loader. For basic type arrays this information is not recorded
302    // so GetClassLoaderClasses will return all of the basic type arrays. This is okay
303    // because the defining loader for basic type arrays is always the boot class loader
304    // and these classes are "visible" to all loaders.
305    SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::increment_with_loader);
306    Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::increment_for_basic_type_arrays);
307    // Next, fill in the classes
308    closure.allocate();
309    SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::add_with_loader);
310    Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::add_for_basic_type_arrays);
311    // Drop the SystemDictionary_lock, so the results could be wrong from here,
312    // but we still have a snapshot.
313  }
314  // Post results
315  jclass* result_list;
316  jvmtiError err = env->Allocate(closure.get_count() * sizeof(jclass),
317                                 (unsigned char**)&result_list);
318  if (err != JVMTI_ERROR_NONE) {
319    return err;
320  }
321  closure.extract(env, result_list);
322  *classCountPtr = closure.get_count();
323  *classesPtr = result_list;
324  return JVMTI_ERROR_NONE;
325}
326