Mercurial > hg > truffle
annotate src/share/vm/prims/jvmtiTagMap.cpp @ 3762:5c0a3c1858b1
7048782: CMS: assert(last_chunk_index_to_check<= last_chunk_index) failed: parCardTableModRefBS.cpp:359
Summary: The LNC array is sized before the start of a scavenge, while the heap may expand during a scavenge. With CMS, the last block of an arbitrary suffice of the LNC array may expand due to coalition with the expansion delta. We now take care not to attempt access past the end of the LNC array. LNC array code will be cleaned up and suitably encapsulated as part of the forthcoming performance RFE 7043675.
Reviewed-by: brutisso
author | ysr |
---|---|
date | Thu, 02 Jun 2011 10:23:36 -0700 |
parents | 167b70ff3abc |
children | d425748f2203 |
rev | line source |
---|---|
0 | 1 /* |
2376
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
2 * Copyright (c) 2003, 2011, 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:
1142
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1142
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:
1142
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "classfile/symbolTable.hpp" | |
27 #include "classfile/systemDictionary.hpp" | |
28 #include "classfile/vmSymbols.hpp" | |
29 #include "jvmtifiles/jvmtiEnv.hpp" | |
2376
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
30 #include "oops/instanceMirrorKlass.hpp" |
1972 | 31 #include "oops/objArrayKlass.hpp" |
32 #include "oops/oop.inline2.hpp" | |
33 #include "prims/jvmtiEventController.hpp" | |
34 #include "prims/jvmtiEventController.inline.hpp" | |
35 #include "prims/jvmtiExport.hpp" | |
36 #include "prims/jvmtiImpl.hpp" | |
37 #include "prims/jvmtiTagMap.hpp" | |
38 #include "runtime/biasedLocking.hpp" | |
39 #include "runtime/javaCalls.hpp" | |
40 #include "runtime/jniHandles.hpp" | |
41 #include "runtime/mutex.hpp" | |
42 #include "runtime/mutexLocker.hpp" | |
43 #include "runtime/reflectionUtils.hpp" | |
44 #include "runtime/vframe.hpp" | |
45 #include "runtime/vmThread.hpp" | |
46 #include "runtime/vm_operations.hpp" | |
47 #include "services/serviceUtil.hpp" | |
48 #ifndef SERIALGC | |
49 #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" | |
50 #endif | |
0 | 51 |
52 // JvmtiTagHashmapEntry | |
53 // | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
54 // Each entry encapsulates a reference to the tagged object |
0 | 55 // and the tag value. In addition an entry includes a next pointer which |
56 // is used to chain entries together. | |
57 | |
58 class JvmtiTagHashmapEntry : public CHeapObj { | |
59 private: | |
60 friend class JvmtiTagMap; | |
61 | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
62 oop _object; // tagged object |
0 | 63 jlong _tag; // the tag |
64 JvmtiTagHashmapEntry* _next; // next on the list | |
65 | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
66 inline void init(oop object, jlong tag) { |
0 | 67 _object = object; |
68 _tag = tag; | |
69 _next = NULL; | |
70 } | |
71 | |
72 // constructor | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
73 JvmtiTagHashmapEntry(oop object, jlong tag) { init(object, tag); } |
0 | 74 |
75 public: | |
76 | |
77 // accessor methods | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
78 inline oop object() const { return _object; } |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
79 inline oop* object_addr() { return &_object; } |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
80 inline jlong tag() const { return _tag; } |
0 | 81 |
82 inline void set_tag(jlong tag) { | |
83 assert(tag != 0, "can't be zero"); | |
84 _tag = tag; | |
85 } | |
86 | |
87 inline JvmtiTagHashmapEntry* next() const { return _next; } | |
88 inline void set_next(JvmtiTagHashmapEntry* next) { _next = next; } | |
89 }; | |
90 | |
91 | |
92 // JvmtiTagHashmap | |
93 // | |
94 // A hashmap is essentially a table of pointers to entries. Entries | |
95 // are hashed to a location, or position in the table, and then | |
96 // chained from that location. The "key" for hashing is address of | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
97 // the object, or oop. The "value" is the tag value. |
0 | 98 // |
99 // A hashmap maintains a count of the number entries in the hashmap | |
100 // and resizes if the number of entries exceeds a given threshold. | |
101 // The threshold is specified as a percentage of the size - for | |
102 // example a threshold of 0.75 will trigger the hashmap to resize | |
103 // if the number of entries is >75% of table size. | |
104 // | |
105 // A hashmap provides functions for adding, removing, and finding | |
106 // entries. It also provides a function to iterate over all entries | |
107 // in the hashmap. | |
108 | |
109 class JvmtiTagHashmap : public CHeapObj { | |
110 private: | |
111 friend class JvmtiTagMap; | |
112 | |
113 enum { | |
114 small_trace_threshold = 10000, // threshold for tracing | |
115 medium_trace_threshold = 100000, | |
116 large_trace_threshold = 1000000, | |
117 initial_trace_threshold = small_trace_threshold | |
118 }; | |
119 | |
120 static int _sizes[]; // array of possible hashmap sizes | |
121 int _size; // actual size of the table | |
122 int _size_index; // index into size table | |
123 | |
124 int _entry_count; // number of entries in the hashmap | |
125 | |
126 float _load_factor; // load factor as a % of the size | |
127 int _resize_threshold; // computed threshold to trigger resizing. | |
128 bool _resizing_enabled; // indicates if hashmap can resize | |
129 | |
130 int _trace_threshold; // threshold for trace messages | |
131 | |
132 JvmtiTagHashmapEntry** _table; // the table of entries. | |
133 | |
134 // private accessors | |
135 int resize_threshold() const { return _resize_threshold; } | |
136 int trace_threshold() const { return _trace_threshold; } | |
137 | |
138 // initialize the hashmap | |
139 void init(int size_index=0, float load_factor=4.0f) { | |
140 int initial_size = _sizes[size_index]; | |
141 _size_index = size_index; | |
142 _size = initial_size; | |
143 _entry_count = 0; | |
144 if (TraceJVMTIObjectTagging) { | |
145 _trace_threshold = initial_trace_threshold; | |
146 } else { | |
147 _trace_threshold = -1; | |
148 } | |
149 _load_factor = load_factor; | |
150 _resize_threshold = (int)(_load_factor * _size); | |
151 _resizing_enabled = true; | |
152 size_t s = initial_size * sizeof(JvmtiTagHashmapEntry*); | |
153 _table = (JvmtiTagHashmapEntry**)os::malloc(s); | |
154 if (_table == NULL) { | |
155 vm_exit_out_of_memory(s, "unable to allocate initial hashtable for jvmti object tags"); | |
156 } | |
157 for (int i=0; i<initial_size; i++) { | |
158 _table[i] = NULL; | |
159 } | |
160 } | |
161 | |
162 // hash a given key (oop) with the specified size | |
163 static unsigned int hash(oop key, int size) { | |
164 // shift right to get better distribution (as these bits will be zero | |
165 // with aligned addresses) | |
166 unsigned int addr = (unsigned int)((intptr_t)key); | |
167 #ifdef _LP64 | |
168 return (addr >> 3) % size; | |
169 #else | |
170 return (addr >> 2) % size; | |
171 #endif | |
172 } | |
173 | |
174 // hash a given key (oop) | |
175 unsigned int hash(oop key) { | |
176 return hash(key, _size); | |
177 } | |
178 | |
179 // resize the hashmap - allocates a large table and re-hashes | |
180 // all entries into the new table. | |
181 void resize() { | |
182 int new_size_index = _size_index+1; | |
183 int new_size = _sizes[new_size_index]; | |
184 if (new_size < 0) { | |
185 // hashmap already at maximum capacity | |
186 return; | |
187 } | |
188 | |
189 // allocate new table | |
190 size_t s = new_size * sizeof(JvmtiTagHashmapEntry*); | |
191 JvmtiTagHashmapEntry** new_table = (JvmtiTagHashmapEntry**)os::malloc(s); | |
192 if (new_table == NULL) { | |
193 warning("unable to allocate larger hashtable for jvmti object tags"); | |
194 set_resizing_enabled(false); | |
195 return; | |
196 } | |
197 | |
198 // initialize new table | |
199 int i; | |
200 for (i=0; i<new_size; i++) { | |
201 new_table[i] = NULL; | |
202 } | |
203 | |
204 // rehash all entries into the new table | |
205 for (i=0; i<_size; i++) { | |
206 JvmtiTagHashmapEntry* entry = _table[i]; | |
207 while (entry != NULL) { | |
208 JvmtiTagHashmapEntry* next = entry->next(); | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
209 oop key = entry->object(); |
0 | 210 assert(key != NULL, "jni weak reference cleared!!"); |
211 unsigned int h = hash(key, new_size); | |
212 JvmtiTagHashmapEntry* anchor = new_table[h]; | |
213 if (anchor == NULL) { | |
214 new_table[h] = entry; | |
215 entry->set_next(NULL); | |
216 } else { | |
217 entry->set_next(anchor); | |
218 new_table[h] = entry; | |
219 } | |
220 entry = next; | |
221 } | |
222 } | |
223 | |
224 // free old table and update settings. | |
225 os::free((void*)_table); | |
226 _table = new_table; | |
227 _size_index = new_size_index; | |
228 _size = new_size; | |
229 | |
230 // compute new resize threshold | |
231 _resize_threshold = (int)(_load_factor * _size); | |
232 } | |
233 | |
234 | |
235 // internal remove function - remove an entry at a given position in the | |
236 // table. | |
237 inline void remove(JvmtiTagHashmapEntry* prev, int pos, JvmtiTagHashmapEntry* entry) { | |
238 assert(pos >= 0 && pos < _size, "out of range"); | |
239 if (prev == NULL) { | |
240 _table[pos] = entry->next(); | |
241 } else { | |
242 prev->set_next(entry->next()); | |
243 } | |
244 assert(_entry_count > 0, "checking"); | |
245 _entry_count--; | |
246 } | |
247 | |
248 // resizing switch | |
249 bool is_resizing_enabled() const { return _resizing_enabled; } | |
250 void set_resizing_enabled(bool enable) { _resizing_enabled = enable; } | |
251 | |
252 // debugging | |
253 void print_memory_usage(); | |
254 void compute_next_trace_threshold(); | |
255 | |
256 public: | |
257 | |
258 // create a JvmtiTagHashmap of a preferred size and optionally a load factor. | |
259 // The preferred size is rounded down to an actual size. | |
260 JvmtiTagHashmap(int size, float load_factor=0.0f) { | |
261 int i=0; | |
262 while (_sizes[i] < size) { | |
263 if (_sizes[i] < 0) { | |
264 assert(i > 0, "sanity check"); | |
265 i--; | |
266 break; | |
267 } | |
268 i++; | |
269 } | |
270 | |
271 // if a load factor is specified then use it, otherwise use default | |
272 if (load_factor > 0.01f) { | |
273 init(i, load_factor); | |
274 } else { | |
275 init(i); | |
276 } | |
277 } | |
278 | |
279 // create a JvmtiTagHashmap with default settings | |
280 JvmtiTagHashmap() { | |
281 init(); | |
282 } | |
283 | |
284 // release table when JvmtiTagHashmap destroyed | |
285 ~JvmtiTagHashmap() { | |
286 if (_table != NULL) { | |
287 os::free((void*)_table); | |
288 _table = NULL; | |
289 } | |
290 } | |
291 | |
292 // accessors | |
293 int size() const { return _size; } | |
294 JvmtiTagHashmapEntry** table() const { return _table; } | |
295 int entry_count() const { return _entry_count; } | |
296 | |
297 // find an entry in the hashmap, returns NULL if not found. | |
298 inline JvmtiTagHashmapEntry* find(oop key) { | |
299 unsigned int h = hash(key); | |
300 JvmtiTagHashmapEntry* entry = _table[h]; | |
301 while (entry != NULL) { | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
302 if (entry->object() == key) { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
303 return entry; |
0 | 304 } |
305 entry = entry->next(); | |
306 } | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
307 return NULL; |
0 | 308 } |
309 | |
310 | |
311 // add a new entry to hashmap | |
312 inline void add(oop key, JvmtiTagHashmapEntry* entry) { | |
313 assert(key != NULL, "checking"); | |
314 assert(find(key) == NULL, "duplicate detected"); | |
315 unsigned int h = hash(key); | |
316 JvmtiTagHashmapEntry* anchor = _table[h]; | |
317 if (anchor == NULL) { | |
318 _table[h] = entry; | |
319 entry->set_next(NULL); | |
320 } else { | |
321 entry->set_next(anchor); | |
322 _table[h] = entry; | |
323 } | |
324 | |
325 _entry_count++; | |
326 if (trace_threshold() > 0 && entry_count() >= trace_threshold()) { | |
327 assert(TraceJVMTIObjectTagging, "should only get here when tracing"); | |
328 print_memory_usage(); | |
329 compute_next_trace_threshold(); | |
330 } | |
331 | |
332 // if the number of entries exceed the threshold then resize | |
333 if (entry_count() > resize_threshold() && is_resizing_enabled()) { | |
334 resize(); | |
335 } | |
336 } | |
337 | |
338 // remove an entry with the given key. | |
339 inline JvmtiTagHashmapEntry* remove(oop key) { | |
340 unsigned int h = hash(key); | |
341 JvmtiTagHashmapEntry* entry = _table[h]; | |
342 JvmtiTagHashmapEntry* prev = NULL; | |
343 while (entry != NULL) { | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
344 if (key == entry->object()) { |
0 | 345 break; |
346 } | |
347 prev = entry; | |
348 entry = entry->next(); | |
349 } | |
350 if (entry != NULL) { | |
351 remove(prev, h, entry); | |
352 } | |
353 return entry; | |
354 } | |
355 | |
356 // iterate over all entries in the hashmap | |
357 void entry_iterate(JvmtiTagHashmapEntryClosure* closure); | |
358 }; | |
359 | |
360 // possible hashmap sizes - odd primes that roughly double in size. | |
361 // To avoid excessive resizing the odd primes from 4801-76831 and | |
362 // 76831-307261 have been removed. The list must be terminated by -1. | |
363 int JvmtiTagHashmap::_sizes[] = { 4801, 76831, 307261, 614563, 1228891, | |
364 2457733, 4915219, 9830479, 19660831, 39321619, 78643219, -1 }; | |
365 | |
366 | |
367 // A supporting class for iterating over all entries in Hashmap | |
368 class JvmtiTagHashmapEntryClosure { | |
369 public: | |
370 virtual void do_entry(JvmtiTagHashmapEntry* entry) = 0; | |
371 }; | |
372 | |
373 | |
374 // iterate over all entries in the hashmap | |
375 void JvmtiTagHashmap::entry_iterate(JvmtiTagHashmapEntryClosure* closure) { | |
376 for (int i=0; i<_size; i++) { | |
377 JvmtiTagHashmapEntry* entry = _table[i]; | |
378 JvmtiTagHashmapEntry* prev = NULL; | |
379 while (entry != NULL) { | |
380 // obtain the next entry before invoking do_entry - this is | |
381 // necessary because do_entry may remove the entry from the | |
382 // hashmap. | |
383 JvmtiTagHashmapEntry* next = entry->next(); | |
384 closure->do_entry(entry); | |
385 entry = next; | |
386 } | |
387 } | |
388 } | |
389 | |
390 // debugging | |
391 void JvmtiTagHashmap::print_memory_usage() { | |
392 intptr_t p = (intptr_t)this; | |
393 tty->print("[JvmtiTagHashmap @ " INTPTR_FORMAT, p); | |
394 | |
395 // table + entries in KB | |
396 int hashmap_usage = (size()*sizeof(JvmtiTagHashmapEntry*) + | |
397 entry_count()*sizeof(JvmtiTagHashmapEntry))/K; | |
398 | |
399 int weak_globals_usage = (int)(JNIHandles::weak_global_handle_memory_usage()/K); | |
400 tty->print_cr(", %d entries (%d KB) <JNI weak globals: %d KB>]", | |
401 entry_count(), hashmap_usage, weak_globals_usage); | |
402 } | |
403 | |
404 // compute threshold for the next trace message | |
405 void JvmtiTagHashmap::compute_next_trace_threshold() { | |
406 if (trace_threshold() < medium_trace_threshold) { | |
407 _trace_threshold += small_trace_threshold; | |
408 } else { | |
409 if (trace_threshold() < large_trace_threshold) { | |
410 _trace_threshold += medium_trace_threshold; | |
411 } else { | |
412 _trace_threshold += large_trace_threshold; | |
413 } | |
414 } | |
415 } | |
416 | |
417 // create a JvmtiTagMap | |
418 JvmtiTagMap::JvmtiTagMap(JvmtiEnv* env) : | |
419 _env(env), | |
420 _lock(Mutex::nonleaf+2, "JvmtiTagMap._lock", false), | |
421 _free_entries(NULL), | |
422 _free_entries_count(0) | |
423 { | |
424 assert(JvmtiThreadState_lock->is_locked(), "sanity check"); | |
425 assert(((JvmtiEnvBase *)env)->tag_map() == NULL, "tag map already exists for environment"); | |
426 | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
427 _hashmap = new JvmtiTagHashmap(); |
0 | 428 |
429 // finally add us to the environment | |
430 ((JvmtiEnvBase *)env)->set_tag_map(this); | |
431 } | |
432 | |
433 | |
434 // destroy a JvmtiTagMap | |
435 JvmtiTagMap::~JvmtiTagMap() { | |
436 | |
437 // no lock acquired as we assume the enclosing environment is | |
438 // also being destroryed. | |
439 ((JvmtiEnvBase *)_env)->set_tag_map(NULL); | |
440 | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
441 JvmtiTagHashmapEntry** table = _hashmap->table(); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
442 for (int j = 0; j < _hashmap->size(); j++) { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
443 JvmtiTagHashmapEntry* entry = table[j]; |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
444 while (entry != NULL) { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
445 JvmtiTagHashmapEntry* next = entry->next(); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
446 delete entry; |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
447 entry = next; |
0 | 448 } |
449 } | |
450 | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
451 // finally destroy the hashmap |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
452 delete _hashmap; |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
453 _hashmap = NULL; |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
454 |
0 | 455 // remove any entries on the free list |
456 JvmtiTagHashmapEntry* entry = _free_entries; | |
457 while (entry != NULL) { | |
458 JvmtiTagHashmapEntry* next = entry->next(); | |
459 delete entry; | |
460 entry = next; | |
461 } | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
462 _free_entries = NULL; |
0 | 463 } |
464 | |
465 // create a hashmap entry | |
466 // - if there's an entry on the (per-environment) free list then this | |
467 // is returned. Otherwise an new entry is allocated. | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
468 JvmtiTagHashmapEntry* JvmtiTagMap::create_entry(oop ref, jlong tag) { |
0 | 469 assert(Thread::current()->is_VM_thread() || is_locked(), "checking"); |
470 JvmtiTagHashmapEntry* entry; | |
471 if (_free_entries == NULL) { | |
472 entry = new JvmtiTagHashmapEntry(ref, tag); | |
473 } else { | |
474 assert(_free_entries_count > 0, "mismatched _free_entries_count"); | |
475 _free_entries_count--; | |
476 entry = _free_entries; | |
477 _free_entries = entry->next(); | |
478 entry->init(ref, tag); | |
479 } | |
480 return entry; | |
481 } | |
482 | |
483 // destroy an entry by returning it to the free list | |
484 void JvmtiTagMap::destroy_entry(JvmtiTagHashmapEntry* entry) { | |
485 assert(SafepointSynchronize::is_at_safepoint() || is_locked(), "checking"); | |
486 // limit the size of the free list | |
487 if (_free_entries_count >= max_free_entries) { | |
488 delete entry; | |
489 } else { | |
490 entry->set_next(_free_entries); | |
491 _free_entries = entry; | |
492 _free_entries_count++; | |
493 } | |
494 } | |
495 | |
496 // returns the tag map for the given environments. If the tag map | |
497 // doesn't exist then it is created. | |
498 JvmtiTagMap* JvmtiTagMap::tag_map_for(JvmtiEnv* env) { | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
499 JvmtiTagMap* tag_map = ((JvmtiEnvBase*)env)->tag_map(); |
0 | 500 if (tag_map == NULL) { |
501 MutexLocker mu(JvmtiThreadState_lock); | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
502 tag_map = ((JvmtiEnvBase*)env)->tag_map(); |
0 | 503 if (tag_map == NULL) { |
504 tag_map = new JvmtiTagMap(env); | |
505 } | |
506 } else { | |
507 CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); | |
508 } | |
509 return tag_map; | |
510 } | |
511 | |
512 // iterate over all entries in the tag map. | |
513 void JvmtiTagMap::entry_iterate(JvmtiTagHashmapEntryClosure* closure) { | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
514 hashmap()->entry_iterate(closure); |
0 | 515 } |
516 | |
517 // returns true if the hashmaps are empty | |
518 bool JvmtiTagMap::is_empty() { | |
519 assert(SafepointSynchronize::is_at_safepoint() || is_locked(), "checking"); | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
520 return hashmap()->entry_count() == 0; |
0 | 521 } |
522 | |
523 | |
524 // Return the tag value for an object, or 0 if the object is | |
525 // not tagged | |
526 // | |
527 static inline jlong tag_for(JvmtiTagMap* tag_map, oop o) { | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
528 JvmtiTagHashmapEntry* entry = tag_map->hashmap()->find(o); |
0 | 529 if (entry == NULL) { |
530 return 0; | |
531 } else { | |
532 return entry->tag(); | |
533 } | |
534 } | |
535 | |
536 // If the object is a java.lang.Class then return the klassOop, | |
537 // otherwise return the original object | |
538 static inline oop klassOop_if_java_lang_Class(oop o) { | |
1142 | 539 if (o->klass() == SystemDictionary::Class_klass()) { |
0 | 540 if (!java_lang_Class::is_primitive(o)) { |
541 o = (oop)java_lang_Class::as_klassOop(o); | |
542 assert(o != NULL, "class for non-primitive mirror must exist"); | |
543 } | |
544 } | |
545 return o; | |
546 } | |
547 | |
548 // A CallbackWrapper is a support class for querying and tagging an object | |
549 // around a callback to a profiler. The constructor does pre-callback | |
550 // work to get the tag value, klass tag value, ... and the destructor | |
551 // does the post-callback work of tagging or untagging the object. | |
552 // | |
553 // { | |
554 // CallbackWrapper wrapper(tag_map, o); | |
555 // | |
556 // (*callback)(wrapper.klass_tag(), wrapper.obj_size(), wrapper.obj_tag_p(), ...) | |
557 // | |
558 // } // wrapper goes out of scope here which results in the destructor | |
559 // checking to see if the object has been tagged, untagged, or the | |
560 // tag value has changed. | |
561 // | |
562 class CallbackWrapper : public StackObj { | |
563 private: | |
564 JvmtiTagMap* _tag_map; | |
565 JvmtiTagHashmap* _hashmap; | |
566 JvmtiTagHashmapEntry* _entry; | |
567 oop _o; | |
568 jlong _obj_size; | |
569 jlong _obj_tag; | |
570 klassOop _klass; // the object's class | |
571 jlong _klass_tag; | |
572 | |
573 protected: | |
574 JvmtiTagMap* tag_map() const { return _tag_map; } | |
575 | |
576 // invoked post-callback to tag, untag, or update the tag of an object | |
577 void inline post_callback_tag_update(oop o, JvmtiTagHashmap* hashmap, | |
578 JvmtiTagHashmapEntry* entry, jlong obj_tag); | |
579 public: | |
580 CallbackWrapper(JvmtiTagMap* tag_map, oop o) { | |
581 assert(Thread::current()->is_VM_thread() || tag_map->is_locked(), | |
582 "MT unsafe or must be VM thread"); | |
583 | |
584 // for Classes the klassOop is tagged | |
585 _o = klassOop_if_java_lang_Class(o); | |
586 | |
587 // object size | |
588 _obj_size = _o->size() * wordSize; | |
589 | |
590 // record the context | |
591 _tag_map = tag_map; | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
592 _hashmap = tag_map->hashmap(); |
0 | 593 _entry = _hashmap->find(_o); |
594 | |
595 // get object tag | |
596 _obj_tag = (_entry == NULL) ? 0 : _entry->tag(); | |
597 | |
598 // get the class and the class's tag value | |
599 if (_o == o) { | |
600 _klass = _o->klass(); | |
601 } else { | |
602 // if the object represents a runtime class then use the | |
603 // tag for java.lang.Class | |
1142 | 604 _klass = SystemDictionary::Class_klass(); |
0 | 605 } |
606 _klass_tag = tag_for(tag_map, _klass); | |
607 } | |
608 | |
609 ~CallbackWrapper() { | |
610 post_callback_tag_update(_o, _hashmap, _entry, _obj_tag); | |
611 } | |
612 | |
613 inline jlong* obj_tag_p() { return &_obj_tag; } | |
614 inline jlong obj_size() const { return _obj_size; } | |
615 inline jlong obj_tag() const { return _obj_tag; } | |
616 inline klassOop klass() const { return _klass; } | |
617 inline jlong klass_tag() const { return _klass_tag; } | |
618 }; | |
619 | |
620 | |
621 | |
622 // callback post-callback to tag, untag, or update the tag of an object | |
623 void inline CallbackWrapper::post_callback_tag_update(oop o, | |
624 JvmtiTagHashmap* hashmap, | |
625 JvmtiTagHashmapEntry* entry, | |
626 jlong obj_tag) { | |
627 if (entry == NULL) { | |
628 if (obj_tag != 0) { | |
629 // callback has tagged the object | |
630 assert(Thread::current()->is_VM_thread(), "must be VMThread"); | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
631 entry = tag_map()->create_entry(o, obj_tag); |
0 | 632 hashmap->add(o, entry); |
633 } | |
634 } else { | |
635 // object was previously tagged - the callback may have untagged | |
636 // the object or changed the tag value | |
637 if (obj_tag == 0) { | |
638 | |
639 JvmtiTagHashmapEntry* entry_removed = hashmap->remove(o); | |
640 assert(entry_removed == entry, "checking"); | |
641 tag_map()->destroy_entry(entry); | |
642 | |
643 } else { | |
644 if (obj_tag != entry->tag()) { | |
645 entry->set_tag(obj_tag); | |
646 } | |
647 } | |
648 } | |
649 } | |
650 | |
651 // An extended CallbackWrapper used when reporting an object reference | |
652 // to the agent. | |
653 // | |
654 // { | |
655 // TwoOopCallbackWrapper wrapper(tag_map, referrer, o); | |
656 // | |
657 // (*callback)(wrapper.klass_tag(), | |
658 // wrapper.obj_size(), | |
659 // wrapper.obj_tag_p() | |
660 // wrapper.referrer_tag_p(), ...) | |
661 // | |
662 // } // wrapper goes out of scope here which results in the destructor | |
663 // checking to see if the referrer object has been tagged, untagged, | |
664 // or the tag value has changed. | |
665 // | |
666 class TwoOopCallbackWrapper : public CallbackWrapper { | |
667 private: | |
668 bool _is_reference_to_self; | |
669 JvmtiTagHashmap* _referrer_hashmap; | |
670 JvmtiTagHashmapEntry* _referrer_entry; | |
671 oop _referrer; | |
672 jlong _referrer_obj_tag; | |
673 jlong _referrer_klass_tag; | |
674 jlong* _referrer_tag_p; | |
675 | |
676 bool is_reference_to_self() const { return _is_reference_to_self; } | |
677 | |
678 public: | |
679 TwoOopCallbackWrapper(JvmtiTagMap* tag_map, oop referrer, oop o) : | |
680 CallbackWrapper(tag_map, o) | |
681 { | |
682 // self reference needs to be handled in a special way | |
683 _is_reference_to_self = (referrer == o); | |
684 | |
685 if (_is_reference_to_self) { | |
686 _referrer_klass_tag = klass_tag(); | |
687 _referrer_tag_p = obj_tag_p(); | |
688 } else { | |
689 // for Classes the klassOop is tagged | |
690 _referrer = klassOop_if_java_lang_Class(referrer); | |
691 // record the context | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
692 _referrer_hashmap = tag_map->hashmap(); |
0 | 693 _referrer_entry = _referrer_hashmap->find(_referrer); |
694 | |
695 // get object tag | |
696 _referrer_obj_tag = (_referrer_entry == NULL) ? 0 : _referrer_entry->tag(); | |
697 _referrer_tag_p = &_referrer_obj_tag; | |
698 | |
699 // get referrer class tag. | |
700 klassOop k = (_referrer == referrer) ? // Check if referrer is a class... | |
701 _referrer->klass() // No, just get its class | |
1142 | 702 : SystemDictionary::Class_klass(); // Yes, its class is Class |
0 | 703 _referrer_klass_tag = tag_for(tag_map, k); |
704 } | |
705 } | |
706 | |
707 ~TwoOopCallbackWrapper() { | |
708 if (!is_reference_to_self()){ | |
709 post_callback_tag_update(_referrer, | |
710 _referrer_hashmap, | |
711 _referrer_entry, | |
712 _referrer_obj_tag); | |
713 } | |
714 } | |
715 | |
716 // address of referrer tag | |
717 // (for a self reference this will return the same thing as obj_tag_p()) | |
718 inline jlong* referrer_tag_p() { return _referrer_tag_p; } | |
719 | |
720 // referrer's class tag | |
721 inline jlong referrer_klass_tag() { return _referrer_klass_tag; } | |
722 }; | |
723 | |
724 // tag an object | |
725 // | |
726 // This function is performance critical. If many threads attempt to tag objects | |
727 // around the same time then it's possible that the Mutex associated with the | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
728 // tag map will be a hot lock. |
0 | 729 void JvmtiTagMap::set_tag(jobject object, jlong tag) { |
730 MutexLocker ml(lock()); | |
731 | |
732 // resolve the object | |
733 oop o = JNIHandles::resolve_non_null(object); | |
734 | |
735 // for Classes we tag the klassOop | |
736 o = klassOop_if_java_lang_Class(o); | |
737 | |
738 // see if the object is already tagged | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
739 JvmtiTagHashmap* hashmap = _hashmap; |
0 | 740 JvmtiTagHashmapEntry* entry = hashmap->find(o); |
741 | |
742 // if the object is not already tagged then we tag it | |
743 if (entry == NULL) { | |
744 if (tag != 0) { | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
745 entry = create_entry(o, tag); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
746 hashmap->add(o, entry); |
0 | 747 } else { |
748 // no-op | |
749 } | |
750 } else { | |
751 // if the object is already tagged then we either update | |
752 // the tag (if a new tag value has been provided) | |
753 // or remove the object if the new tag value is 0. | |
754 if (tag == 0) { | |
755 hashmap->remove(o); | |
756 destroy_entry(entry); | |
757 } else { | |
758 entry->set_tag(tag); | |
759 } | |
760 } | |
761 } | |
762 | |
763 // get the tag for an object | |
764 jlong JvmtiTagMap::get_tag(jobject object) { | |
765 MutexLocker ml(lock()); | |
766 | |
767 // resolve the object | |
768 oop o = JNIHandles::resolve_non_null(object); | |
769 | |
770 // for Classes get the tag from the klassOop | |
771 return tag_for(this, klassOop_if_java_lang_Class(o)); | |
772 } | |
773 | |
774 | |
775 // Helper class used to describe the static or instance fields of a class. | |
776 // For each field it holds the field index (as defined by the JVMTI specification), | |
777 // the field type, and the offset. | |
778 | |
779 class ClassFieldDescriptor: public CHeapObj { | |
780 private: | |
781 int _field_index; | |
782 int _field_offset; | |
783 char _field_type; | |
784 public: | |
785 ClassFieldDescriptor(int index, char type, int offset) : | |
786 _field_index(index), _field_type(type), _field_offset(offset) { | |
787 } | |
788 int field_index() const { return _field_index; } | |
789 char field_type() const { return _field_type; } | |
790 int field_offset() const { return _field_offset; } | |
791 }; | |
792 | |
793 class ClassFieldMap: public CHeapObj { | |
794 private: | |
795 enum { | |
796 initial_field_count = 5 | |
797 }; | |
798 | |
799 // list of field descriptors | |
800 GrowableArray<ClassFieldDescriptor*>* _fields; | |
801 | |
802 // constructor | |
803 ClassFieldMap(); | |
804 | |
805 // add a field | |
806 void add(int index, char type, int offset); | |
807 | |
808 // returns the field count for the given class | |
809 static int compute_field_count(instanceKlassHandle ikh); | |
810 | |
811 public: | |
812 ~ClassFieldMap(); | |
813 | |
814 // access | |
815 int field_count() { return _fields->length(); } | |
816 ClassFieldDescriptor* field_at(int i) { return _fields->at(i); } | |
817 | |
818 // functions to create maps of static or instance fields | |
819 static ClassFieldMap* create_map_of_static_fields(klassOop k); | |
820 static ClassFieldMap* create_map_of_instance_fields(oop obj); | |
821 }; | |
822 | |
823 ClassFieldMap::ClassFieldMap() { | |
824 _fields = new (ResourceObj::C_HEAP) GrowableArray<ClassFieldDescriptor*>(initial_field_count, true); | |
825 } | |
826 | |
827 ClassFieldMap::~ClassFieldMap() { | |
828 for (int i=0; i<_fields->length(); i++) { | |
829 delete _fields->at(i); | |
830 } | |
831 delete _fields; | |
832 } | |
833 | |
834 void ClassFieldMap::add(int index, char type, int offset) { | |
835 ClassFieldDescriptor* field = new ClassFieldDescriptor(index, type, offset); | |
836 _fields->append(field); | |
837 } | |
838 | |
839 // Returns a heap allocated ClassFieldMap to describe the static fields | |
840 // of the given class. | |
841 // | |
842 ClassFieldMap* ClassFieldMap::create_map_of_static_fields(klassOop k) { | |
843 HandleMark hm; | |
844 instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k); | |
845 | |
846 // create the field map | |
847 ClassFieldMap* field_map = new ClassFieldMap(); | |
848 | |
849 FilteredFieldStream f(ikh, false, false); | |
850 int max_field_index = f.field_count()-1; | |
851 | |
852 int index = 0; | |
853 for (FilteredFieldStream fld(ikh, true, true); !fld.eos(); fld.next(), index++) { | |
854 // ignore instance fields | |
855 if (!fld.access_flags().is_static()) { | |
856 continue; | |
857 } | |
858 field_map->add(max_field_index - index, fld.signature()->byte_at(0), fld.offset()); | |
859 } | |
860 return field_map; | |
861 } | |
862 | |
863 // Returns a heap allocated ClassFieldMap to describe the instance fields | |
864 // of the given class. All instance fields are included (this means public | |
865 // and private fields declared in superclasses and superinterfaces too). | |
866 // | |
867 ClassFieldMap* ClassFieldMap::create_map_of_instance_fields(oop obj) { | |
868 HandleMark hm; | |
869 instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), obj->klass()); | |
870 | |
871 // create the field map | |
872 ClassFieldMap* field_map = new ClassFieldMap(); | |
873 | |
874 FilteredFieldStream f(ikh, false, false); | |
875 | |
876 int max_field_index = f.field_count()-1; | |
877 | |
878 int index = 0; | |
879 for (FilteredFieldStream fld(ikh, false, false); !fld.eos(); fld.next(), index++) { | |
880 // ignore static fields | |
881 if (fld.access_flags().is_static()) { | |
882 continue; | |
883 } | |
884 field_map->add(max_field_index - index, fld.signature()->byte_at(0), fld.offset()); | |
885 } | |
886 | |
887 return field_map; | |
888 } | |
889 | |
890 // Helper class used to cache a ClassFileMap for the instance fields of | |
891 // a cache. A JvmtiCachedClassFieldMap can be cached by an instanceKlass during | |
892 // heap iteration and avoid creating a field map for each object in the heap | |
893 // (only need to create the map when the first instance of a class is encountered). | |
894 // | |
895 class JvmtiCachedClassFieldMap : public CHeapObj { | |
896 private: | |
897 enum { | |
898 initial_class_count = 200 | |
899 }; | |
900 ClassFieldMap* _field_map; | |
901 | |
902 ClassFieldMap* field_map() const { return _field_map; } | |
903 | |
904 JvmtiCachedClassFieldMap(ClassFieldMap* field_map); | |
905 ~JvmtiCachedClassFieldMap(); | |
906 | |
907 static GrowableArray<instanceKlass*>* _class_list; | |
908 static void add_to_class_list(instanceKlass* ik); | |
909 | |
910 public: | |
911 // returns the field map for a given object (returning map cached | |
912 // by instanceKlass if possible | |
913 static ClassFieldMap* get_map_of_instance_fields(oop obj); | |
914 | |
915 // removes the field map from all instanceKlasses - should be | |
916 // called before VM operation completes | |
917 static void clear_cache(); | |
918 | |
919 // returns the number of ClassFieldMap cached by instanceKlasses | |
920 static int cached_field_map_count(); | |
921 }; | |
922 | |
923 GrowableArray<instanceKlass*>* JvmtiCachedClassFieldMap::_class_list; | |
924 | |
925 JvmtiCachedClassFieldMap::JvmtiCachedClassFieldMap(ClassFieldMap* field_map) { | |
926 _field_map = field_map; | |
927 } | |
928 | |
929 JvmtiCachedClassFieldMap::~JvmtiCachedClassFieldMap() { | |
930 if (_field_map != NULL) { | |
931 delete _field_map; | |
932 } | |
933 } | |
934 | |
935 // Marker class to ensure that the class file map cache is only used in a defined | |
936 // scope. | |
937 class ClassFieldMapCacheMark : public StackObj { | |
938 private: | |
939 static bool _is_active; | |
940 public: | |
941 ClassFieldMapCacheMark() { | |
942 assert(Thread::current()->is_VM_thread(), "must be VMThread"); | |
943 assert(JvmtiCachedClassFieldMap::cached_field_map_count() == 0, "cache not empty"); | |
944 assert(!_is_active, "ClassFieldMapCacheMark cannot be nested"); | |
945 _is_active = true; | |
946 } | |
947 ~ClassFieldMapCacheMark() { | |
948 JvmtiCachedClassFieldMap::clear_cache(); | |
949 _is_active = false; | |
950 } | |
951 static bool is_active() { return _is_active; } | |
952 }; | |
953 | |
954 bool ClassFieldMapCacheMark::_is_active; | |
955 | |
956 | |
957 // record that the given instanceKlass is caching a field map | |
958 void JvmtiCachedClassFieldMap::add_to_class_list(instanceKlass* ik) { | |
959 if (_class_list == NULL) { | |
960 _class_list = new (ResourceObj::C_HEAP) GrowableArray<instanceKlass*>(initial_class_count, true); | |
961 } | |
962 _class_list->push(ik); | |
963 } | |
964 | |
965 // returns the instance field map for the given object | |
966 // (returns field map cached by the instanceKlass if possible) | |
967 ClassFieldMap* JvmtiCachedClassFieldMap::get_map_of_instance_fields(oop obj) { | |
968 assert(Thread::current()->is_VM_thread(), "must be VMThread"); | |
969 assert(ClassFieldMapCacheMark::is_active(), "ClassFieldMapCacheMark not active"); | |
970 | |
971 klassOop k = obj->klass(); | |
972 instanceKlass* ik = instanceKlass::cast(k); | |
973 | |
974 // return cached map if possible | |
975 JvmtiCachedClassFieldMap* cached_map = ik->jvmti_cached_class_field_map(); | |
976 if (cached_map != NULL) { | |
977 assert(cached_map->field_map() != NULL, "missing field list"); | |
978 return cached_map->field_map(); | |
979 } else { | |
980 ClassFieldMap* field_map = ClassFieldMap::create_map_of_instance_fields(obj); | |
981 cached_map = new JvmtiCachedClassFieldMap(field_map); | |
982 ik->set_jvmti_cached_class_field_map(cached_map); | |
983 add_to_class_list(ik); | |
984 return field_map; | |
985 } | |
986 } | |
987 | |
988 // remove the fields maps cached from all instanceKlasses | |
989 void JvmtiCachedClassFieldMap::clear_cache() { | |
990 assert(Thread::current()->is_VM_thread(), "must be VMThread"); | |
991 if (_class_list != NULL) { | |
992 for (int i = 0; i < _class_list->length(); i++) { | |
993 instanceKlass* ik = _class_list->at(i); | |
994 JvmtiCachedClassFieldMap* cached_map = ik->jvmti_cached_class_field_map(); | |
995 assert(cached_map != NULL, "should not be NULL"); | |
996 ik->set_jvmti_cached_class_field_map(NULL); | |
997 delete cached_map; // deletes the encapsulated field map | |
998 } | |
999 delete _class_list; | |
1000 _class_list = NULL; | |
1001 } | |
1002 } | |
1003 | |
1004 // returns the number of ClassFieldMap cached by instanceKlasses | |
1005 int JvmtiCachedClassFieldMap::cached_field_map_count() { | |
1006 return (_class_list == NULL) ? 0 : _class_list->length(); | |
1007 } | |
1008 | |
1009 // helper function to indicate if an object is filtered by its tag or class tag | |
1010 static inline bool is_filtered_by_heap_filter(jlong obj_tag, | |
1011 jlong klass_tag, | |
1012 int heap_filter) { | |
1013 // apply the heap filter | |
1014 if (obj_tag != 0) { | |
1015 // filter out tagged objects | |
1016 if (heap_filter & JVMTI_HEAP_FILTER_TAGGED) return true; | |
1017 } else { | |
1018 // filter out untagged objects | |
1019 if (heap_filter & JVMTI_HEAP_FILTER_UNTAGGED) return true; | |
1020 } | |
1021 if (klass_tag != 0) { | |
1022 // filter out objects with tagged classes | |
1023 if (heap_filter & JVMTI_HEAP_FILTER_CLASS_TAGGED) return true; | |
1024 } else { | |
1025 // filter out objects with untagged classes. | |
1026 if (heap_filter & JVMTI_HEAP_FILTER_CLASS_UNTAGGED) return true; | |
1027 } | |
1028 return false; | |
1029 } | |
1030 | |
1031 // helper function to indicate if an object is filtered by a klass filter | |
1032 static inline bool is_filtered_by_klass_filter(oop obj, KlassHandle klass_filter) { | |
1033 if (!klass_filter.is_null()) { | |
1034 if (obj->klass() != klass_filter()) { | |
1035 return true; | |
1036 } | |
1037 } | |
1038 return false; | |
1039 } | |
1040 | |
1041 // helper function to tell if a field is a primitive field or not | |
1042 static inline bool is_primitive_field_type(char type) { | |
1043 return (type != 'L' && type != '['); | |
1044 } | |
1045 | |
1046 // helper function to copy the value from location addr to jvalue. | |
1047 static inline void copy_to_jvalue(jvalue *v, address addr, jvmtiPrimitiveType value_type) { | |
1048 switch (value_type) { | |
1049 case JVMTI_PRIMITIVE_TYPE_BOOLEAN : { v->z = *(jboolean*)addr; break; } | |
1050 case JVMTI_PRIMITIVE_TYPE_BYTE : { v->b = *(jbyte*)addr; break; } | |
1051 case JVMTI_PRIMITIVE_TYPE_CHAR : { v->c = *(jchar*)addr; break; } | |
1052 case JVMTI_PRIMITIVE_TYPE_SHORT : { v->s = *(jshort*)addr; break; } | |
1053 case JVMTI_PRIMITIVE_TYPE_INT : { v->i = *(jint*)addr; break; } | |
1054 case JVMTI_PRIMITIVE_TYPE_LONG : { v->j = *(jlong*)addr; break; } | |
1055 case JVMTI_PRIMITIVE_TYPE_FLOAT : { v->f = *(jfloat*)addr; break; } | |
1056 case JVMTI_PRIMITIVE_TYPE_DOUBLE : { v->d = *(jdouble*)addr; break; } | |
1057 default: ShouldNotReachHere(); | |
1058 } | |
1059 } | |
1060 | |
1061 // helper function to invoke string primitive value callback | |
1062 // returns visit control flags | |
1063 static jint invoke_string_value_callback(jvmtiStringPrimitiveValueCallback cb, | |
1064 CallbackWrapper* wrapper, | |
1065 oop str, | |
1066 void* user_data) | |
1067 { | |
1142 | 1068 assert(str->klass() == SystemDictionary::String_klass(), "not a string"); |
0 | 1069 |
1070 // get the string value and length | |
1071 // (string value may be offset from the base) | |
1072 int s_len = java_lang_String::length(str); | |
1073 typeArrayOop s_value = java_lang_String::value(str); | |
1074 int s_offset = java_lang_String::offset(str); | |
1075 jchar* value; | |
1076 if (s_len > 0) { | |
1077 value = s_value->char_at_addr(s_offset); | |
1078 } else { | |
1079 value = (jchar*) s_value->base(T_CHAR); | |
1080 } | |
1081 | |
1082 // invoke the callback | |
1083 return (*cb)(wrapper->klass_tag(), | |
1084 wrapper->obj_size(), | |
1085 wrapper->obj_tag_p(), | |
1086 value, | |
1087 (jint)s_len, | |
1088 user_data); | |
1089 } | |
1090 | |
1091 // helper function to invoke string primitive value callback | |
1092 // returns visit control flags | |
1093 static jint invoke_array_primitive_value_callback(jvmtiArrayPrimitiveValueCallback cb, | |
1094 CallbackWrapper* wrapper, | |
1095 oop obj, | |
1096 void* user_data) | |
1097 { | |
1098 assert(obj->is_typeArray(), "not a primitive array"); | |
1099 | |
1100 // get base address of first element | |
1101 typeArrayOop array = typeArrayOop(obj); | |
1102 BasicType type = typeArrayKlass::cast(array->klass())->element_type(); | |
1103 void* elements = array->base(type); | |
1104 | |
1105 // jvmtiPrimitiveType is defined so this mapping is always correct | |
1106 jvmtiPrimitiveType elem_type = (jvmtiPrimitiveType)type2char(type); | |
1107 | |
1108 return (*cb)(wrapper->klass_tag(), | |
1109 wrapper->obj_size(), | |
1110 wrapper->obj_tag_p(), | |
1111 (jint)array->length(), | |
1112 elem_type, | |
1113 elements, | |
1114 user_data); | |
1115 } | |
1116 | |
1117 // helper function to invoke the primitive field callback for all static fields | |
1118 // of a given class | |
1119 static jint invoke_primitive_field_callback_for_static_fields | |
1120 (CallbackWrapper* wrapper, | |
1121 oop obj, | |
1122 jvmtiPrimitiveFieldCallback cb, | |
1123 void* user_data) | |
1124 { | |
1125 // for static fields only the index will be set | |
1126 static jvmtiHeapReferenceInfo reference_info = { 0 }; | |
1127 | |
1142 | 1128 assert(obj->klass() == SystemDictionary::Class_klass(), "not a class"); |
0 | 1129 if (java_lang_Class::is_primitive(obj)) { |
1130 return 0; | |
1131 } | |
1132 klassOop k = java_lang_Class::as_klassOop(obj); | |
1133 Klass* klass = k->klass_part(); | |
1134 | |
1135 // ignore classes for object and type arrays | |
1136 if (!klass->oop_is_instance()) { | |
1137 return 0; | |
1138 } | |
1139 | |
1140 // ignore classes which aren't linked yet | |
1141 instanceKlass* ik = instanceKlass::cast(k); | |
1142 if (!ik->is_linked()) { | |
1143 return 0; | |
1144 } | |
1145 | |
1146 // get the field map | |
1147 ClassFieldMap* field_map = ClassFieldMap::create_map_of_static_fields(k); | |
1148 | |
1149 // invoke the callback for each static primitive field | |
1150 for (int i=0; i<field_map->field_count(); i++) { | |
1151 ClassFieldDescriptor* field = field_map->field_at(i); | |
1152 | |
1153 // ignore non-primitive fields | |
1154 char type = field->field_type(); | |
1155 if (!is_primitive_field_type(type)) { | |
1156 continue; | |
1157 } | |
1158 // one-to-one mapping | |
1159 jvmtiPrimitiveType value_type = (jvmtiPrimitiveType)type; | |
1160 | |
1161 // get offset and field value | |
1162 int offset = field->field_offset(); | |
1163 address addr = (address)k + offset; | |
1164 jvalue value; | |
1165 copy_to_jvalue(&value, addr, value_type); | |
1166 | |
1167 // field index | |
1168 reference_info.field.index = field->field_index(); | |
1169 | |
1170 // invoke the callback | |
1171 jint res = (*cb)(JVMTI_HEAP_REFERENCE_STATIC_FIELD, | |
1172 &reference_info, | |
1173 wrapper->klass_tag(), | |
1174 wrapper->obj_tag_p(), | |
1175 value, | |
1176 value_type, | |
1177 user_data); | |
1178 if (res & JVMTI_VISIT_ABORT) { | |
1179 delete field_map; | |
1180 return res; | |
1181 } | |
1182 } | |
1183 | |
1184 delete field_map; | |
1185 return 0; | |
1186 } | |
1187 | |
1188 // helper function to invoke the primitive field callback for all instance fields | |
1189 // of a given object | |
1190 static jint invoke_primitive_field_callback_for_instance_fields( | |
1191 CallbackWrapper* wrapper, | |
1192 oop obj, | |
1193 jvmtiPrimitiveFieldCallback cb, | |
1194 void* user_data) | |
1195 { | |
1196 // for instance fields only the index will be set | |
1197 static jvmtiHeapReferenceInfo reference_info = { 0 }; | |
1198 | |
1199 // get the map of the instance fields | |
1200 ClassFieldMap* fields = JvmtiCachedClassFieldMap::get_map_of_instance_fields(obj); | |
1201 | |
1202 // invoke the callback for each instance primitive field | |
1203 for (int i=0; i<fields->field_count(); i++) { | |
1204 ClassFieldDescriptor* field = fields->field_at(i); | |
1205 | |
1206 // ignore non-primitive fields | |
1207 char type = field->field_type(); | |
1208 if (!is_primitive_field_type(type)) { | |
1209 continue; | |
1210 } | |
1211 // one-to-one mapping | |
1212 jvmtiPrimitiveType value_type = (jvmtiPrimitiveType)type; | |
1213 | |
1214 // get offset and field value | |
1215 int offset = field->field_offset(); | |
1216 address addr = (address)obj + offset; | |
1217 jvalue value; | |
1218 copy_to_jvalue(&value, addr, value_type); | |
1219 | |
1220 // field index | |
1221 reference_info.field.index = field->field_index(); | |
1222 | |
1223 // invoke the callback | |
1224 jint res = (*cb)(JVMTI_HEAP_REFERENCE_FIELD, | |
1225 &reference_info, | |
1226 wrapper->klass_tag(), | |
1227 wrapper->obj_tag_p(), | |
1228 value, | |
1229 value_type, | |
1230 user_data); | |
1231 if (res & JVMTI_VISIT_ABORT) { | |
1232 return res; | |
1233 } | |
1234 } | |
1235 return 0; | |
1236 } | |
1237 | |
1238 | |
1239 // VM operation to iterate over all objects in the heap (both reachable | |
1240 // and unreachable) | |
1241 class VM_HeapIterateOperation: public VM_Operation { | |
1242 private: | |
1243 ObjectClosure* _blk; | |
1244 public: | |
1245 VM_HeapIterateOperation(ObjectClosure* blk) { _blk = blk; } | |
1246 | |
1247 VMOp_Type type() const { return VMOp_HeapIterateOperation; } | |
1248 void doit() { | |
1249 // allows class files maps to be cached during iteration | |
1250 ClassFieldMapCacheMark cm; | |
1251 | |
1252 // make sure that heap is parsable (fills TLABs with filler objects) | |
1253 Universe::heap()->ensure_parsability(false); // no need to retire TLABs | |
1254 | |
1255 // Verify heap before iteration - if the heap gets corrupted then | |
1256 // JVMTI's IterateOverHeap will crash. | |
1257 if (VerifyBeforeIteration) { | |
1258 Universe::verify(); | |
1259 } | |
1260 | |
1261 // do the iteration | |
517
e9be0e04635a
6689653: JMapPerm fails with UseConcMarkSweepIncGC and compressed oops off
jmasa
parents:
356
diff
changeset
|
1262 // If this operation encounters a bad object when using CMS, |
e9be0e04635a
6689653: JMapPerm fails with UseConcMarkSweepIncGC and compressed oops off
jmasa
parents:
356
diff
changeset
|
1263 // consider using safe_object_iterate() which avoids perm gen |
e9be0e04635a
6689653: JMapPerm fails with UseConcMarkSweepIncGC and compressed oops off
jmasa
parents:
356
diff
changeset
|
1264 // objects that may contain bad references. |
0 | 1265 Universe::heap()->object_iterate(_blk); |
1266 | |
1267 // when sharing is enabled we must iterate over the shared spaces | |
1268 if (UseSharedSpaces) { | |
1269 GenCollectedHeap* gch = GenCollectedHeap::heap(); | |
1270 CompactingPermGenGen* gen = (CompactingPermGenGen*)gch->perm_gen(); | |
1271 gen->ro_space()->object_iterate(_blk); | |
1272 gen->rw_space()->object_iterate(_blk); | |
1273 } | |
1274 } | |
1275 | |
1276 }; | |
1277 | |
1278 | |
1279 // An ObjectClosure used to support the deprecated IterateOverHeap and | |
1280 // IterateOverInstancesOfClass functions | |
1281 class IterateOverHeapObjectClosure: public ObjectClosure { | |
1282 private: | |
1283 JvmtiTagMap* _tag_map; | |
1284 KlassHandle _klass; | |
1285 jvmtiHeapObjectFilter _object_filter; | |
1286 jvmtiHeapObjectCallback _heap_object_callback; | |
1287 const void* _user_data; | |
1288 | |
1289 // accessors | |
1290 JvmtiTagMap* tag_map() const { return _tag_map; } | |
1291 jvmtiHeapObjectFilter object_filter() const { return _object_filter; } | |
1292 jvmtiHeapObjectCallback object_callback() const { return _heap_object_callback; } | |
1293 KlassHandle klass() const { return _klass; } | |
1294 const void* user_data() const { return _user_data; } | |
1295 | |
1296 // indicates if iteration has been aborted | |
1297 bool _iteration_aborted; | |
1298 bool is_iteration_aborted() const { return _iteration_aborted; } | |
1299 void set_iteration_aborted(bool aborted) { _iteration_aborted = aborted; } | |
1300 | |
1301 public: | |
1302 IterateOverHeapObjectClosure(JvmtiTagMap* tag_map, | |
1303 KlassHandle klass, | |
1304 jvmtiHeapObjectFilter object_filter, | |
1305 jvmtiHeapObjectCallback heap_object_callback, | |
1306 const void* user_data) : | |
1307 _tag_map(tag_map), | |
1308 _klass(klass), | |
1309 _object_filter(object_filter), | |
1310 _heap_object_callback(heap_object_callback), | |
1311 _user_data(user_data), | |
1312 _iteration_aborted(false) | |
1313 { | |
1314 } | |
1315 | |
1316 void do_object(oop o); | |
1317 }; | |
1318 | |
1319 // invoked for each object in the heap | |
1320 void IterateOverHeapObjectClosure::do_object(oop o) { | |
1321 // check if iteration has been halted | |
1322 if (is_iteration_aborted()) return; | |
1323 | |
1324 // ignore any objects that aren't visible to profiler | |
1325 if (!ServiceUtil::visible_oop(o)) return; | |
1326 | |
1327 // instanceof check when filtering by klass | |
1328 if (!klass().is_null() && !o->is_a(klass()())) { | |
1329 return; | |
1330 } | |
1331 // prepare for the calllback | |
1332 CallbackWrapper wrapper(tag_map(), o); | |
1333 | |
1334 // if the object is tagged and we're only interested in untagged objects | |
1335 // then don't invoke the callback. Similiarly, if the object is untagged | |
1336 // and we're only interested in tagged objects we skip the callback. | |
1337 if (wrapper.obj_tag() != 0) { | |
1338 if (object_filter() == JVMTI_HEAP_OBJECT_UNTAGGED) return; | |
1339 } else { | |
1340 if (object_filter() == JVMTI_HEAP_OBJECT_TAGGED) return; | |
1341 } | |
1342 | |
1343 // invoke the agent's callback | |
1344 jvmtiIterationControl control = (*object_callback())(wrapper.klass_tag(), | |
1345 wrapper.obj_size(), | |
1346 wrapper.obj_tag_p(), | |
1347 (void*)user_data()); | |
1348 if (control == JVMTI_ITERATION_ABORT) { | |
1349 set_iteration_aborted(true); | |
1350 } | |
1351 } | |
1352 | |
1353 // An ObjectClosure used to support the IterateThroughHeap function | |
1354 class IterateThroughHeapObjectClosure: public ObjectClosure { | |
1355 private: | |
1356 JvmtiTagMap* _tag_map; | |
1357 KlassHandle _klass; | |
1358 int _heap_filter; | |
1359 const jvmtiHeapCallbacks* _callbacks; | |
1360 const void* _user_data; | |
1361 | |
1362 // accessor functions | |
1363 JvmtiTagMap* tag_map() const { return _tag_map; } | |
1364 int heap_filter() const { return _heap_filter; } | |
1365 const jvmtiHeapCallbacks* callbacks() const { return _callbacks; } | |
1366 KlassHandle klass() const { return _klass; } | |
1367 const void* user_data() const { return _user_data; } | |
1368 | |
1369 // indicates if the iteration has been aborted | |
1370 bool _iteration_aborted; | |
1371 bool is_iteration_aborted() const { return _iteration_aborted; } | |
1372 | |
1373 // used to check the visit control flags. If the abort flag is set | |
1374 // then we set the iteration aborted flag so that the iteration completes | |
1375 // without processing any further objects | |
1376 bool check_flags_for_abort(jint flags) { | |
1377 bool is_abort = (flags & JVMTI_VISIT_ABORT) != 0; | |
1378 if (is_abort) { | |
1379 _iteration_aborted = true; | |
1380 } | |
1381 return is_abort; | |
1382 } | |
1383 | |
1384 public: | |
1385 IterateThroughHeapObjectClosure(JvmtiTagMap* tag_map, | |
1386 KlassHandle klass, | |
1387 int heap_filter, | |
1388 const jvmtiHeapCallbacks* heap_callbacks, | |
1389 const void* user_data) : | |
1390 _tag_map(tag_map), | |
1391 _klass(klass), | |
1392 _heap_filter(heap_filter), | |
1393 _callbacks(heap_callbacks), | |
1394 _user_data(user_data), | |
1395 _iteration_aborted(false) | |
1396 { | |
1397 } | |
1398 | |
1399 void do_object(oop o); | |
1400 }; | |
1401 | |
1402 // invoked for each object in the heap | |
1403 void IterateThroughHeapObjectClosure::do_object(oop obj) { | |
1404 // check if iteration has been halted | |
1405 if (is_iteration_aborted()) return; | |
1406 | |
1407 // ignore any objects that aren't visible to profiler | |
1408 if (!ServiceUtil::visible_oop(obj)) return; | |
1409 | |
1410 // apply class filter | |
1411 if (is_filtered_by_klass_filter(obj, klass())) return; | |
1412 | |
1413 // prepare for callback | |
1414 CallbackWrapper wrapper(tag_map(), obj); | |
1415 | |
1416 // check if filtered by the heap filter | |
1417 if (is_filtered_by_heap_filter(wrapper.obj_tag(), wrapper.klass_tag(), heap_filter())) { | |
1418 return; | |
1419 } | |
1420 | |
1421 // for arrays we need the length, otherwise -1 | |
1422 bool is_array = obj->is_array(); | |
1423 int len = is_array ? arrayOop(obj)->length() : -1; | |
1424 | |
1425 // invoke the object callback (if callback is provided) | |
1426 if (callbacks()->heap_iteration_callback != NULL) { | |
1427 jvmtiHeapIterationCallback cb = callbacks()->heap_iteration_callback; | |
1428 jint res = (*cb)(wrapper.klass_tag(), | |
1429 wrapper.obj_size(), | |
1430 wrapper.obj_tag_p(), | |
1431 (jint)len, | |
1432 (void*)user_data()); | |
1433 if (check_flags_for_abort(res)) return; | |
1434 } | |
1435 | |
1436 // for objects and classes we report primitive fields if callback provided | |
1437 if (callbacks()->primitive_field_callback != NULL && obj->is_instance()) { | |
1438 jint res; | |
1439 jvmtiPrimitiveFieldCallback cb = callbacks()->primitive_field_callback; | |
1142 | 1440 if (obj->klass() == SystemDictionary::Class_klass()) { |
0 | 1441 res = invoke_primitive_field_callback_for_static_fields(&wrapper, |
1442 obj, | |
1443 cb, | |
1444 (void*)user_data()); | |
1445 } else { | |
1446 res = invoke_primitive_field_callback_for_instance_fields(&wrapper, | |
1447 obj, | |
1448 cb, | |
1449 (void*)user_data()); | |
1450 } | |
1451 if (check_flags_for_abort(res)) return; | |
1452 } | |
1453 | |
1454 // string callback | |
1455 if (!is_array && | |
1456 callbacks()->string_primitive_value_callback != NULL && | |
1142 | 1457 obj->klass() == SystemDictionary::String_klass()) { |
0 | 1458 jint res = invoke_string_value_callback( |
1459 callbacks()->string_primitive_value_callback, | |
1460 &wrapper, | |
1461 obj, | |
1462 (void*)user_data() ); | |
1463 if (check_flags_for_abort(res)) return; | |
1464 } | |
1465 | |
1466 // array callback | |
1467 if (is_array && | |
1468 callbacks()->array_primitive_value_callback != NULL && | |
1469 obj->is_typeArray()) { | |
1470 jint res = invoke_array_primitive_value_callback( | |
1471 callbacks()->array_primitive_value_callback, | |
1472 &wrapper, | |
1473 obj, | |
1474 (void*)user_data() ); | |
1475 if (check_flags_for_abort(res)) return; | |
1476 } | |
1477 }; | |
1478 | |
1479 | |
1480 // Deprecated function to iterate over all objects in the heap | |
1481 void JvmtiTagMap::iterate_over_heap(jvmtiHeapObjectFilter object_filter, | |
1482 KlassHandle klass, | |
1483 jvmtiHeapObjectCallback heap_object_callback, | |
1484 const void* user_data) | |
1485 { | |
1486 MutexLocker ml(Heap_lock); | |
1487 IterateOverHeapObjectClosure blk(this, | |
1488 klass, | |
1489 object_filter, | |
1490 heap_object_callback, | |
1491 user_data); | |
1492 VM_HeapIterateOperation op(&blk); | |
1493 VMThread::execute(&op); | |
1494 } | |
1495 | |
1496 | |
1497 // Iterates over all objects in the heap | |
1498 void JvmtiTagMap::iterate_through_heap(jint heap_filter, | |
1499 KlassHandle klass, | |
1500 const jvmtiHeapCallbacks* callbacks, | |
1501 const void* user_data) | |
1502 { | |
1503 MutexLocker ml(Heap_lock); | |
1504 IterateThroughHeapObjectClosure blk(this, | |
1505 klass, | |
1506 heap_filter, | |
1507 callbacks, | |
1508 user_data); | |
1509 VM_HeapIterateOperation op(&blk); | |
1510 VMThread::execute(&op); | |
1511 } | |
1512 | |
1513 // support class for get_objects_with_tags | |
1514 | |
1515 class TagObjectCollector : public JvmtiTagHashmapEntryClosure { | |
1516 private: | |
1517 JvmtiEnv* _env; | |
1518 jlong* _tags; | |
1519 jint _tag_count; | |
1520 | |
1521 GrowableArray<jobject>* _object_results; // collected objects (JNI weak refs) | |
1522 GrowableArray<uint64_t>* _tag_results; // collected tags | |
1523 | |
1524 public: | |
1525 TagObjectCollector(JvmtiEnv* env, const jlong* tags, jint tag_count) { | |
1526 _env = env; | |
1527 _tags = (jlong*)tags; | |
1528 _tag_count = tag_count; | |
1529 _object_results = new (ResourceObj::C_HEAP) GrowableArray<jobject>(1,true); | |
1530 _tag_results = new (ResourceObj::C_HEAP) GrowableArray<uint64_t>(1,true); | |
1531 } | |
1532 | |
1533 ~TagObjectCollector() { | |
1534 delete _object_results; | |
1535 delete _tag_results; | |
1536 } | |
1537 | |
1538 // for each tagged object check if the tag value matches | |
1539 // - if it matches then we create a JNI local reference to the object | |
1540 // and record the reference and tag value. | |
1541 // | |
1542 void do_entry(JvmtiTagHashmapEntry* entry) { | |
1543 for (int i=0; i<_tag_count; i++) { | |
1544 if (_tags[i] == entry->tag()) { | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
1545 oop o = entry->object(); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
1546 assert(o != NULL, "sanity check"); |
0 | 1547 |
1548 // the mirror is tagged | |
1549 if (o->is_klass()) { | |
1550 klassOop k = (klassOop)o; | |
1551 o = Klass::cast(k)->java_mirror(); | |
1552 } | |
1553 | |
1554 jobject ref = JNIHandles::make_local(JavaThread::current(), o); | |
1555 _object_results->append(ref); | |
1556 _tag_results->append((uint64_t)entry->tag()); | |
1557 } | |
1558 } | |
1559 } | |
1560 | |
1561 // return the results from the collection | |
1562 // | |
1563 jvmtiError result(jint* count_ptr, jobject** object_result_ptr, jlong** tag_result_ptr) { | |
1564 jvmtiError error; | |
1565 int count = _object_results->length(); | |
1566 assert(count >= 0, "sanity check"); | |
1567 | |
1568 // if object_result_ptr is not NULL then allocate the result and copy | |
1569 // in the object references. | |
1570 if (object_result_ptr != NULL) { | |
1571 error = _env->Allocate(count * sizeof(jobject), (unsigned char**)object_result_ptr); | |
1572 if (error != JVMTI_ERROR_NONE) { | |
1573 return error; | |
1574 } | |
1575 for (int i=0; i<count; i++) { | |
1576 (*object_result_ptr)[i] = _object_results->at(i); | |
1577 } | |
1578 } | |
1579 | |
1580 // if tag_result_ptr is not NULL then allocate the result and copy | |
1581 // in the tag values. | |
1582 if (tag_result_ptr != NULL) { | |
1583 error = _env->Allocate(count * sizeof(jlong), (unsigned char**)tag_result_ptr); | |
1584 if (error != JVMTI_ERROR_NONE) { | |
1585 if (object_result_ptr != NULL) { | |
1586 _env->Deallocate((unsigned char*)object_result_ptr); | |
1587 } | |
1588 return error; | |
1589 } | |
1590 for (int i=0; i<count; i++) { | |
1591 (*tag_result_ptr)[i] = (jlong)_tag_results->at(i); | |
1592 } | |
1593 } | |
1594 | |
1595 *count_ptr = count; | |
1596 return JVMTI_ERROR_NONE; | |
1597 } | |
1598 }; | |
1599 | |
1600 // return the list of objects with the specified tags | |
1601 jvmtiError JvmtiTagMap::get_objects_with_tags(const jlong* tags, | |
1602 jint count, jint* count_ptr, jobject** object_result_ptr, jlong** tag_result_ptr) { | |
1603 | |
1604 TagObjectCollector collector(env(), tags, count); | |
1605 { | |
1606 // iterate over all tagged objects | |
1607 MutexLocker ml(lock()); | |
1608 entry_iterate(&collector); | |
1609 } | |
1610 return collector.result(count_ptr, object_result_ptr, tag_result_ptr); | |
1611 } | |
1612 | |
1613 | |
1614 // ObjectMarker is used to support the marking objects when walking the | |
1615 // heap. | |
1616 // | |
1617 // This implementation uses the existing mark bits in an object for | |
1618 // marking. Objects that are marked must later have their headers restored. | |
1619 // As most objects are unlocked and don't have their identity hash computed | |
1620 // we don't have to save their headers. Instead we save the headers that | |
1621 // are "interesting". Later when the headers are restored this implementation | |
1622 // restores all headers to their initial value and then restores the few | |
1623 // objects that had interesting headers. | |
1624 // | |
1625 // Future work: This implementation currently uses growable arrays to save | |
1626 // the oop and header of interesting objects. As an optimization we could | |
1627 // use the same technique as the GC and make use of the unused area | |
1628 // between top() and end(). | |
1629 // | |
1630 | |
1631 // An ObjectClosure used to restore the mark bits of an object | |
1632 class RestoreMarksClosure : public ObjectClosure { | |
1633 public: | |
1634 void do_object(oop o) { | |
1635 if (o != NULL) { | |
1636 markOop mark = o->mark(); | |
1637 if (mark->is_marked()) { | |
1638 o->init_mark(); | |
1639 } | |
1640 } | |
1641 } | |
1642 }; | |
1643 | |
1644 // ObjectMarker provides the mark and visited functions | |
1645 class ObjectMarker : AllStatic { | |
1646 private: | |
1647 // saved headers | |
1648 static GrowableArray<oop>* _saved_oop_stack; | |
1649 static GrowableArray<markOop>* _saved_mark_stack; | |
1650 | |
1651 public: | |
1652 static void init(); // initialize | |
1653 static void done(); // clean-up | |
1654 | |
1655 static inline void mark(oop o); // mark an object | |
1656 static inline bool visited(oop o); // check if object has been visited | |
1657 }; | |
1658 | |
1659 GrowableArray<oop>* ObjectMarker::_saved_oop_stack = NULL; | |
1660 GrowableArray<markOop>* ObjectMarker::_saved_mark_stack = NULL; | |
1661 | |
1662 // initialize ObjectMarker - prepares for object marking | |
1663 void ObjectMarker::init() { | |
1664 assert(Thread::current()->is_VM_thread(), "must be VMThread"); | |
1665 | |
1666 // prepare heap for iteration | |
1667 Universe::heap()->ensure_parsability(false); // no need to retire TLABs | |
1668 | |
1669 // create stacks for interesting headers | |
1670 _saved_mark_stack = new (ResourceObj::C_HEAP) GrowableArray<markOop>(4000, true); | |
1671 _saved_oop_stack = new (ResourceObj::C_HEAP) GrowableArray<oop>(4000, true); | |
1672 | |
1673 if (UseBiasedLocking) { | |
1674 BiasedLocking::preserve_marks(); | |
1675 } | |
1676 } | |
1677 | |
1678 // Object marking is done so restore object headers | |
1679 void ObjectMarker::done() { | |
1680 // iterate over all objects and restore the mark bits to | |
1681 // their initial value | |
1682 RestoreMarksClosure blk; | |
1683 Universe::heap()->object_iterate(&blk); | |
1684 | |
1685 // When sharing is enabled we need to restore the headers of the objects | |
1686 // in the readwrite space too. | |
1687 if (UseSharedSpaces) { | |
1688 GenCollectedHeap* gch = GenCollectedHeap::heap(); | |
1689 CompactingPermGenGen* gen = (CompactingPermGenGen*)gch->perm_gen(); | |
1690 gen->rw_space()->object_iterate(&blk); | |
1691 } | |
1692 | |
1693 // now restore the interesting headers | |
1694 for (int i = 0; i < _saved_oop_stack->length(); i++) { | |
1695 oop o = _saved_oop_stack->at(i); | |
1696 markOop mark = _saved_mark_stack->at(i); | |
1697 o->set_mark(mark); | |
1698 } | |
1699 | |
1700 if (UseBiasedLocking) { | |
1701 BiasedLocking::restore_marks(); | |
1702 } | |
1703 | |
1704 // free the stacks | |
1705 delete _saved_oop_stack; | |
1706 delete _saved_mark_stack; | |
1707 } | |
1708 | |
1709 // mark an object | |
1710 inline void ObjectMarker::mark(oop o) { | |
1711 assert(Universe::heap()->is_in(o), "sanity check"); | |
1712 assert(!o->mark()->is_marked(), "should only mark an object once"); | |
1713 | |
1714 // object's mark word | |
1715 markOop mark = o->mark(); | |
1716 | |
1717 if (mark->must_be_preserved(o)) { | |
1718 _saved_mark_stack->push(mark); | |
1719 _saved_oop_stack->push(o); | |
1720 } | |
1721 | |
1722 // mark the object | |
1723 o->set_mark(markOopDesc::prototype()->set_marked()); | |
1724 } | |
1725 | |
1726 // return true if object is marked | |
1727 inline bool ObjectMarker::visited(oop o) { | |
1728 return o->mark()->is_marked(); | |
1729 } | |
1730 | |
1731 // Stack allocated class to help ensure that ObjectMarker is used | |
1732 // correctly. Constructor initializes ObjectMarker, destructor calls | |
1733 // ObjectMarker's done() function to restore object headers. | |
1734 class ObjectMarkerController : public StackObj { | |
1735 public: | |
1736 ObjectMarkerController() { | |
1737 ObjectMarker::init(); | |
1738 } | |
1739 ~ObjectMarkerController() { | |
1740 ObjectMarker::done(); | |
1741 } | |
1742 }; | |
1743 | |
1744 | |
1745 // helper to map a jvmtiHeapReferenceKind to an old style jvmtiHeapRootKind | |
1746 // (not performance critical as only used for roots) | |
1747 static jvmtiHeapRootKind toJvmtiHeapRootKind(jvmtiHeapReferenceKind kind) { | |
1748 switch (kind) { | |
1749 case JVMTI_HEAP_REFERENCE_JNI_GLOBAL: return JVMTI_HEAP_ROOT_JNI_GLOBAL; | |
1750 case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS: return JVMTI_HEAP_ROOT_SYSTEM_CLASS; | |
1751 case JVMTI_HEAP_REFERENCE_MONITOR: return JVMTI_HEAP_ROOT_MONITOR; | |
1752 case JVMTI_HEAP_REFERENCE_STACK_LOCAL: return JVMTI_HEAP_ROOT_STACK_LOCAL; | |
1753 case JVMTI_HEAP_REFERENCE_JNI_LOCAL: return JVMTI_HEAP_ROOT_JNI_LOCAL; | |
1754 case JVMTI_HEAP_REFERENCE_THREAD: return JVMTI_HEAP_ROOT_THREAD; | |
1755 case JVMTI_HEAP_REFERENCE_OTHER: return JVMTI_HEAP_ROOT_OTHER; | |
1756 default: ShouldNotReachHere(); return JVMTI_HEAP_ROOT_OTHER; | |
1757 } | |
1758 } | |
1759 | |
1760 // Base class for all heap walk contexts. The base class maintains a flag | |
1761 // to indicate if the context is valid or not. | |
1762 class HeapWalkContext VALUE_OBJ_CLASS_SPEC { | |
1763 private: | |
1764 bool _valid; | |
1765 public: | |
1766 HeapWalkContext(bool valid) { _valid = valid; } | |
1767 void invalidate() { _valid = false; } | |
1768 bool is_valid() const { return _valid; } | |
1769 }; | |
1770 | |
1771 // A basic heap walk context for the deprecated heap walking functions. | |
1772 // The context for a basic heap walk are the callbacks and fields used by | |
1773 // the referrer caching scheme. | |
1774 class BasicHeapWalkContext: public HeapWalkContext { | |
1775 private: | |
1776 jvmtiHeapRootCallback _heap_root_callback; | |
1777 jvmtiStackReferenceCallback _stack_ref_callback; | |
1778 jvmtiObjectReferenceCallback _object_ref_callback; | |
1779 | |
1780 // used for caching | |
1781 oop _last_referrer; | |
1782 jlong _last_referrer_tag; | |
1783 | |
1784 public: | |
1785 BasicHeapWalkContext() : HeapWalkContext(false) { } | |
1786 | |
1787 BasicHeapWalkContext(jvmtiHeapRootCallback heap_root_callback, | |
1788 jvmtiStackReferenceCallback stack_ref_callback, | |
1789 jvmtiObjectReferenceCallback object_ref_callback) : | |
1790 HeapWalkContext(true), | |
1791 _heap_root_callback(heap_root_callback), | |
1792 _stack_ref_callback(stack_ref_callback), | |
1793 _object_ref_callback(object_ref_callback), | |
1794 _last_referrer(NULL), | |
1795 _last_referrer_tag(0) { | |
1796 } | |
1797 | |
1798 // accessors | |
1799 jvmtiHeapRootCallback heap_root_callback() const { return _heap_root_callback; } | |
1800 jvmtiStackReferenceCallback stack_ref_callback() const { return _stack_ref_callback; } | |
1801 jvmtiObjectReferenceCallback object_ref_callback() const { return _object_ref_callback; } | |
1802 | |
1803 oop last_referrer() const { return _last_referrer; } | |
1804 void set_last_referrer(oop referrer) { _last_referrer = referrer; } | |
1805 jlong last_referrer_tag() const { return _last_referrer_tag; } | |
1806 void set_last_referrer_tag(jlong value) { _last_referrer_tag = value; } | |
1807 }; | |
1808 | |
1809 // The advanced heap walk context for the FollowReferences functions. | |
1810 // The context is the callbacks, and the fields used for filtering. | |
1811 class AdvancedHeapWalkContext: public HeapWalkContext { | |
1812 private: | |
1813 jint _heap_filter; | |
1814 KlassHandle _klass_filter; | |
1815 const jvmtiHeapCallbacks* _heap_callbacks; | |
1816 | |
1817 public: | |
1818 AdvancedHeapWalkContext() : HeapWalkContext(false) { } | |
1819 | |
1820 AdvancedHeapWalkContext(jint heap_filter, | |
1821 KlassHandle klass_filter, | |
1822 const jvmtiHeapCallbacks* heap_callbacks) : | |
1823 HeapWalkContext(true), | |
1824 _heap_filter(heap_filter), | |
1825 _klass_filter(klass_filter), | |
1826 _heap_callbacks(heap_callbacks) { | |
1827 } | |
1828 | |
1829 // accessors | |
1830 jint heap_filter() const { return _heap_filter; } | |
1831 KlassHandle klass_filter() const { return _klass_filter; } | |
1832 | |
1833 const jvmtiHeapReferenceCallback heap_reference_callback() const { | |
1834 return _heap_callbacks->heap_reference_callback; | |
1835 }; | |
1836 const jvmtiPrimitiveFieldCallback primitive_field_callback() const { | |
1837 return _heap_callbacks->primitive_field_callback; | |
1838 } | |
1839 const jvmtiArrayPrimitiveValueCallback array_primitive_value_callback() const { | |
1840 return _heap_callbacks->array_primitive_value_callback; | |
1841 } | |
1842 const jvmtiStringPrimitiveValueCallback string_primitive_value_callback() const { | |
1843 return _heap_callbacks->string_primitive_value_callback; | |
1844 } | |
1845 }; | |
1846 | |
1847 // The CallbackInvoker is a class with static functions that the heap walk can call | |
1848 // into to invoke callbacks. It works in one of two modes. The "basic" mode is | |
1849 // used for the deprecated IterateOverReachableObjects functions. The "advanced" | |
1850 // mode is for the newer FollowReferences function which supports a lot of | |
1851 // additional callbacks. | |
1852 class CallbackInvoker : AllStatic { | |
1853 private: | |
1854 // heap walk styles | |
1855 enum { basic, advanced }; | |
1856 static int _heap_walk_type; | |
1857 static bool is_basic_heap_walk() { return _heap_walk_type == basic; } | |
1858 static bool is_advanced_heap_walk() { return _heap_walk_type == advanced; } | |
1859 | |
1860 // context for basic style heap walk | |
1861 static BasicHeapWalkContext _basic_context; | |
1862 static BasicHeapWalkContext* basic_context() { | |
1863 assert(_basic_context.is_valid(), "invalid"); | |
1864 return &_basic_context; | |
1865 } | |
1866 | |
1867 // context for advanced style heap walk | |
1868 static AdvancedHeapWalkContext _advanced_context; | |
1869 static AdvancedHeapWalkContext* advanced_context() { | |
1870 assert(_advanced_context.is_valid(), "invalid"); | |
1871 return &_advanced_context; | |
1872 } | |
1873 | |
1874 // context needed for all heap walks | |
1875 static JvmtiTagMap* _tag_map; | |
1876 static const void* _user_data; | |
1877 static GrowableArray<oop>* _visit_stack; | |
1878 | |
1879 // accessors | |
1880 static JvmtiTagMap* tag_map() { return _tag_map; } | |
1881 static const void* user_data() { return _user_data; } | |
1882 static GrowableArray<oop>* visit_stack() { return _visit_stack; } | |
1883 | |
1884 // if the object hasn't been visited then push it onto the visit stack | |
1885 // so that it will be visited later | |
1886 static inline bool check_for_visit(oop obj) { | |
1887 if (!ObjectMarker::visited(obj)) visit_stack()->push(obj); | |
1888 return true; | |
1889 } | |
1890 | |
1891 // invoke basic style callbacks | |
1892 static inline bool invoke_basic_heap_root_callback | |
1893 (jvmtiHeapRootKind root_kind, oop obj); | |
1894 static inline bool invoke_basic_stack_ref_callback | |
1895 (jvmtiHeapRootKind root_kind, jlong thread_tag, jint depth, jmethodID method, | |
1896 int slot, oop obj); | |
1897 static inline bool invoke_basic_object_reference_callback | |
1898 (jvmtiObjectReferenceKind ref_kind, oop referrer, oop referree, jint index); | |
1899 | |
1900 // invoke advanced style callbacks | |
1901 static inline bool invoke_advanced_heap_root_callback | |
1902 (jvmtiHeapReferenceKind ref_kind, oop obj); | |
1903 static inline bool invoke_advanced_stack_ref_callback | |
1904 (jvmtiHeapReferenceKind ref_kind, jlong thread_tag, jlong tid, int depth, | |
1905 jmethodID method, jlocation bci, jint slot, oop obj); | |
1906 static inline bool invoke_advanced_object_reference_callback | |
1907 (jvmtiHeapReferenceKind ref_kind, oop referrer, oop referree, jint index); | |
1908 | |
1909 // used to report the value of primitive fields | |
1910 static inline bool report_primitive_field | |
1911 (jvmtiHeapReferenceKind ref_kind, oop obj, jint index, address addr, char type); | |
1912 | |
1913 public: | |
1914 // initialize for basic mode | |
1915 static void initialize_for_basic_heap_walk(JvmtiTagMap* tag_map, | |
1916 GrowableArray<oop>* visit_stack, | |
1917 const void* user_data, | |
1918 BasicHeapWalkContext context); | |
1919 | |
1920 // initialize for advanced mode | |
1921 static void initialize_for_advanced_heap_walk(JvmtiTagMap* tag_map, | |
1922 GrowableArray<oop>* visit_stack, | |
1923 const void* user_data, | |
1924 AdvancedHeapWalkContext context); | |
1925 | |
1926 // functions to report roots | |
1927 static inline bool report_simple_root(jvmtiHeapReferenceKind kind, oop o); | |
1928 static inline bool report_jni_local_root(jlong thread_tag, jlong tid, jint depth, | |
1929 jmethodID m, oop o); | |
1930 static inline bool report_stack_ref_root(jlong thread_tag, jlong tid, jint depth, | |
1931 jmethodID method, jlocation bci, jint slot, oop o); | |
1932 | |
1933 // functions to report references | |
1934 static inline bool report_array_element_reference(oop referrer, oop referree, jint index); | |
1935 static inline bool report_class_reference(oop referrer, oop referree); | |
1936 static inline bool report_class_loader_reference(oop referrer, oop referree); | |
1937 static inline bool report_signers_reference(oop referrer, oop referree); | |
1938 static inline bool report_protection_domain_reference(oop referrer, oop referree); | |
1939 static inline bool report_superclass_reference(oop referrer, oop referree); | |
1940 static inline bool report_interface_reference(oop referrer, oop referree); | |
1941 static inline bool report_static_field_reference(oop referrer, oop referree, jint slot); | |
1942 static inline bool report_field_reference(oop referrer, oop referree, jint slot); | |
1943 static inline bool report_constant_pool_reference(oop referrer, oop referree, jint index); | |
1944 static inline bool report_primitive_array_values(oop array); | |
1945 static inline bool report_string_value(oop str); | |
1946 static inline bool report_primitive_instance_field(oop o, jint index, address value, char type); | |
1947 static inline bool report_primitive_static_field(oop o, jint index, address value, char type); | |
1948 }; | |
1949 | |
1950 // statics | |
1951 int CallbackInvoker::_heap_walk_type; | |
1952 BasicHeapWalkContext CallbackInvoker::_basic_context; | |
1953 AdvancedHeapWalkContext CallbackInvoker::_advanced_context; | |
1954 JvmtiTagMap* CallbackInvoker::_tag_map; | |
1955 const void* CallbackInvoker::_user_data; | |
1956 GrowableArray<oop>* CallbackInvoker::_visit_stack; | |
1957 | |
1958 // initialize for basic heap walk (IterateOverReachableObjects et al) | |
1959 void CallbackInvoker::initialize_for_basic_heap_walk(JvmtiTagMap* tag_map, | |
1960 GrowableArray<oop>* visit_stack, | |
1961 const void* user_data, | |
1962 BasicHeapWalkContext context) { | |
1963 _tag_map = tag_map; | |
1964 _visit_stack = visit_stack; | |
1965 _user_data = user_data; | |
1966 _basic_context = context; | |
1967 _advanced_context.invalidate(); // will trigger assertion if used | |
1968 _heap_walk_type = basic; | |
1969 } | |
1970 | |
1971 // initialize for advanced heap walk (FollowReferences) | |
1972 void CallbackInvoker::initialize_for_advanced_heap_walk(JvmtiTagMap* tag_map, | |
1973 GrowableArray<oop>* visit_stack, | |
1974 const void* user_data, | |
1975 AdvancedHeapWalkContext context) { | |
1976 _tag_map = tag_map; | |
1977 _visit_stack = visit_stack; | |
1978 _user_data = user_data; | |
1979 _advanced_context = context; | |
1980 _basic_context.invalidate(); // will trigger assertion if used | |
1981 _heap_walk_type = advanced; | |
1982 } | |
1983 | |
1984 | |
1985 // invoke basic style heap root callback | |
1986 inline bool CallbackInvoker::invoke_basic_heap_root_callback(jvmtiHeapRootKind root_kind, oop obj) { | |
1987 assert(ServiceUtil::visible_oop(obj), "checking"); | |
1988 | |
1989 // if we heap roots should be reported | |
1990 jvmtiHeapRootCallback cb = basic_context()->heap_root_callback(); | |
1991 if (cb == NULL) { | |
1992 return check_for_visit(obj); | |
1993 } | |
1994 | |
1995 CallbackWrapper wrapper(tag_map(), obj); | |
1996 jvmtiIterationControl control = (*cb)(root_kind, | |
1997 wrapper.klass_tag(), | |
1998 wrapper.obj_size(), | |
1999 wrapper.obj_tag_p(), | |
2000 (void*)user_data()); | |
2001 // push root to visit stack when following references | |
2002 if (control == JVMTI_ITERATION_CONTINUE && | |
2003 basic_context()->object_ref_callback() != NULL) { | |
2004 visit_stack()->push(obj); | |
2005 } | |
2006 return control != JVMTI_ITERATION_ABORT; | |
2007 } | |
2008 | |
2009 // invoke basic style stack ref callback | |
2010 inline bool CallbackInvoker::invoke_basic_stack_ref_callback(jvmtiHeapRootKind root_kind, | |
2011 jlong thread_tag, | |
2012 jint depth, | |
2013 jmethodID method, | |
2014 jint slot, | |
2015 oop obj) { | |
2016 assert(ServiceUtil::visible_oop(obj), "checking"); | |
2017 | |
2018 // if we stack refs should be reported | |
2019 jvmtiStackReferenceCallback cb = basic_context()->stack_ref_callback(); | |
2020 if (cb == NULL) { | |
2021 return check_for_visit(obj); | |
2022 } | |
2023 | |
2024 CallbackWrapper wrapper(tag_map(), obj); | |
2025 jvmtiIterationControl control = (*cb)(root_kind, | |
2026 wrapper.klass_tag(), | |
2027 wrapper.obj_size(), | |
2028 wrapper.obj_tag_p(), | |
2029 thread_tag, | |
2030 depth, | |
2031 method, | |
2032 slot, | |
2033 (void*)user_data()); | |
2034 // push root to visit stack when following references | |
2035 if (control == JVMTI_ITERATION_CONTINUE && | |
2036 basic_context()->object_ref_callback() != NULL) { | |
2037 visit_stack()->push(obj); | |
2038 } | |
2039 return control != JVMTI_ITERATION_ABORT; | |
2040 } | |
2041 | |
2042 // invoke basic style object reference callback | |
2043 inline bool CallbackInvoker::invoke_basic_object_reference_callback(jvmtiObjectReferenceKind ref_kind, | |
2044 oop referrer, | |
2045 oop referree, | |
2046 jint index) { | |
2047 | |
2048 assert(ServiceUtil::visible_oop(referrer), "checking"); | |
2049 assert(ServiceUtil::visible_oop(referree), "checking"); | |
2050 | |
2051 BasicHeapWalkContext* context = basic_context(); | |
2052 | |
2053 // callback requires the referrer's tag. If it's the same referrer | |
2054 // as the last call then we use the cached value. | |
2055 jlong referrer_tag; | |
2056 if (referrer == context->last_referrer()) { | |
2057 referrer_tag = context->last_referrer_tag(); | |
2058 } else { | |
2059 referrer_tag = tag_for(tag_map(), klassOop_if_java_lang_Class(referrer)); | |
2060 } | |
2061 | |
2062 // do the callback | |
2063 CallbackWrapper wrapper(tag_map(), referree); | |
2064 jvmtiObjectReferenceCallback cb = context->object_ref_callback(); | |
2065 jvmtiIterationControl control = (*cb)(ref_kind, | |
2066 wrapper.klass_tag(), | |
2067 wrapper.obj_size(), | |
2068 wrapper.obj_tag_p(), | |
2069 referrer_tag, | |
2070 index, | |
2071 (void*)user_data()); | |
2072 | |
2073 // record referrer and referrer tag. For self-references record the | |
2074 // tag value from the callback as this might differ from referrer_tag. | |
2075 context->set_last_referrer(referrer); | |
2076 if (referrer == referree) { | |
2077 context->set_last_referrer_tag(*wrapper.obj_tag_p()); | |
2078 } else { | |
2079 context->set_last_referrer_tag(referrer_tag); | |
2080 } | |
2081 | |
2082 if (control == JVMTI_ITERATION_CONTINUE) { | |
2083 return check_for_visit(referree); | |
2084 } else { | |
2085 return control != JVMTI_ITERATION_ABORT; | |
2086 } | |
2087 } | |
2088 | |
2089 // invoke advanced style heap root callback | |
2090 inline bool CallbackInvoker::invoke_advanced_heap_root_callback(jvmtiHeapReferenceKind ref_kind, | |
2091 oop obj) { | |
2092 assert(ServiceUtil::visible_oop(obj), "checking"); | |
2093 | |
2094 AdvancedHeapWalkContext* context = advanced_context(); | |
2095 | |
2096 // check that callback is provided | |
2097 jvmtiHeapReferenceCallback cb = context->heap_reference_callback(); | |
2098 if (cb == NULL) { | |
2099 return check_for_visit(obj); | |
2100 } | |
2101 | |
2102 // apply class filter | |
2103 if (is_filtered_by_klass_filter(obj, context->klass_filter())) { | |
2104 return check_for_visit(obj); | |
2105 } | |
2106 | |
2107 // setup the callback wrapper | |
2108 CallbackWrapper wrapper(tag_map(), obj); | |
2109 | |
2110 // apply tag filter | |
2111 if (is_filtered_by_heap_filter(wrapper.obj_tag(), | |
2112 wrapper.klass_tag(), | |
2113 context->heap_filter())) { | |
2114 return check_for_visit(obj); | |
2115 } | |
2116 | |
2117 // for arrays we need the length, otherwise -1 | |
2118 jint len = (jint)(obj->is_array() ? arrayOop(obj)->length() : -1); | |
2119 | |
2120 // invoke the callback | |
2121 jint res = (*cb)(ref_kind, | |
2122 NULL, // referrer info | |
2123 wrapper.klass_tag(), | |
2124 0, // referrer_class_tag is 0 for heap root | |
2125 wrapper.obj_size(), | |
2126 wrapper.obj_tag_p(), | |
2127 NULL, // referrer_tag_p | |
2128 len, | |
2129 (void*)user_data()); | |
2130 if (res & JVMTI_VISIT_ABORT) { | |
2131 return false;// referrer class tag | |
2132 } | |
2133 if (res & JVMTI_VISIT_OBJECTS) { | |
2134 check_for_visit(obj); | |
2135 } | |
2136 return true; | |
2137 } | |
2138 | |
2139 // report a reference from a thread stack to an object | |
2140 inline bool CallbackInvoker::invoke_advanced_stack_ref_callback(jvmtiHeapReferenceKind ref_kind, | |
2141 jlong thread_tag, | |
2142 jlong tid, | |
2143 int depth, | |
2144 jmethodID method, | |
2145 jlocation bci, | |
2146 jint slot, | |
2147 oop obj) { | |
2148 assert(ServiceUtil::visible_oop(obj), "checking"); | |
2149 | |
2150 AdvancedHeapWalkContext* context = advanced_context(); | |
2151 | |
2152 // check that callback is provider | |
2153 jvmtiHeapReferenceCallback cb = context->heap_reference_callback(); | |
2154 if (cb == NULL) { | |
2155 return check_for_visit(obj); | |
2156 } | |
2157 | |
2158 // apply class filter | |
2159 if (is_filtered_by_klass_filter(obj, context->klass_filter())) { | |
2160 return check_for_visit(obj); | |
2161 } | |
2162 | |
2163 // setup the callback wrapper | |
2164 CallbackWrapper wrapper(tag_map(), obj); | |
2165 | |
2166 // apply tag filter | |
2167 if (is_filtered_by_heap_filter(wrapper.obj_tag(), | |
2168 wrapper.klass_tag(), | |
2169 context->heap_filter())) { | |
2170 return check_for_visit(obj); | |
2171 } | |
2172 | |
2173 // setup the referrer info | |
2174 jvmtiHeapReferenceInfo reference_info; | |
2175 reference_info.stack_local.thread_tag = thread_tag; | |
2176 reference_info.stack_local.thread_id = tid; | |
2177 reference_info.stack_local.depth = depth; | |
2178 reference_info.stack_local.method = method; | |
2179 reference_info.stack_local.location = bci; | |
2180 reference_info.stack_local.slot = slot; | |
2181 | |
2182 // for arrays we need the length, otherwise -1 | |
2183 jint len = (jint)(obj->is_array() ? arrayOop(obj)->length() : -1); | |
2184 | |
2185 // call into the agent | |
2186 int res = (*cb)(ref_kind, | |
2187 &reference_info, | |
2188 wrapper.klass_tag(), | |
2189 0, // referrer_class_tag is 0 for heap root (stack) | |
2190 wrapper.obj_size(), | |
2191 wrapper.obj_tag_p(), | |
2192 NULL, // referrer_tag is 0 for root | |
2193 len, | |
2194 (void*)user_data()); | |
2195 | |
2196 if (res & JVMTI_VISIT_ABORT) { | |
2197 return false; | |
2198 } | |
2199 if (res & JVMTI_VISIT_OBJECTS) { | |
2200 check_for_visit(obj); | |
2201 } | |
2202 return true; | |
2203 } | |
2204 | |
2205 // This mask is used to pass reference_info to a jvmtiHeapReferenceCallback | |
2206 // only for ref_kinds defined by the JVM TI spec. Otherwise, NULL is passed. | |
2207 #define REF_INFO_MASK ((1 << JVMTI_HEAP_REFERENCE_FIELD) \ | |
2208 | (1 << JVMTI_HEAP_REFERENCE_STATIC_FIELD) \ | |
2209 | (1 << JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT) \ | |
2210 | (1 << JVMTI_HEAP_REFERENCE_CONSTANT_POOL) \ | |
2211 | (1 << JVMTI_HEAP_REFERENCE_STACK_LOCAL) \ | |
2212 | (1 << JVMTI_HEAP_REFERENCE_JNI_LOCAL)) | |
2213 | |
2214 // invoke the object reference callback to report a reference | |
2215 inline bool CallbackInvoker::invoke_advanced_object_reference_callback(jvmtiHeapReferenceKind ref_kind, | |
2216 oop referrer, | |
2217 oop obj, | |
2218 jint index) | |
2219 { | |
2220 // field index is only valid field in reference_info | |
2221 static jvmtiHeapReferenceInfo reference_info = { 0 }; | |
2222 | |
2223 assert(ServiceUtil::visible_oop(referrer), "checking"); | |
2224 assert(ServiceUtil::visible_oop(obj), "checking"); | |
2225 | |
2226 AdvancedHeapWalkContext* context = advanced_context(); | |
2227 | |
2228 // check that callback is provider | |
2229 jvmtiHeapReferenceCallback cb = context->heap_reference_callback(); | |
2230 if (cb == NULL) { | |
2231 return check_for_visit(obj); | |
2232 } | |
2233 | |
2234 // apply class filter | |
2235 if (is_filtered_by_klass_filter(obj, context->klass_filter())) { | |
2236 return check_for_visit(obj); | |
2237 } | |
2238 | |
2239 // setup the callback wrapper | |
2240 TwoOopCallbackWrapper wrapper(tag_map(), referrer, obj); | |
2241 | |
2242 // apply tag filter | |
2243 if (is_filtered_by_heap_filter(wrapper.obj_tag(), | |
2244 wrapper.klass_tag(), | |
2245 context->heap_filter())) { | |
2246 return check_for_visit(obj); | |
2247 } | |
2248 | |
2249 // field index is only valid field in reference_info | |
2250 reference_info.field.index = index; | |
2251 | |
2252 // for arrays we need the length, otherwise -1 | |
2253 jint len = (jint)(obj->is_array() ? arrayOop(obj)->length() : -1); | |
2254 | |
2255 // invoke the callback | |
2256 int res = (*cb)(ref_kind, | |
2257 (REF_INFO_MASK & (1 << ref_kind)) ? &reference_info : NULL, | |
2258 wrapper.klass_tag(), | |
2259 wrapper.referrer_klass_tag(), | |
2260 wrapper.obj_size(), | |
2261 wrapper.obj_tag_p(), | |
2262 wrapper.referrer_tag_p(), | |
2263 len, | |
2264 (void*)user_data()); | |
2265 | |
2266 if (res & JVMTI_VISIT_ABORT) { | |
2267 return false; | |
2268 } | |
2269 if (res & JVMTI_VISIT_OBJECTS) { | |
2270 check_for_visit(obj); | |
2271 } | |
2272 return true; | |
2273 } | |
2274 | |
2275 // report a "simple root" | |
2276 inline bool CallbackInvoker::report_simple_root(jvmtiHeapReferenceKind kind, oop obj) { | |
2277 assert(kind != JVMTI_HEAP_REFERENCE_STACK_LOCAL && | |
2278 kind != JVMTI_HEAP_REFERENCE_JNI_LOCAL, "not a simple root"); | |
2279 assert(ServiceUtil::visible_oop(obj), "checking"); | |
2280 | |
2281 if (is_basic_heap_walk()) { | |
2282 // map to old style root kind | |
2283 jvmtiHeapRootKind root_kind = toJvmtiHeapRootKind(kind); | |
2284 return invoke_basic_heap_root_callback(root_kind, obj); | |
2285 } else { | |
2286 assert(is_advanced_heap_walk(), "wrong heap walk type"); | |
2287 return invoke_advanced_heap_root_callback(kind, obj); | |
2288 } | |
2289 } | |
2290 | |
2291 | |
2292 // invoke the primitive array values | |
2293 inline bool CallbackInvoker::report_primitive_array_values(oop obj) { | |
2294 assert(obj->is_typeArray(), "not a primitive array"); | |
2295 | |
2296 AdvancedHeapWalkContext* context = advanced_context(); | |
2297 assert(context->array_primitive_value_callback() != NULL, "no callback"); | |
2298 | |
2299 // apply class filter | |
2300 if (is_filtered_by_klass_filter(obj, context->klass_filter())) { | |
2301 return true; | |
2302 } | |
2303 | |
2304 CallbackWrapper wrapper(tag_map(), obj); | |
2305 | |
2306 // apply tag filter | |
2307 if (is_filtered_by_heap_filter(wrapper.obj_tag(), | |
2308 wrapper.klass_tag(), | |
2309 context->heap_filter())) { | |
2310 return true; | |
2311 } | |
2312 | |
2313 // invoke the callback | |
2314 int res = invoke_array_primitive_value_callback(context->array_primitive_value_callback(), | |
2315 &wrapper, | |
2316 obj, | |
2317 (void*)user_data()); | |
2318 return (!(res & JVMTI_VISIT_ABORT)); | |
2319 } | |
2320 | |
2321 // invoke the string value callback | |
2322 inline bool CallbackInvoker::report_string_value(oop str) { | |
1142 | 2323 assert(str->klass() == SystemDictionary::String_klass(), "not a string"); |
0 | 2324 |
2325 AdvancedHeapWalkContext* context = advanced_context(); | |
2326 assert(context->string_primitive_value_callback() != NULL, "no callback"); | |
2327 | |
2328 // apply class filter | |
2329 if (is_filtered_by_klass_filter(str, context->klass_filter())) { | |
2330 return true; | |
2331 } | |
2332 | |
2333 CallbackWrapper wrapper(tag_map(), str); | |
2334 | |
2335 // apply tag filter | |
2336 if (is_filtered_by_heap_filter(wrapper.obj_tag(), | |
2337 wrapper.klass_tag(), | |
2338 context->heap_filter())) { | |
2339 return true; | |
2340 } | |
2341 | |
2342 // invoke the callback | |
2343 int res = invoke_string_value_callback(context->string_primitive_value_callback(), | |
2344 &wrapper, | |
2345 str, | |
2346 (void*)user_data()); | |
2347 return (!(res & JVMTI_VISIT_ABORT)); | |
2348 } | |
2349 | |
2350 // invoke the primitive field callback | |
2351 inline bool CallbackInvoker::report_primitive_field(jvmtiHeapReferenceKind ref_kind, | |
2352 oop obj, | |
2353 jint index, | |
2354 address addr, | |
2355 char type) | |
2356 { | |
2357 // for primitive fields only the index will be set | |
2358 static jvmtiHeapReferenceInfo reference_info = { 0 }; | |
2359 | |
2360 AdvancedHeapWalkContext* context = advanced_context(); | |
2361 assert(context->primitive_field_callback() != NULL, "no callback"); | |
2362 | |
2363 // apply class filter | |
2364 if (is_filtered_by_klass_filter(obj, context->klass_filter())) { | |
2365 return true; | |
2366 } | |
2367 | |
2368 CallbackWrapper wrapper(tag_map(), obj); | |
2369 | |
2370 // apply tag filter | |
2371 if (is_filtered_by_heap_filter(wrapper.obj_tag(), | |
2372 wrapper.klass_tag(), | |
2373 context->heap_filter())) { | |
2374 return true; | |
2375 } | |
2376 | |
2377 // the field index in the referrer | |
2378 reference_info.field.index = index; | |
2379 | |
2380 // map the type | |
2381 jvmtiPrimitiveType value_type = (jvmtiPrimitiveType)type; | |
2382 | |
2383 // setup the jvalue | |
2384 jvalue value; | |
2385 copy_to_jvalue(&value, addr, value_type); | |
2386 | |
2387 jvmtiPrimitiveFieldCallback cb = context->primitive_field_callback(); | |
2388 int res = (*cb)(ref_kind, | |
2389 &reference_info, | |
2390 wrapper.klass_tag(), | |
2391 wrapper.obj_tag_p(), | |
2392 value, | |
2393 value_type, | |
2394 (void*)user_data()); | |
2395 return (!(res & JVMTI_VISIT_ABORT)); | |
2396 } | |
2397 | |
2398 | |
2399 // instance field | |
2400 inline bool CallbackInvoker::report_primitive_instance_field(oop obj, | |
2401 jint index, | |
2402 address value, | |
2403 char type) { | |
2404 return report_primitive_field(JVMTI_HEAP_REFERENCE_FIELD, | |
2405 obj, | |
2406 index, | |
2407 value, | |
2408 type); | |
2409 } | |
2410 | |
2411 // static field | |
2412 inline bool CallbackInvoker::report_primitive_static_field(oop obj, | |
2413 jint index, | |
2414 address value, | |
2415 char type) { | |
2416 return report_primitive_field(JVMTI_HEAP_REFERENCE_STATIC_FIELD, | |
2417 obj, | |
2418 index, | |
2419 value, | |
2420 type); | |
2421 } | |
2422 | |
2423 // report a JNI local (root object) to the profiler | |
2424 inline bool CallbackInvoker::report_jni_local_root(jlong thread_tag, jlong tid, jint depth, jmethodID m, oop obj) { | |
2425 if (is_basic_heap_walk()) { | |
2426 return invoke_basic_stack_ref_callback(JVMTI_HEAP_ROOT_JNI_LOCAL, | |
2427 thread_tag, | |
2428 depth, | |
2429 m, | |
2430 -1, | |
2431 obj); | |
2432 } else { | |
2433 return invoke_advanced_stack_ref_callback(JVMTI_HEAP_REFERENCE_JNI_LOCAL, | |
2434 thread_tag, tid, | |
2435 depth, | |
2436 m, | |
2437 (jlocation)-1, | |
2438 -1, | |
2439 obj); | |
2440 } | |
2441 } | |
2442 | |
2443 | |
2444 // report a local (stack reference, root object) | |
2445 inline bool CallbackInvoker::report_stack_ref_root(jlong thread_tag, | |
2446 jlong tid, | |
2447 jint depth, | |
2448 jmethodID method, | |
2449 jlocation bci, | |
2450 jint slot, | |
2451 oop obj) { | |
2452 if (is_basic_heap_walk()) { | |
2453 return invoke_basic_stack_ref_callback(JVMTI_HEAP_ROOT_STACK_LOCAL, | |
2454 thread_tag, | |
2455 depth, | |
2456 method, | |
2457 slot, | |
2458 obj); | |
2459 } else { | |
2460 return invoke_advanced_stack_ref_callback(JVMTI_HEAP_REFERENCE_STACK_LOCAL, | |
2461 thread_tag, | |
2462 tid, | |
2463 depth, | |
2464 method, | |
2465 bci, | |
2466 slot, | |
2467 obj); | |
2468 } | |
2469 } | |
2470 | |
2471 // report an object referencing a class. | |
2472 inline bool CallbackInvoker::report_class_reference(oop referrer, oop referree) { | |
2473 if (is_basic_heap_walk()) { | |
2474 return invoke_basic_object_reference_callback(JVMTI_REFERENCE_CLASS, referrer, referree, -1); | |
2475 } else { | |
2476 return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_CLASS, referrer, referree, -1); | |
2477 } | |
2478 } | |
2479 | |
2480 // report a class referencing its class loader. | |
2481 inline bool CallbackInvoker::report_class_loader_reference(oop referrer, oop referree) { | |
2482 if (is_basic_heap_walk()) { | |
2483 return invoke_basic_object_reference_callback(JVMTI_REFERENCE_CLASS_LOADER, referrer, referree, -1); | |
2484 } else { | |
2485 return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_CLASS_LOADER, referrer, referree, -1); | |
2486 } | |
2487 } | |
2488 | |
2489 // report a class referencing its signers. | |
2490 inline bool CallbackInvoker::report_signers_reference(oop referrer, oop referree) { | |
2491 if (is_basic_heap_walk()) { | |
2492 return invoke_basic_object_reference_callback(JVMTI_REFERENCE_SIGNERS, referrer, referree, -1); | |
2493 } else { | |
2494 return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_SIGNERS, referrer, referree, -1); | |
2495 } | |
2496 } | |
2497 | |
2498 // report a class referencing its protection domain.. | |
2499 inline bool CallbackInvoker::report_protection_domain_reference(oop referrer, oop referree) { | |
2500 if (is_basic_heap_walk()) { | |
2501 return invoke_basic_object_reference_callback(JVMTI_REFERENCE_PROTECTION_DOMAIN, referrer, referree, -1); | |
2502 } else { | |
2503 return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN, referrer, referree, -1); | |
2504 } | |
2505 } | |
2506 | |
2507 // report a class referencing its superclass. | |
2508 inline bool CallbackInvoker::report_superclass_reference(oop referrer, oop referree) { | |
2509 if (is_basic_heap_walk()) { | |
2510 // Send this to be consistent with past implementation | |
2511 return invoke_basic_object_reference_callback(JVMTI_REFERENCE_CLASS, referrer, referree, -1); | |
2512 } else { | |
2513 return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_SUPERCLASS, referrer, referree, -1); | |
2514 } | |
2515 } | |
2516 | |
2517 // report a class referencing one of its interfaces. | |
2518 inline bool CallbackInvoker::report_interface_reference(oop referrer, oop referree) { | |
2519 if (is_basic_heap_walk()) { | |
2520 return invoke_basic_object_reference_callback(JVMTI_REFERENCE_INTERFACE, referrer, referree, -1); | |
2521 } else { | |
2522 return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_INTERFACE, referrer, referree, -1); | |
2523 } | |
2524 } | |
2525 | |
2526 // report a class referencing one of its static fields. | |
2527 inline bool CallbackInvoker::report_static_field_reference(oop referrer, oop referree, jint slot) { | |
2528 if (is_basic_heap_walk()) { | |
2529 return invoke_basic_object_reference_callback(JVMTI_REFERENCE_STATIC_FIELD, referrer, referree, slot); | |
2530 } else { | |
2531 return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_STATIC_FIELD, referrer, referree, slot); | |
2532 } | |
2533 } | |
2534 | |
2535 // report an array referencing an element object | |
2536 inline bool CallbackInvoker::report_array_element_reference(oop referrer, oop referree, jint index) { | |
2537 if (is_basic_heap_walk()) { | |
2538 return invoke_basic_object_reference_callback(JVMTI_REFERENCE_ARRAY_ELEMENT, referrer, referree, index); | |
2539 } else { | |
2540 return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT, referrer, referree, index); | |
2541 } | |
2542 } | |
2543 | |
2544 // report an object referencing an instance field object | |
2545 inline bool CallbackInvoker::report_field_reference(oop referrer, oop referree, jint slot) { | |
2546 if (is_basic_heap_walk()) { | |
2547 return invoke_basic_object_reference_callback(JVMTI_REFERENCE_FIELD, referrer, referree, slot); | |
2548 } else { | |
2549 return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_FIELD, referrer, referree, slot); | |
2550 } | |
2551 } | |
2552 | |
2553 // report an array referencing an element object | |
2554 inline bool CallbackInvoker::report_constant_pool_reference(oop referrer, oop referree, jint index) { | |
2555 if (is_basic_heap_walk()) { | |
2556 return invoke_basic_object_reference_callback(JVMTI_REFERENCE_CONSTANT_POOL, referrer, referree, index); | |
2557 } else { | |
2558 return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_CONSTANT_POOL, referrer, referree, index); | |
2559 } | |
2560 } | |
2561 | |
2562 // A supporting closure used to process simple roots | |
2563 class SimpleRootsClosure : public OopClosure { | |
2564 private: | |
2565 jvmtiHeapReferenceKind _kind; | |
2566 bool _continue; | |
2567 | |
2568 jvmtiHeapReferenceKind root_kind() { return _kind; } | |
2569 | |
2570 public: | |
2571 void set_kind(jvmtiHeapReferenceKind kind) { | |
2572 _kind = kind; | |
2573 _continue = true; | |
2574 } | |
2575 | |
2576 inline bool stopped() { | |
2577 return !_continue; | |
2578 } | |
2579 | |
2580 void do_oop(oop* obj_p) { | |
2581 // iteration has terminated | |
2582 if (stopped()) { | |
2583 return; | |
2584 } | |
2585 | |
2586 // ignore null or deleted handles | |
2587 oop o = *obj_p; | |
2588 if (o == NULL || o == JNIHandles::deleted_handle()) { | |
2589 return; | |
2590 } | |
2591 | |
2592 jvmtiHeapReferenceKind kind = root_kind(); | |
2593 | |
2594 // many roots are Klasses so we use the java mirror | |
2595 if (o->is_klass()) { | |
2596 klassOop k = (klassOop)o; | |
2597 o = Klass::cast(k)->java_mirror(); | |
2376
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
2598 if (o == NULL) { |
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
2599 // Classes without mirrors don't correspond to real Java |
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
2600 // classes so just ignore them. |
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
2601 return; |
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
2602 } |
0 | 2603 } else { |
2604 | |
2605 // SystemDictionary::always_strong_oops_do reports the application | |
2606 // class loader as a root. We want this root to be reported as | |
2607 // a root kind of "OTHER" rather than "SYSTEM_CLASS". | |
2608 if (o->is_instance() && root_kind() == JVMTI_HEAP_REFERENCE_SYSTEM_CLASS) { | |
2609 kind = JVMTI_HEAP_REFERENCE_OTHER; | |
2610 } | |
2611 } | |
2612 | |
2613 // some objects are ignored - in the case of simple | |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
2145
diff
changeset
|
2614 // roots it's mostly Symbol*s that we are skipping |
0 | 2615 // here. |
2616 if (!ServiceUtil::visible_oop(o)) { | |
2617 return; | |
2618 } | |
2619 | |
2620 // invoke the callback | |
2621 _continue = CallbackInvoker::report_simple_root(kind, o); | |
2622 | |
2623 } | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
2624 virtual void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } |
0 | 2625 }; |
2626 | |
2627 // A supporting closure used to process JNI locals | |
2628 class JNILocalRootsClosure : public OopClosure { | |
2629 private: | |
2630 jlong _thread_tag; | |
2631 jlong _tid; | |
2632 jint _depth; | |
2633 jmethodID _method; | |
2634 bool _continue; | |
2635 public: | |
2636 void set_context(jlong thread_tag, jlong tid, jint depth, jmethodID method) { | |
2637 _thread_tag = thread_tag; | |
2638 _tid = tid; | |
2639 _depth = depth; | |
2640 _method = method; | |
2641 _continue = true; | |
2642 } | |
2643 | |
2644 inline bool stopped() { | |
2645 return !_continue; | |
2646 } | |
2647 | |
2648 void do_oop(oop* obj_p) { | |
2649 // iteration has terminated | |
2650 if (stopped()) { | |
2651 return; | |
2652 } | |
2653 | |
2654 // ignore null or deleted handles | |
2655 oop o = *obj_p; | |
2656 if (o == NULL || o == JNIHandles::deleted_handle()) { | |
2657 return; | |
2658 } | |
2659 | |
2660 if (!ServiceUtil::visible_oop(o)) { | |
2661 return; | |
2662 } | |
2663 | |
2664 // invoke the callback | |
2665 _continue = CallbackInvoker::report_jni_local_root(_thread_tag, _tid, _depth, _method, o); | |
2666 } | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
2667 virtual void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } |
0 | 2668 }; |
2669 | |
2670 | |
2671 // A VM operation to iterate over objects that are reachable from | |
2672 // a set of roots or an initial object. | |
2673 // | |
2674 // For VM_HeapWalkOperation the set of roots used is :- | |
2675 // | |
2676 // - All JNI global references | |
2677 // - All inflated monitors | |
2678 // - All classes loaded by the boot class loader (or all classes | |
2679 // in the event that class unloading is disabled) | |
2680 // - All java threads | |
2681 // - For each java thread then all locals and JNI local references | |
2682 // on the thread's execution stack | |
2683 // - All visible/explainable objects from Universes::oops_do | |
2684 // | |
2685 class VM_HeapWalkOperation: public VM_Operation { | |
2686 private: | |
2687 enum { | |
2688 initial_visit_stack_size = 4000 | |
2689 }; | |
2690 | |
2691 bool _is_advanced_heap_walk; // indicates FollowReferences | |
2692 JvmtiTagMap* _tag_map; | |
2693 Handle _initial_object; | |
2694 GrowableArray<oop>* _visit_stack; // the visit stack | |
2695 | |
2696 bool _collecting_heap_roots; // are we collecting roots | |
2697 bool _following_object_refs; // are we following object references | |
2698 | |
2699 bool _reporting_primitive_fields; // optional reporting | |
2700 bool _reporting_primitive_array_values; | |
2701 bool _reporting_string_values; | |
2702 | |
2703 GrowableArray<oop>* create_visit_stack() { | |
2704 return new (ResourceObj::C_HEAP) GrowableArray<oop>(initial_visit_stack_size, true); | |
2705 } | |
2706 | |
2707 // accessors | |
2708 bool is_advanced_heap_walk() const { return _is_advanced_heap_walk; } | |
2709 JvmtiTagMap* tag_map() const { return _tag_map; } | |
2710 Handle initial_object() const { return _initial_object; } | |
2711 | |
2712 bool is_following_references() const { return _following_object_refs; } | |
2713 | |
2714 bool is_reporting_primitive_fields() const { return _reporting_primitive_fields; } | |
2715 bool is_reporting_primitive_array_values() const { return _reporting_primitive_array_values; } | |
2716 bool is_reporting_string_values() const { return _reporting_string_values; } | |
2717 | |
2718 GrowableArray<oop>* visit_stack() const { return _visit_stack; } | |
2719 | |
2720 // iterate over the various object types | |
2721 inline bool iterate_over_array(oop o); | |
2722 inline bool iterate_over_type_array(oop o); | |
2723 inline bool iterate_over_class(klassOop o); | |
2724 inline bool iterate_over_object(oop o); | |
2725 | |
2726 // root collection | |
2727 inline bool collect_simple_roots(); | |
2728 inline bool collect_stack_roots(); | |
2729 inline bool collect_stack_roots(JavaThread* java_thread, JNILocalRootsClosure* blk); | |
2730 | |
2731 // visit an object | |
2732 inline bool visit(oop o); | |
2733 | |
2734 public: | |
2735 VM_HeapWalkOperation(JvmtiTagMap* tag_map, | |
2736 Handle initial_object, | |
2737 BasicHeapWalkContext callbacks, | |
2738 const void* user_data); | |
2739 | |
2740 VM_HeapWalkOperation(JvmtiTagMap* tag_map, | |
2741 Handle initial_object, | |
2742 AdvancedHeapWalkContext callbacks, | |
2743 const void* user_data); | |
2744 | |
2745 ~VM_HeapWalkOperation(); | |
2746 | |
2747 VMOp_Type type() const { return VMOp_HeapWalkOperation; } | |
2748 void doit(); | |
2749 }; | |
2750 | |
2751 | |
2752 VM_HeapWalkOperation::VM_HeapWalkOperation(JvmtiTagMap* tag_map, | |
2753 Handle initial_object, | |
2754 BasicHeapWalkContext callbacks, | |
2755 const void* user_data) { | |
2756 _is_advanced_heap_walk = false; | |
2757 _tag_map = tag_map; | |
2758 _initial_object = initial_object; | |
2759 _following_object_refs = (callbacks.object_ref_callback() != NULL); | |
2760 _reporting_primitive_fields = false; | |
2761 _reporting_primitive_array_values = false; | |
2762 _reporting_string_values = false; | |
2763 _visit_stack = create_visit_stack(); | |
2764 | |
2765 | |
2766 CallbackInvoker::initialize_for_basic_heap_walk(tag_map, _visit_stack, user_data, callbacks); | |
2767 } | |
2768 | |
2769 VM_HeapWalkOperation::VM_HeapWalkOperation(JvmtiTagMap* tag_map, | |
2770 Handle initial_object, | |
2771 AdvancedHeapWalkContext callbacks, | |
2772 const void* user_data) { | |
2773 _is_advanced_heap_walk = true; | |
2774 _tag_map = tag_map; | |
2775 _initial_object = initial_object; | |
2776 _following_object_refs = true; | |
2777 _reporting_primitive_fields = (callbacks.primitive_field_callback() != NULL);; | |
2778 _reporting_primitive_array_values = (callbacks.array_primitive_value_callback() != NULL);; | |
2779 _reporting_string_values = (callbacks.string_primitive_value_callback() != NULL);; | |
2780 _visit_stack = create_visit_stack(); | |
2781 | |
2782 CallbackInvoker::initialize_for_advanced_heap_walk(tag_map, _visit_stack, user_data, callbacks); | |
2783 } | |
2784 | |
2785 VM_HeapWalkOperation::~VM_HeapWalkOperation() { | |
2786 if (_following_object_refs) { | |
2787 assert(_visit_stack != NULL, "checking"); | |
2788 delete _visit_stack; | |
2789 _visit_stack = NULL; | |
2790 } | |
2791 } | |
2792 | |
2793 // an array references its class and has a reference to | |
2794 // each element in the array | |
2795 inline bool VM_HeapWalkOperation::iterate_over_array(oop o) { | |
2796 objArrayOop array = objArrayOop(o); | |
2797 if (array->klass() == Universe::systemObjArrayKlassObj()) { | |
2798 // filtered out | |
2799 return true; | |
2800 } | |
2801 | |
2802 // array reference to its class | |
2803 oop mirror = objArrayKlass::cast(array->klass())->java_mirror(); | |
2804 if (!CallbackInvoker::report_class_reference(o, mirror)) { | |
2805 return false; | |
2806 } | |
2807 | |
2808 // iterate over the array and report each reference to a | |
2809 // non-null element | |
2810 for (int index=0; index<array->length(); index++) { | |
2811 oop elem = array->obj_at(index); | |
2812 if (elem == NULL) { | |
2813 continue; | |
2814 } | |
2815 | |
2816 // report the array reference o[index] = elem | |
2817 if (!CallbackInvoker::report_array_element_reference(o, elem, index)) { | |
2818 return false; | |
2819 } | |
2820 } | |
2821 return true; | |
2822 } | |
2823 | |
2824 // a type array references its class | |
2825 inline bool VM_HeapWalkOperation::iterate_over_type_array(oop o) { | |
2826 klassOop k = o->klass(); | |
2827 oop mirror = Klass::cast(k)->java_mirror(); | |
2828 if (!CallbackInvoker::report_class_reference(o, mirror)) { | |
2829 return false; | |
2830 } | |
2831 | |
2832 // report the array contents if required | |
2833 if (is_reporting_primitive_array_values()) { | |
2834 if (!CallbackInvoker::report_primitive_array_values(o)) { | |
2835 return false; | |
2836 } | |
2837 } | |
2838 return true; | |
2839 } | |
2840 | |
2841 // verify that a static oop field is in range | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
2842 static inline bool verify_static_oop(instanceKlass* ik, |
2376
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
2843 oop mirror, int offset) { |
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
2844 address obj_p = (address)mirror + offset; |
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
2845 address start = (address)instanceMirrorKlass::start_of_static_fields(mirror); |
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
2846 address end = start + (java_lang_Class::static_oop_field_count(mirror) * heapOopSize); |
0 | 2847 assert(end >= start, "sanity check"); |
2848 | |
2849 if (obj_p >= start && obj_p < end) { | |
2850 return true; | |
2851 } else { | |
2852 return false; | |
2853 } | |
2854 } | |
2855 | |
2856 // a class references its super class, interfaces, class loader, ... | |
2857 // and finally its static fields | |
2858 inline bool VM_HeapWalkOperation::iterate_over_class(klassOop k) { | |
2859 int i; | |
2860 Klass* klass = klassOop(k)->klass_part(); | |
2861 | |
2862 if (klass->oop_is_instance()) { | |
2863 instanceKlass* ik = instanceKlass::cast(k); | |
2864 | |
2865 // ignore the class if it's has been initialized yet | |
2866 if (!ik->is_linked()) { | |
2867 return true; | |
2868 } | |
2869 | |
2870 // get the java mirror | |
2871 oop mirror = klass->java_mirror(); | |
2872 | |
2873 // super (only if something more interesting than java.lang.Object) | |
2874 klassOop java_super = ik->java_super(); | |
1142 | 2875 if (java_super != NULL && java_super != SystemDictionary::Object_klass()) { |
0 | 2876 oop super = Klass::cast(java_super)->java_mirror(); |
2877 if (!CallbackInvoker::report_superclass_reference(mirror, super)) { | |
2878 return false; | |
2879 } | |
2880 } | |
2881 | |
2882 // class loader | |
2883 oop cl = ik->class_loader(); | |
2884 if (cl != NULL) { | |
2885 if (!CallbackInvoker::report_class_loader_reference(mirror, cl)) { | |
2886 return false; | |
2887 } | |
2888 } | |
2889 | |
2890 // protection domain | |
2891 oop pd = ik->protection_domain(); | |
2892 if (pd != NULL) { | |
2893 if (!CallbackInvoker::report_protection_domain_reference(mirror, pd)) { | |
2894 return false; | |
2895 } | |
2896 } | |
2897 | |
2898 // signers | |
2899 oop signers = ik->signers(); | |
2900 if (signers != NULL) { | |
2901 if (!CallbackInvoker::report_signers_reference(mirror, signers)) { | |
2902 return false; | |
2903 } | |
2904 } | |
2905 | |
2906 // references from the constant pool | |
2907 { | |
2908 const constantPoolOop pool = ik->constants(); | |
2909 for (int i = 1; i < pool->length(); i++) { | |
2910 constantTag tag = pool->tag_at(i).value(); | |
2911 if (tag.is_string() || tag.is_klass()) { | |
2912 oop entry; | |
2913 if (tag.is_string()) { | |
2914 entry = pool->resolved_string_at(i); | |
2915 assert(java_lang_String::is_instance(entry), "must be string"); | |
2916 } else { | |
2917 entry = Klass::cast(pool->resolved_klass_at(i))->java_mirror(); | |
2918 } | |
2919 if (!CallbackInvoker::report_constant_pool_reference(mirror, entry, (jint)i)) { | |
2920 return false; | |
2921 } | |
2922 } | |
2923 } | |
2924 } | |
2925 | |
2926 // interfaces | |
2927 // (These will already have been reported as references from the constant pool | |
2928 // but are specified by IterateOverReachableObjects and must be reported). | |
2929 objArrayOop interfaces = ik->local_interfaces(); | |
2930 for (i = 0; i < interfaces->length(); i++) { | |
2931 oop interf = Klass::cast((klassOop)interfaces->obj_at(i))->java_mirror(); | |
2932 if (interf == NULL) { | |
2933 continue; | |
2934 } | |
2935 if (!CallbackInvoker::report_interface_reference(mirror, interf)) { | |
2936 return false; | |
2937 } | |
2938 } | |
2939 | |
2940 // iterate over the static fields | |
2941 | |
2942 ClassFieldMap* field_map = ClassFieldMap::create_map_of_static_fields(k); | |
2943 for (i=0; i<field_map->field_count(); i++) { | |
2944 ClassFieldDescriptor* field = field_map->field_at(i); | |
2945 char type = field->field_type(); | |
2946 if (!is_primitive_field_type(type)) { | |
2376
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
2947 oop fld_o = mirror->obj_field(field->field_offset()); |
c7f3d0b4570f
7017732: move static fields into Class to prepare for perm gen removal
never
parents:
2177
diff
changeset
|
2948 assert(verify_static_oop(ik, mirror, field->field_offset()), "sanity check"); |
0 | 2949 if (fld_o != NULL) { |
2950 int slot = field->field_index(); | |
2951 if (!CallbackInvoker::report_static_field_reference(mirror, fld_o, slot)) { | |
2952 delete field_map; | |
2953 return false; | |
2954 } | |
2955 } | |
2956 } else { | |
2957 if (is_reporting_primitive_fields()) { | |
2377
57552dca1708
7029509: nightly failures after static fields in Class
never
parents:
2376
diff
changeset
|
2958 address addr = (address)mirror + field->field_offset(); |
0 | 2959 int slot = field->field_index(); |
2960 if (!CallbackInvoker::report_primitive_static_field(mirror, slot, addr, type)) { | |
2961 delete field_map; | |
2962 return false; | |
2963 } | |
2964 } | |
2965 } | |
2966 } | |
2967 delete field_map; | |
2968 | |
2969 return true; | |
2970 } | |
2971 | |
2972 return true; | |
2973 } | |
2974 | |
2975 // an object references a class and its instance fields | |
2976 // (static fields are ignored here as we report these as | |
2977 // references from the class). | |
2978 inline bool VM_HeapWalkOperation::iterate_over_object(oop o) { | |
2979 // reference to the class | |
2980 if (!CallbackInvoker::report_class_reference(o, Klass::cast(o->klass())->java_mirror())) { | |
2981 return false; | |
2982 } | |
2983 | |
2984 // iterate over instance fields | |
2985 ClassFieldMap* field_map = JvmtiCachedClassFieldMap::get_map_of_instance_fields(o); | |
2986 for (int i=0; i<field_map->field_count(); i++) { | |
2987 ClassFieldDescriptor* field = field_map->field_at(i); | |
2988 char type = field->field_type(); | |
2989 if (!is_primitive_field_type(type)) { | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
2990 oop fld_o = o->obj_field(field->field_offset()); |
0 | 2991 if (fld_o != NULL) { |
2992 // reflection code may have a reference to a klassOop. | |
2993 // - see sun.reflect.UnsafeStaticFieldAccessorImpl and sun.misc.Unsafe | |
2994 if (fld_o->is_klass()) { | |
2995 klassOop k = (klassOop)fld_o; | |
2996 fld_o = Klass::cast(k)->java_mirror(); | |
2997 } | |
2998 int slot = field->field_index(); | |
2999 if (!CallbackInvoker::report_field_reference(o, fld_o, slot)) { | |
3000 return false; | |
3001 } | |
3002 } | |
3003 } else { | |
3004 if (is_reporting_primitive_fields()) { | |
3005 // primitive instance field | |
3006 address addr = (address)o + field->field_offset(); | |
3007 int slot = field->field_index(); | |
3008 if (!CallbackInvoker::report_primitive_instance_field(o, slot, addr, type)) { | |
3009 return false; | |
3010 } | |
3011 } | |
3012 } | |
3013 } | |
3014 | |
3015 // if the object is a java.lang.String | |
3016 if (is_reporting_string_values() && | |
1142 | 3017 o->klass() == SystemDictionary::String_klass()) { |
0 | 3018 if (!CallbackInvoker::report_string_value(o)) { |
3019 return false; | |
3020 } | |
3021 } | |
3022 return true; | |
3023 } | |
3024 | |
3025 | |
3026 // collects all simple (non-stack) roots. | |
3027 // if there's a heap root callback provided then the callback is | |
3028 // invoked for each simple root. | |
3029 // if an object reference callback is provided then all simple | |
3030 // roots are pushed onto the marking stack so that they can be | |
3031 // processed later | |
3032 // | |
3033 inline bool VM_HeapWalkOperation::collect_simple_roots() { | |
3034 SimpleRootsClosure blk; | |
3035 | |
3036 // JNI globals | |
3037 blk.set_kind(JVMTI_HEAP_REFERENCE_JNI_GLOBAL); | |
3038 JNIHandles::oops_do(&blk); | |
3039 if (blk.stopped()) { | |
3040 return false; | |
3041 } | |
3042 | |
3043 // Preloaded classes and loader from the system dictionary | |
3044 blk.set_kind(JVMTI_HEAP_REFERENCE_SYSTEM_CLASS); | |
3045 SystemDictionary::always_strong_oops_do(&blk); | |
3046 if (blk.stopped()) { | |
3047 return false; | |
3048 } | |
3049 | |
3050 // Inflated monitors | |
3051 blk.set_kind(JVMTI_HEAP_REFERENCE_MONITOR); | |
3052 ObjectSynchronizer::oops_do(&blk); | |
3053 if (blk.stopped()) { | |
3054 return false; | |
3055 } | |
3056 | |
3057 // Threads | |
3058 for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) { | |
3059 oop threadObj = thread->threadObj(); | |
3060 if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) { | |
3061 bool cont = CallbackInvoker::report_simple_root(JVMTI_HEAP_REFERENCE_THREAD, threadObj); | |
3062 if (!cont) { | |
3063 return false; | |
3064 } | |
3065 } | |
3066 } | |
3067 | |
3068 // Other kinds of roots maintained by HotSpot | |
3069 // Many of these won't be visible but others (such as instances of important | |
3070 // exceptions) will be visible. | |
3071 blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER); | |
3072 Universe::oops_do(&blk); | |
989
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
579
diff
changeset
|
3073 |
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
579
diff
changeset
|
3074 // If there are any non-perm roots in the code cache, visit them. |
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
579
diff
changeset
|
3075 blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER); |
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
579
diff
changeset
|
3076 CodeBlobToOopClosure look_in_blobs(&blk, false); |
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
579
diff
changeset
|
3077 CodeCache::scavenge_root_nmethods_do(&look_in_blobs); |
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
579
diff
changeset
|
3078 |
0 | 3079 return true; |
3080 } | |
3081 | |
3082 // Walk the stack of a given thread and find all references (locals | |
3083 // and JNI calls) and report these as stack references | |
3084 inline bool VM_HeapWalkOperation::collect_stack_roots(JavaThread* java_thread, | |
3085 JNILocalRootsClosure* blk) | |
3086 { | |
3087 oop threadObj = java_thread->threadObj(); | |
3088 assert(threadObj != NULL, "sanity check"); | |
3089 | |
3090 // only need to get the thread's tag once per thread | |
3091 jlong thread_tag = tag_for(_tag_map, threadObj); | |
3092 | |
3093 // also need the thread id | |
3094 jlong tid = java_lang_Thread::thread_id(threadObj); | |
3095 | |
3096 | |
3097 if (java_thread->has_last_Java_frame()) { | |
3098 | |
3099 // vframes are resource allocated | |
3100 Thread* current_thread = Thread::current(); | |
3101 ResourceMark rm(current_thread); | |
3102 HandleMark hm(current_thread); | |
3103 | |
3104 RegisterMap reg_map(java_thread); | |
3105 frame f = java_thread->last_frame(); | |
3106 vframe* vf = vframe::new_vframe(&f, ®_map, java_thread); | |
3107 | |
3108 bool is_top_frame = true; | |
3109 int depth = 0; | |
3110 frame* last_entry_frame = NULL; | |
3111 | |
3112 while (vf != NULL) { | |
3113 if (vf->is_java_frame()) { | |
3114 | |
3115 // java frame (interpreted, compiled, ...) | |
3116 javaVFrame *jvf = javaVFrame::cast(vf); | |
3117 | |
3118 // the jmethodID | |
3119 jmethodID method = jvf->method()->jmethod_id(); | |
3120 | |
3121 if (!(jvf->method()->is_native())) { | |
3122 jlocation bci = (jlocation)jvf->bci(); | |
3123 StackValueCollection* locals = jvf->locals(); | |
3124 for (int slot=0; slot<locals->size(); slot++) { | |
3125 if (locals->at(slot)->type() == T_OBJECT) { | |
3126 oop o = locals->obj_at(slot)(); | |
3127 if (o == NULL) { | |
3128 continue; | |
3129 } | |
3130 | |
3131 // stack reference | |
3132 if (!CallbackInvoker::report_stack_ref_root(thread_tag, tid, depth, method, | |
3133 bci, slot, o)) { | |
3134 return false; | |
3135 } | |
3136 } | |
3137 } | |
3138 } else { | |
3139 blk->set_context(thread_tag, tid, depth, method); | |
3140 if (is_top_frame) { | |
3141 // JNI locals for the top frame. | |
3142 java_thread->active_handles()->oops_do(blk); | |
3143 } else { | |
3144 if (last_entry_frame != NULL) { | |
3145 // JNI locals for the entry frame | |
3146 assert(last_entry_frame->is_entry_frame(), "checking"); | |
3147 last_entry_frame->entry_frame_call_wrapper()->handles()->oops_do(blk); | |
3148 } | |
3149 } | |
3150 } | |
3151 last_entry_frame = NULL; | |
3152 depth++; | |
3153 } else { | |
3154 // externalVFrame - for an entry frame then we report the JNI locals | |
3155 // when we find the corresponding javaVFrame | |
3156 frame* fr = vf->frame_pointer(); | |
3157 assert(fr != NULL, "sanity check"); | |
3158 if (fr->is_entry_frame()) { | |
3159 last_entry_frame = fr; | |
3160 } | |
3363
167b70ff3abc
6939861: JVM should handle more conversion operations
never
parents:
2377
diff
changeset
|
3161 if (fr->is_ricochet_frame()) { |
167b70ff3abc
6939861: JVM should handle more conversion operations
never
parents:
2377
diff
changeset
|
3162 fr->oops_ricochet_do(blk, vf->register_map()); |
167b70ff3abc
6939861: JVM should handle more conversion operations
never
parents:
2377
diff
changeset
|
3163 } |
0 | 3164 } |
3165 | |
3166 vf = vf->sender(); | |
3167 is_top_frame = false; | |
3168 } | |
3169 } else { | |
3170 // no last java frame but there may be JNI locals | |
3171 blk->set_context(thread_tag, tid, 0, (jmethodID)NULL); | |
3172 java_thread->active_handles()->oops_do(blk); | |
3173 } | |
3174 return true; | |
3175 } | |
3176 | |
3177 | |
3178 // collects all stack roots - for each thread it walks the execution | |
3179 // stack to find all references and local JNI refs. | |
3180 inline bool VM_HeapWalkOperation::collect_stack_roots() { | |
3181 JNILocalRootsClosure blk; | |
3182 for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) { | |
3183 oop threadObj = thread->threadObj(); | |
3184 if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) { | |
3185 if (!collect_stack_roots(thread, &blk)) { | |
3186 return false; | |
3187 } | |
3188 } | |
3189 } | |
3190 return true; | |
3191 } | |
3192 | |
3193 // visit an object | |
3194 // first mark the object as visited | |
3195 // second get all the outbound references from this object (in other words, all | |
3196 // the objects referenced by this object). | |
3197 // | |
3198 bool VM_HeapWalkOperation::visit(oop o) { | |
3199 // mark object as visited | |
3200 assert(!ObjectMarker::visited(o), "can't visit same object more than once"); | |
3201 ObjectMarker::mark(o); | |
3202 | |
3203 // instance | |
3204 if (o->is_instance()) { | |
1142 | 3205 if (o->klass() == SystemDictionary::Class_klass()) { |
0 | 3206 o = klassOop_if_java_lang_Class(o); |
3207 if (o->is_klass()) { | |
3208 // a java.lang.Class | |
3209 return iterate_over_class(klassOop(o)); | |
3210 } | |
3211 } else { | |
3212 return iterate_over_object(o); | |
3213 } | |
3214 } | |
3215 | |
3216 // object array | |
3217 if (o->is_objArray()) { | |
3218 return iterate_over_array(o); | |
3219 } | |
3220 | |
3221 // type array | |
3222 if (o->is_typeArray()) { | |
3223 return iterate_over_type_array(o); | |
3224 } | |
3225 | |
3226 return true; | |
3227 } | |
3228 | |
3229 void VM_HeapWalkOperation::doit() { | |
3230 ResourceMark rm; | |
3231 ObjectMarkerController marker; | |
3232 ClassFieldMapCacheMark cm; | |
3233 | |
3234 assert(visit_stack()->is_empty(), "visit stack must be empty"); | |
3235 | |
3236 // the heap walk starts with an initial object or the heap roots | |
3237 if (initial_object().is_null()) { | |
3238 if (!collect_simple_roots()) return; | |
3239 if (!collect_stack_roots()) return; | |
3240 } else { | |
3241 visit_stack()->push(initial_object()()); | |
3242 } | |
3243 | |
3244 // object references required | |
3245 if (is_following_references()) { | |
3246 | |
3247 // visit each object until all reachable objects have been | |
3248 // visited or the callback asked to terminate the iteration. | |
3249 while (!visit_stack()->is_empty()) { | |
3250 oop o = visit_stack()->pop(); | |
3251 if (!ObjectMarker::visited(o)) { | |
3252 if (!visit(o)) { | |
3253 break; | |
3254 } | |
3255 } | |
3256 } | |
3257 } | |
3258 } | |
3259 | |
3260 // iterate over all objects that are reachable from a set of roots | |
3261 void JvmtiTagMap::iterate_over_reachable_objects(jvmtiHeapRootCallback heap_root_callback, | |
3262 jvmtiStackReferenceCallback stack_ref_callback, | |
3263 jvmtiObjectReferenceCallback object_ref_callback, | |
3264 const void* user_data) { | |
3265 MutexLocker ml(Heap_lock); | |
3266 BasicHeapWalkContext context(heap_root_callback, stack_ref_callback, object_ref_callback); | |
3267 VM_HeapWalkOperation op(this, Handle(), context, user_data); | |
3268 VMThread::execute(&op); | |
3269 } | |
3270 | |
3271 // iterate over all objects that are reachable from a given object | |
3272 void JvmtiTagMap::iterate_over_objects_reachable_from_object(jobject object, | |
3273 jvmtiObjectReferenceCallback object_ref_callback, | |
3274 const void* user_data) { | |
3275 oop obj = JNIHandles::resolve(object); | |
3276 Handle initial_object(Thread::current(), obj); | |
3277 | |
3278 MutexLocker ml(Heap_lock); | |
3279 BasicHeapWalkContext context(NULL, NULL, object_ref_callback); | |
3280 VM_HeapWalkOperation op(this, initial_object, context, user_data); | |
3281 VMThread::execute(&op); | |
3282 } | |
3283 | |
3284 // follow references from an initial object or the GC roots | |
3285 void JvmtiTagMap::follow_references(jint heap_filter, | |
3286 KlassHandle klass, | |
3287 jobject object, | |
3288 const jvmtiHeapCallbacks* callbacks, | |
3289 const void* user_data) | |
3290 { | |
3291 oop obj = JNIHandles::resolve(object); | |
3292 Handle initial_object(Thread::current(), obj); | |
3293 | |
3294 MutexLocker ml(Heap_lock); | |
3295 AdvancedHeapWalkContext context(heap_filter, klass, callbacks); | |
3296 VM_HeapWalkOperation op(this, initial_object, context, user_data); | |
3297 VMThread::execute(&op); | |
3298 } | |
3299 | |
3300 | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3301 void JvmtiTagMap::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { |
2145
c1a0ede55d6f
7012493: 2/2 6849574/Test.java fails with Internal Error (src/share/vm/prims/jvmtiTagMap.cpp:3294)
dcubed
parents:
2125
diff
changeset
|
3302 // No locks during VM bring-up (0 threads) and no safepoints after main |
c1a0ede55d6f
7012493: 2/2 6849574/Test.java fails with Internal Error (src/share/vm/prims/jvmtiTagMap.cpp:3294)
dcubed
parents:
2125
diff
changeset
|
3303 // thread creation and before VMThread creation (1 thread); initial GC |
c1a0ede55d6f
7012493: 2/2 6849574/Test.java fails with Internal Error (src/share/vm/prims/jvmtiTagMap.cpp:3294)
dcubed
parents:
2125
diff
changeset
|
3304 // verification can happen in that window which gets to here. |
c1a0ede55d6f
7012493: 2/2 6849574/Test.java fails with Internal Error (src/share/vm/prims/jvmtiTagMap.cpp:3294)
dcubed
parents:
2125
diff
changeset
|
3305 assert(Threads::number_of_threads() <= 1 || |
c1a0ede55d6f
7012493: 2/2 6849574/Test.java fails with Internal Error (src/share/vm/prims/jvmtiTagMap.cpp:3294)
dcubed
parents:
2125
diff
changeset
|
3306 SafepointSynchronize::is_at_safepoint(), |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3307 "must be executed at a safepoint"); |
0 | 3308 if (JvmtiEnv::environments_might_exist()) { |
3309 JvmtiEnvIterator it; | |
3310 for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) { | |
3311 JvmtiTagMap* tag_map = env->tag_map(); | |
3312 if (tag_map != NULL && !tag_map->is_empty()) { | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3313 tag_map->do_weak_oops(is_alive, f); |
0 | 3314 } |
3315 } | |
3316 } | |
3317 } | |
3318 | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3319 void JvmtiTagMap::do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f) { |
0 | 3320 |
3321 // does this environment have the OBJECT_FREE event enabled | |
3322 bool post_object_free = env()->is_enabled(JVMTI_EVENT_OBJECT_FREE); | |
3323 | |
3324 // counters used for trace message | |
3325 int freed = 0; | |
3326 int moved = 0; | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3327 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3328 JvmtiTagHashmap* hashmap = this->hashmap(); |
0 | 3329 |
3330 // reenable sizing (if disabled) | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3331 hashmap->set_resizing_enabled(true); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3332 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3333 // if the hashmap is empty then we can skip it |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3334 if (hashmap->_entry_count == 0) { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3335 return; |
0 | 3336 } |
3337 | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3338 // now iterate through each entry in the table |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3339 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3340 JvmtiTagHashmapEntry** table = hashmap->table(); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3341 int size = hashmap->size(); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3342 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3343 JvmtiTagHashmapEntry* delayed_add = NULL; |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3344 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3345 for (int pos = 0; pos < size; ++pos) { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3346 JvmtiTagHashmapEntry* entry = table[pos]; |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3347 JvmtiTagHashmapEntry* prev = NULL; |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3348 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3349 while (entry != NULL) { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3350 JvmtiTagHashmapEntry* next = entry->next(); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3351 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3352 oop* obj = entry->object_addr(); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3353 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3354 // has object been GC'ed |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3355 if (!is_alive->do_object_b(entry->object())) { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3356 // grab the tag |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3357 jlong tag = entry->tag(); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3358 guarantee(tag != 0, "checking"); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3359 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3360 // remove GC'ed entry from hashmap and return the |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3361 // entry to the free list |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3362 hashmap->remove(prev, pos, entry); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3363 destroy_entry(entry); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3364 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3365 // post the event to the profiler |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3366 if (post_object_free) { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3367 JvmtiExport::post_object_free(env(), tag); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3368 } |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3369 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3370 ++freed; |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3371 } else { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3372 f->do_oop(entry->object_addr()); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3373 oop new_oop = entry->object(); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3374 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3375 // if the object has moved then re-hash it and move its |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3376 // entry to its new location. |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3377 unsigned int new_pos = JvmtiTagHashmap::hash(new_oop, size); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3378 if (new_pos != (unsigned int)pos) { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3379 if (prev == NULL) { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3380 table[pos] = next; |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3381 } else { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3382 prev->set_next(next); |
0 | 3383 } |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3384 if (new_pos < (unsigned int)pos) { |
0 | 3385 entry->set_next(table[new_pos]); |
3386 table[new_pos] = entry; | |
3387 } else { | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3388 // Delay adding this entry to it's new position as we'd end up |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3389 // hitting it again during this iteration. |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3390 entry->set_next(delayed_add); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3391 delayed_add = entry; |
0 | 3392 } |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3393 moved++; |
0 | 3394 } else { |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3395 // object didn't move |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3396 prev = entry; |
0 | 3397 } |
3398 } | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3399 |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3400 entry = next; |
0 | 3401 } |
3402 } | |
3403 | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3404 // Re-add all the entries which were kept aside |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3405 while (delayed_add != NULL) { |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3406 JvmtiTagHashmapEntry* next = delayed_add->next(); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3407 unsigned int pos = JvmtiTagHashmap::hash(delayed_add->object(), size); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3408 delayed_add->set_next(table[pos]); |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3409 table[pos] = delayed_add; |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3410 delayed_add = next; |
0 | 3411 } |
3412 | |
3413 // stats | |
3414 if (TraceJVMTIObjectTagging) { | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3415 int post_total = hashmap->_entry_count; |
0 | 3416 int pre_total = post_total + freed; |
3417 | |
2125
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3418 tty->print_cr("(%d->%d, %d freed, %d total moves)", |
7246a374a9f2
6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent
kamg
parents:
1972
diff
changeset
|
3419 pre_total, post_total, freed, moved); |
0 | 3420 } |
3421 } |