Mercurial > hg > truffle
annotate src/share/vm/prims/jvmtiGetLoadedClasses.cpp @ 3763:e66f38dd58a9
Merge
author | ysr |
---|---|
date | Wed, 08 Jun 2011 08:39:53 -0700 |
parents | f95d63e2154a |
children | d2a62e0f25eb |
rev | line source |
---|---|
0 | 1 /* |
1972 | 2 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "classfile/systemDictionary.hpp" | |
27 #include "memory/universe.inline.hpp" | |
28 #include "prims/jvmtiGetLoadedClasses.hpp" | |
29 #include "runtime/thread.hpp" | |
0 | 30 |
31 | |
32 | |
33 // The closure for GetLoadedClasses and GetClassLoaderClasses | |
34 class JvmtiGetLoadedClassesClosure : public StackObj { | |
35 // Since the SystemDictionary::classes_do callback | |
36 // doesn't pass a closureData pointer, | |
37 // we use a thread-local slot to hold a pointer to | |
38 // a stack allocated instance of this structure. | |
39 private: | |
40 jobject _initiatingLoader; | |
41 int _count; | |
42 Handle* _list; | |
43 int _index; | |
44 | |
45 private: | |
46 // Getting and setting the thread local pointer | |
47 static JvmtiGetLoadedClassesClosure* get_this() { | |
48 JvmtiGetLoadedClassesClosure* result = NULL; | |
49 JavaThread* thread = JavaThread::current(); | |
50 result = thread->get_jvmti_get_loaded_classes_closure(); | |
51 return result; | |
52 } | |
53 static void set_this(JvmtiGetLoadedClassesClosure* that) { | |
54 JavaThread* thread = JavaThread::current(); | |
55 thread->set_jvmti_get_loaded_classes_closure(that); | |
56 } | |
57 | |
58 public: | |
59 // Constructor/Destructor | |
60 JvmtiGetLoadedClassesClosure() { | |
61 JvmtiGetLoadedClassesClosure* that = get_this(); | |
62 assert(that == NULL, "JvmtiGetLoadedClassesClosure in use"); | |
63 _initiatingLoader = NULL; | |
64 _count = 0; | |
65 _list = NULL; | |
66 _index = 0; | |
67 set_this(this); | |
68 } | |
69 | |
70 JvmtiGetLoadedClassesClosure(jobject initiatingLoader) { | |
71 JvmtiGetLoadedClassesClosure* that = get_this(); | |
72 assert(that == NULL, "JvmtiGetLoadedClassesClosure in use"); | |
73 _initiatingLoader = initiatingLoader; | |
74 _count = 0; | |
75 _list = NULL; | |
76 _index = 0; | |
77 set_this(this); | |
78 } | |
79 | |
80 ~JvmtiGetLoadedClassesClosure() { | |
81 JvmtiGetLoadedClassesClosure* that = get_this(); | |
82 assert(that != NULL, "JvmtiGetLoadedClassesClosure not found"); | |
83 set_this(NULL); | |
84 _initiatingLoader = NULL; | |
85 _count = 0; | |
86 if (_list != NULL) { | |
87 FreeHeap(_list); | |
88 _list = NULL; | |
89 } | |
90 _index = 0; | |
91 } | |
92 | |
93 // Accessors. | |
94 jobject get_initiatingLoader() { | |
95 return _initiatingLoader; | |
96 } | |
97 | |
98 int get_count() { | |
99 return _count; | |
100 } | |
101 | |
102 void set_count(int value) { | |
103 _count = value; | |
104 } | |
105 | |
106 Handle* get_list() { | |
107 return _list; | |
108 } | |
109 | |
110 void set_list(Handle* value) { | |
111 _list = value; | |
112 } | |
113 | |
114 int get_index() { | |
115 return _index; | |
116 } | |
117 | |
118 void set_index(int value) { | |
119 _index = value; | |
120 } | |
121 | |
122 Handle get_element(int index) { | |
123 if ((_list != NULL) && (index < _count)) { | |
124 return _list[index]; | |
125 } else { | |
126 assert(false, "empty get_element"); | |
127 return Handle(); | |
128 } | |
129 } | |
130 | |
131 void set_element(int index, Handle value) { | |
132 if ((_list != NULL) && (index < _count)) { | |
133 _list[index] = value; | |
134 } else { | |
135 assert(false, "bad set_element"); | |
136 } | |
137 } | |
138 | |
139 // Other predicates | |
140 bool available() { | |
141 return (_list != NULL); | |
142 } | |
143 | |
144 #ifdef ASSERT | |
145 // For debugging. | |
146 void check(int limit) { | |
147 for (int i = 0; i < limit; i += 1) { | |
148 assert(Universe::heap()->is_in(get_element(i)()), "check fails"); | |
149 } | |
150 } | |
151 #endif | |
152 | |
153 // Public methods that get called within the scope of the closure | |
154 void allocate() { | |
155 _list = NEW_C_HEAP_ARRAY(Handle, _count); | |
156 assert(_list != NULL, "Out of memory"); | |
157 if (_list == NULL) { | |
158 _count = 0; | |
159 } | |
160 } | |
161 | |
162 void extract(JvmtiEnv *env, jclass* result) { | |
163 for (int index = 0; index < _count; index += 1) { | |
164 result[index] = (jclass) env->jni_reference(get_element(index)); | |
165 } | |
166 } | |
167 | |
168 // Finally, the static methods that are the callbacks | |
169 static void increment(klassOop k) { | |
170 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); | |
171 if (that->get_initiatingLoader() == NULL) { | |
172 for (klassOop l = k; l != NULL; l = Klass::cast(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(klassOop k, oop loader) { | |
182 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); | |
183 if (loader == JNIHandles::resolve(that->get_initiatingLoader())) { | |
184 for (klassOop l = k; l != NULL; l = Klass::cast(l)->array_klass_or_null()) { | |
185 that->set_count(that->get_count() + 1); | |
186 } | |
187 } | |
188 } | |
189 | |
190 static void prim_array_increment_with_loader(klassOop array, oop loader) { | |
191 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); | |
192 if (loader == JNIHandles::resolve(that->get_initiatingLoader())) { | |
193 that->set_count(that->get_count() + 1); | |
194 } | |
195 } | |
196 | |
197 static void add(klassOop k) { | |
198 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); | |
199 if (that->available()) { | |
200 if (that->get_initiatingLoader() == NULL) { | |
201 for (klassOop l = k; l != NULL; l = Klass::cast(l)->array_klass_or_null()) { | |
202 oop mirror = Klass::cast(l)->java_mirror(); | |
203 that->set_element(that->get_index(), mirror); | |
204 that->set_index(that->get_index() + 1); | |
205 } | |
206 } else if (k != NULL) { | |
207 // if initiating loader not null, just include the instance with 1 dimension | |
208 oop mirror = Klass::cast(k)->java_mirror(); | |
209 that->set_element(that->get_index(), mirror); | |
210 that->set_index(that->get_index() + 1); | |
211 } | |
212 } | |
213 } | |
214 | |
215 static void add_with_loader(klassOop k, oop loader) { | |
216 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); | |
217 if (that->available()) { | |
218 if (loader == JNIHandles::resolve(that->get_initiatingLoader())) { | |
219 for (klassOop l = k; l != NULL; l = Klass::cast(l)->array_klass_or_null()) { | |
220 oop mirror = Klass::cast(l)->java_mirror(); | |
221 that->set_element(that->get_index(), mirror); | |
222 that->set_index(that->get_index() + 1); | |
223 } | |
224 } | |
225 } | |
226 } | |
227 | |
228 // increment the count for the given basic type array class (and any | |
229 // multi-dimensional arrays). For example, for [B we check for | |
230 // [[B, [[[B, .. and the count is incremented for each one that exists. | |
231 static void increment_for_basic_type_arrays(klassOop k) { | |
232 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); | |
233 assert(that != NULL, "no JvmtiGetLoadedClassesClosure"); | |
234 for (klassOop l = k; l != NULL; l = Klass::cast(l)->array_klass_or_null()) { | |
235 that->set_count(that->get_count() + 1); | |
236 } | |
237 } | |
238 | |
239 // add the basic type array class and its multi-dimensional array classes to the list | |
240 static void add_for_basic_type_arrays(klassOop k) { | |
241 JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this(); | |
242 assert(that != NULL, "no JvmtiGetLoadedClassesClosure"); | |
243 assert(that->available(), "no list"); | |
244 for (klassOop l = k; l != NULL; l = Klass::cast(l)->array_klass_or_null()) { | |
245 oop mirror = Klass::cast(l)->java_mirror(); | |
246 that->set_element(that->get_index(), mirror); | |
247 that->set_index(that->get_index() + 1); | |
248 } | |
249 } | |
250 }; | |
251 | |
252 | |
253 jvmtiError | |
254 JvmtiGetLoadedClasses::getLoadedClasses(JvmtiEnv *env, jint* classCountPtr, jclass** classesPtr) { | |
255 // Since SystemDictionary::classes_do only takes a function pointer | |
256 // and doesn't call back with a closure data pointer, | |
257 // we can only pass static methods. | |
258 | |
259 JvmtiGetLoadedClassesClosure closure; | |
260 { | |
261 // To get a consistent list of classes we need MultiArray_lock to ensure | |
262 // array classes aren't created, and SystemDictionary_lock to ensure that | |
263 // classes aren't added to the system dictionary, | |
264 MutexLocker ma(MultiArray_lock); | |
265 MutexLocker sd(SystemDictionary_lock); | |
266 | |
267 // First, count the classes | |
268 SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::increment); | |
269 Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::increment); | |
270 // Next, fill in the classes | |
271 closure.allocate(); | |
272 SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::add); | |
273 Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::add); | |
274 // Drop the SystemDictionary_lock, so the results could be wrong from here, | |
275 // but we still have a snapshot. | |
276 } | |
277 // Post results | |
278 jclass* result_list; | |
279 jvmtiError err = env->Allocate(closure.get_count() * sizeof(jclass), | |
280 (unsigned char**)&result_list); | |
281 if (err != JVMTI_ERROR_NONE) { | |
282 return err; | |
283 } | |
284 closure.extract(env, result_list); | |
285 *classCountPtr = closure.get_count(); | |
286 *classesPtr = result_list; | |
287 return JVMTI_ERROR_NONE; | |
288 } | |
289 | |
290 jvmtiError | |
291 JvmtiGetLoadedClasses::getClassLoaderClasses(JvmtiEnv *env, jobject initiatingLoader, | |
292 jint* classCountPtr, jclass** classesPtr) { | |
293 // Since SystemDictionary::classes_do only takes a function pointer | |
294 // and doesn't call back with a closure data pointer, | |
295 // we can only pass static methods. | |
296 JvmtiGetLoadedClassesClosure closure(initiatingLoader); | |
297 { | |
298 // To get a consistent list of classes we need MultiArray_lock to ensure | |
299 // array classes aren't created, and SystemDictionary_lock to ensure that | |
300 // classes aren't added to the system dictionary, | |
301 MutexLocker ma(MultiArray_lock); | |
302 MutexLocker sd(SystemDictionary_lock); | |
303 // First, count the classes in the system dictionary which have this loader recorded | |
304 // as an initiating loader. For basic type arrays this information is not recorded | |
305 // so GetClassLoaderClasses will return all of the basic type arrays. This is okay | |
306 // because the defining loader for basic type arrays is always the boot class loader | |
307 // and these classes are "visible" to all loaders. | |
308 SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::increment_with_loader); | |
309 Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::increment_for_basic_type_arrays); | |
310 // Next, fill in the classes | |
311 closure.allocate(); | |
312 SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::add_with_loader); | |
313 Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::add_for_basic_type_arrays); | |
314 // Drop the SystemDictionary_lock, so the results could be wrong from here, | |
315 // but we still have a snapshot. | |
316 } | |
317 // Post results | |
318 jclass* result_list; | |
319 jvmtiError err = env->Allocate(closure.get_count() * sizeof(jclass), | |
320 (unsigned char**)&result_list); | |
321 if (err != JVMTI_ERROR_NONE) { | |
322 return err; | |
323 } | |
324 closure.extract(env, result_list); | |
325 *classCountPtr = closure.get_count(); | |
326 *classesPtr = result_list; | |
327 return JVMTI_ERROR_NONE; | |
328 } |