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