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