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