Mercurial > hg > graal-compiler
annotate src/share/vm/prims/jvmtiGetLoadedClasses.cpp @ 3917:eca1193ca245
4965777: GC changes to support use of discovered field for pending references
Summary: If and when the reference handler thread is able to use the discovered field to link reference objects in its pending list, so will GC. In that case, GC will scan through this field once a reference object has been placed on the pending list, but not scan that field before that stage, as the field is used by the concurrent GC thread to link discovered objects. When ReferenceHandleR thread does not use the discovered field for the purpose of linking the elements in the pending list, as would be the case in older JDKs, the JVM will fall back to the old behaviour of using the next field for that purpose.
Reviewed-by: jcoomes, mchung, stefank
author | ysr |
---|---|
date | Wed, 07 Sep 2011 13:55:42 -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 } |