17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "precompiled.hpp"
26 #include "classfile/javaClasses.inline.hpp"
27 #include "classfile/symbolTable.hpp"
28 #include "classfile/systemDictionary.hpp"
29 #include "classfile/vmSymbols.hpp"
30 #include "code/codeCache.hpp"
31 #include "jvmtifiles/jvmtiEnv.hpp"
32 #include "memory/resourceArea.hpp"
33 #include "oops/instanceMirrorKlass.hpp"
34 #include "oops/objArrayKlass.hpp"
35 #include "oops/objArrayOop.inline.hpp"
36 #include "oops/oop.inline.hpp"
37 #include "prims/jvmtiEventController.hpp"
38 #include "prims/jvmtiEventController.inline.hpp"
39 #include "prims/jvmtiExport.hpp"
40 #include "prims/jvmtiImpl.hpp"
41 #include "prims/jvmtiTagMap.hpp"
42 #include "runtime/biasedLocking.hpp"
43 #include "runtime/javaCalls.hpp"
44 #include "runtime/jniHandles.hpp"
45 #include "runtime/mutex.hpp"
46 #include "runtime/mutexLocker.hpp"
47 #include "runtime/reflectionUtils.hpp"
48 #include "runtime/vframe.hpp"
49 #include "runtime/vmThread.hpp"
50 #include "runtime/vm_operations.hpp"
51 #include "services/serviceUtil.hpp"
52 #include "utilities/macros.hpp"
53 #if INCLUDE_ALL_GCS
54 #include "gc/g1/g1SATBCardTableModRefBS.hpp"
55 #include "gc/parallel/parallelScavengeHeap.hpp"
56 #endif // INCLUDE_ALL_GCS
57
58 // JvmtiTagHashmapEntry
59 //
60 // Each entry encapsulates a reference to the tagged object
61 // and the tag value. In addition an entry includes a next pointer which
62 // is used to chain entries together.
63
64 class JvmtiTagHashmapEntry : public CHeapObj<mtInternal> {
65 private:
66 friend class JvmtiTagMap;
67
68 oop _object; // tagged object
69 jlong _tag; // the tag
70 JvmtiTagHashmapEntry* _next; // next on the list
71
72 inline void init(oop object, jlong tag) {
73 _object = object;
74 _tag = tag;
75 _next = NULL;
76 }
77
78 // constructor
79 JvmtiTagHashmapEntry(oop object, jlong tag) { init(object, tag); }
80
81 public:
82
83 // accessor methods
84 inline oop object() const { return _object; }
85 inline oop* object_addr() { return &_object; }
86 inline jlong tag() const { return _tag; }
87
88 inline void set_tag(jlong tag) {
89 assert(tag != 0, "can't be zero");
90 _tag = tag;
91 }
92
93 inline JvmtiTagHashmapEntry* next() const { return _next; }
94 inline void set_next(JvmtiTagHashmapEntry* next) { _next = next; }
95 };
96
97
98 // JvmtiTagHashmap
99 //
100 // A hashmap is essentially a table of pointers to entries. Entries
101 // are hashed to a location, or position in the table, and then
102 // chained from that location. The "key" for hashing is address of
103 // the object, or oop. The "value" is the tag value.
104 //
105 // A hashmap maintains a count of the number entries in the hashmap
106 // and resizes if the number of entries exceeds a given threshold.
107 // The threshold is specified as a percentage of the size - for
108 // example a threshold of 0.75 will trigger the hashmap to resize
109 // if the number of entries is >75% of table size.
110 //
111 // A hashmap provides functions for adding, removing, and finding
112 // entries. It also provides a function to iterate over all entries
192 // allocate new table
193 size_t s = new_size * sizeof(JvmtiTagHashmapEntry*);
194 JvmtiTagHashmapEntry** new_table = (JvmtiTagHashmapEntry**)os::malloc(s, mtInternal);
195 if (new_table == NULL) {
196 warning("unable to allocate larger hashtable for jvmti object tags");
197 set_resizing_enabled(false);
198 return;
199 }
200
201 // initialize new table
202 int i;
203 for (i=0; i<new_size; i++) {
204 new_table[i] = NULL;
205 }
206
207 // rehash all entries into the new table
208 for (i=0; i<_size; i++) {
209 JvmtiTagHashmapEntry* entry = _table[i];
210 while (entry != NULL) {
211 JvmtiTagHashmapEntry* next = entry->next();
212 oop key = entry->object();
213 assert(key != NULL, "jni weak reference cleared!!");
214 unsigned int h = hash(key, new_size);
215 JvmtiTagHashmapEntry* anchor = new_table[h];
216 if (anchor == NULL) {
217 new_table[h] = entry;
218 entry->set_next(NULL);
219 } else {
220 entry->set_next(anchor);
221 new_table[h] = entry;
222 }
223 entry = next;
224 }
225 }
226
227 // free old table and update settings.
228 os::free((void*)_table);
229 _table = new_table;
230 _size_index = new_size_index;
231 _size = new_size;
232
285 }
286
287 // release table when JvmtiTagHashmap destroyed
288 ~JvmtiTagHashmap() {
289 if (_table != NULL) {
290 os::free((void*)_table);
291 _table = NULL;
292 }
293 }
294
295 // accessors
296 int size() const { return _size; }
297 JvmtiTagHashmapEntry** table() const { return _table; }
298 int entry_count() const { return _entry_count; }
299
300 // find an entry in the hashmap, returns NULL if not found.
301 inline JvmtiTagHashmapEntry* find(oop key) {
302 unsigned int h = hash(key);
303 JvmtiTagHashmapEntry* entry = _table[h];
304 while (entry != NULL) {
305 if (entry->object() == key) {
306 return entry;
307 }
308 entry = entry->next();
309 }
310 return NULL;
311 }
312
313
314 // add a new entry to hashmap
315 inline void add(oop key, JvmtiTagHashmapEntry* entry) {
316 assert(key != NULL, "checking");
317 assert(find(key) == NULL, "duplicate detected");
318 unsigned int h = hash(key);
319 JvmtiTagHashmapEntry* anchor = _table[h];
320 if (anchor == NULL) {
321 _table[h] = entry;
322 entry->set_next(NULL);
323 } else {
324 entry->set_next(anchor);
325 _table[h] = entry;
1516 TagObjectCollector(JvmtiEnv* env, const jlong* tags, jint tag_count) {
1517 _env = env;
1518 _tags = (jlong*)tags;
1519 _tag_count = tag_count;
1520 _object_results = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<jobject>(1,true);
1521 _tag_results = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<uint64_t>(1,true);
1522 }
1523
1524 ~TagObjectCollector() {
1525 delete _object_results;
1526 delete _tag_results;
1527 }
1528
1529 // for each tagged object check if the tag value matches
1530 // - if it matches then we create a JNI local reference to the object
1531 // and record the reference and tag value.
1532 //
1533 void do_entry(JvmtiTagHashmapEntry* entry) {
1534 for (int i=0; i<_tag_count; i++) {
1535 if (_tags[i] == entry->tag()) {
1536 oop o = entry->object();
1537 assert(o != NULL && Universe::heap()->is_in_reserved(o), "sanity check");
1538 #if INCLUDE_ALL_GCS
1539 if (UseG1GC) {
1540 // The reference in this tag map could be the only (implicitly weak)
1541 // reference to that object. If we hand it out, we need to keep it live wrt
1542 // SATB marking similar to other j.l.ref.Reference referents.
1543 G1SATBCardTableModRefBS::enqueue(o);
1544 }
1545 #endif
1546 jobject ref = JNIHandles::make_local(JavaThread::current(), o);
1547 _object_results->append(ref);
1548 _tag_results->append((uint64_t)entry->tag());
1549 }
1550 }
1551 }
1552
1553 // return the results from the collection
1554 //
1555 jvmtiError result(jint* count_ptr, jobject** object_result_ptr, jlong** tag_result_ptr) {
1556 jvmtiError error;
1557 int count = _object_results->length();
1558 assert(count >= 0, "sanity check");
1559
1560 // if object_result_ptr is not NULL then allocate the result and copy
1561 // in the object references.
1562 if (object_result_ptr != NULL) {
1563 error = _env->Allocate(count * sizeof(jobject), (unsigned char**)object_result_ptr);
1564 if (error != JVMTI_ERROR_NONE) {
1565 return error;
3345
3346 // if the hashmap is empty then we can skip it
3347 if (hashmap->_entry_count == 0) {
3348 return;
3349 }
3350
3351 // now iterate through each entry in the table
3352
3353 JvmtiTagHashmapEntry** table = hashmap->table();
3354 int size = hashmap->size();
3355
3356 JvmtiTagHashmapEntry* delayed_add = NULL;
3357
3358 for (int pos = 0; pos < size; ++pos) {
3359 JvmtiTagHashmapEntry* entry = table[pos];
3360 JvmtiTagHashmapEntry* prev = NULL;
3361
3362 while (entry != NULL) {
3363 JvmtiTagHashmapEntry* next = entry->next();
3364
3365 oop* obj = entry->object_addr();
3366
3367 // has object been GC'ed
3368 if (!is_alive->do_object_b(entry->object())) {
3369 // grab the tag
3370 jlong tag = entry->tag();
3371 guarantee(tag != 0, "checking");
3372
3373 // remove GC'ed entry from hashmap and return the
3374 // entry to the free list
3375 hashmap->remove(prev, pos, entry);
3376 destroy_entry(entry);
3377
3378 // post the event to the profiler
3379 if (post_object_free) {
3380 JvmtiExport::post_object_free(env(), tag);
3381 }
3382
3383 ++freed;
3384 } else {
3385 f->do_oop(entry->object_addr());
3386 oop new_oop = entry->object();
3387
3388 // if the object has moved then re-hash it and move its
3389 // entry to its new location.
3390 unsigned int new_pos = JvmtiTagHashmap::hash(new_oop, size);
3391 if (new_pos != (unsigned int)pos) {
3392 if (prev == NULL) {
3393 table[pos] = next;
3394 } else {
3395 prev->set_next(next);
3396 }
3397 if (new_pos < (unsigned int)pos) {
3398 entry->set_next(table[new_pos]);
3399 table[new_pos] = entry;
3400 } else {
3401 // Delay adding this entry to it's new position as we'd end up
3402 // hitting it again during this iteration.
3403 entry->set_next(delayed_add);
3404 delayed_add = entry;
3405 }
3406 moved++;
3407 } else {
3408 // object didn't move
3409 prev = entry;
3410 }
3411 }
3412
3413 entry = next;
3414 }
3415 }
3416
3417 // Re-add all the entries which were kept aside
3418 while (delayed_add != NULL) {
3419 JvmtiTagHashmapEntry* next = delayed_add->next();
3420 unsigned int pos = JvmtiTagHashmap::hash(delayed_add->object(), size);
3421 delayed_add->set_next(table[pos]);
3422 table[pos] = delayed_add;
3423 delayed_add = next;
3424 }
3425
3426 log_debug(jvmti, objecttagging)("(%d->%d, %d freed, %d total moves)",
3427 hashmap->_entry_count + freed, hashmap->_entry_count, freed, moved);
3428 }
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "precompiled.hpp"
26 #include "classfile/javaClasses.inline.hpp"
27 #include "classfile/symbolTable.hpp"
28 #include "classfile/systemDictionary.hpp"
29 #include "classfile/vmSymbols.hpp"
30 #include "code/codeCache.hpp"
31 #include "jvmtifiles/jvmtiEnv.hpp"
32 #include "memory/resourceArea.hpp"
33 #include "oops/instanceMirrorKlass.hpp"
34 #include "oops/objArrayKlass.hpp"
35 #include "oops/objArrayOop.inline.hpp"
36 #include "oops/oop.inline.hpp"
37 #include "oops/typeArrayOop.inline.hpp"
38 #include "prims/jvmtiEventController.hpp"
39 #include "prims/jvmtiEventController.inline.hpp"
40 #include "prims/jvmtiExport.hpp"
41 #include "prims/jvmtiImpl.hpp"
42 #include "prims/jvmtiTagMap.hpp"
43 #include "runtime/access.inline.hpp"
44 #include "runtime/biasedLocking.hpp"
45 #include "runtime/javaCalls.hpp"
46 #include "runtime/jniHandles.hpp"
47 #include "runtime/mutex.hpp"
48 #include "runtime/mutexLocker.hpp"
49 #include "runtime/reflectionUtils.hpp"
50 #include "runtime/vframe.hpp"
51 #include "runtime/vmThread.hpp"
52 #include "runtime/vm_operations.hpp"
53 #include "services/serviceUtil.hpp"
54 #include "utilities/macros.hpp"
55
56 // JvmtiTagHashmapEntry
57 //
58 // Each entry encapsulates a reference to the tagged object
59 // and the tag value. In addition an entry includes a next pointer which
60 // is used to chain entries together.
61
62 class JvmtiTagHashmapEntry : public CHeapObj<mtInternal> {
63 private:
64 friend class JvmtiTagMap;
65
66 oop _object; // tagged object
67 jlong _tag; // the tag
68 JvmtiTagHashmapEntry* _next; // next on the list
69
70 inline void init(oop object, jlong tag) {
71 _object = object;
72 _tag = tag;
73 _next = NULL;
74 }
75
76 // constructor
77 JvmtiTagHashmapEntry(oop object, jlong tag) { init(object, tag); }
78
79 public:
80
81 // accessor methods
82 inline oop* object_addr() { return &_object; }
83 inline oop object() { return RootAccess<GC_ACCESS_ON_PHANTOM>::oop_load(object_addr()); }
84 // Load the object weakly. The returned object is not allowed to be seen by the GC.
85 inline oop load_object_weakly() { return RootAccess<ACCESS_WEAK | GC_ACCESS_ON_PHANTOM>::oop_load(object_addr()); }
86 inline jlong tag() const { return _tag; }
87
88 inline void set_tag(jlong tag) {
89 assert(tag != 0, "can't be zero");
90 _tag = tag;
91 }
92
93 inline bool equals(oop object) {
94 return object == load_object_weakly();
95 }
96
97 inline JvmtiTagHashmapEntry* next() const { return _next; }
98 inline void set_next(JvmtiTagHashmapEntry* next) { _next = next; }
99 };
100
101
102 // JvmtiTagHashmap
103 //
104 // A hashmap is essentially a table of pointers to entries. Entries
105 // are hashed to a location, or position in the table, and then
106 // chained from that location. The "key" for hashing is address of
107 // the object, or oop. The "value" is the tag value.
108 //
109 // A hashmap maintains a count of the number entries in the hashmap
110 // and resizes if the number of entries exceeds a given threshold.
111 // The threshold is specified as a percentage of the size - for
112 // example a threshold of 0.75 will trigger the hashmap to resize
113 // if the number of entries is >75% of table size.
114 //
115 // A hashmap provides functions for adding, removing, and finding
116 // entries. It also provides a function to iterate over all entries
196 // allocate new table
197 size_t s = new_size * sizeof(JvmtiTagHashmapEntry*);
198 JvmtiTagHashmapEntry** new_table = (JvmtiTagHashmapEntry**)os::malloc(s, mtInternal);
199 if (new_table == NULL) {
200 warning("unable to allocate larger hashtable for jvmti object tags");
201 set_resizing_enabled(false);
202 return;
203 }
204
205 // initialize new table
206 int i;
207 for (i=0; i<new_size; i++) {
208 new_table[i] = NULL;
209 }
210
211 // rehash all entries into the new table
212 for (i=0; i<_size; i++) {
213 JvmtiTagHashmapEntry* entry = _table[i];
214 while (entry != NULL) {
215 JvmtiTagHashmapEntry* next = entry->next();
216 oop key = entry->load_object_weakly();
217 assert(key != NULL, "jni weak reference cleared!!");
218 unsigned int h = hash(key, new_size);
219 JvmtiTagHashmapEntry* anchor = new_table[h];
220 if (anchor == NULL) {
221 new_table[h] = entry;
222 entry->set_next(NULL);
223 } else {
224 entry->set_next(anchor);
225 new_table[h] = entry;
226 }
227 entry = next;
228 }
229 }
230
231 // free old table and update settings.
232 os::free((void*)_table);
233 _table = new_table;
234 _size_index = new_size_index;
235 _size = new_size;
236
289 }
290
291 // release table when JvmtiTagHashmap destroyed
292 ~JvmtiTagHashmap() {
293 if (_table != NULL) {
294 os::free((void*)_table);
295 _table = NULL;
296 }
297 }
298
299 // accessors
300 int size() const { return _size; }
301 JvmtiTagHashmapEntry** table() const { return _table; }
302 int entry_count() const { return _entry_count; }
303
304 // find an entry in the hashmap, returns NULL if not found.
305 inline JvmtiTagHashmapEntry* find(oop key) {
306 unsigned int h = hash(key);
307 JvmtiTagHashmapEntry* entry = _table[h];
308 while (entry != NULL) {
309 if (entry->equals(key)) {
310 return entry;
311 }
312 entry = entry->next();
313 }
314 return NULL;
315 }
316
317
318 // add a new entry to hashmap
319 inline void add(oop key, JvmtiTagHashmapEntry* entry) {
320 assert(key != NULL, "checking");
321 assert(find(key) == NULL, "duplicate detected");
322 unsigned int h = hash(key);
323 JvmtiTagHashmapEntry* anchor = _table[h];
324 if (anchor == NULL) {
325 _table[h] = entry;
326 entry->set_next(NULL);
327 } else {
328 entry->set_next(anchor);
329 _table[h] = entry;
1520 TagObjectCollector(JvmtiEnv* env, const jlong* tags, jint tag_count) {
1521 _env = env;
1522 _tags = (jlong*)tags;
1523 _tag_count = tag_count;
1524 _object_results = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<jobject>(1,true);
1525 _tag_results = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<uint64_t>(1,true);
1526 }
1527
1528 ~TagObjectCollector() {
1529 delete _object_results;
1530 delete _tag_results;
1531 }
1532
1533 // for each tagged object check if the tag value matches
1534 // - if it matches then we create a JNI local reference to the object
1535 // and record the reference and tag value.
1536 //
1537 void do_entry(JvmtiTagHashmapEntry* entry) {
1538 for (int i=0; i<_tag_count; i++) {
1539 if (_tags[i] == entry->tag()) {
1540 oop* p = entry->object_addr();
1541 // The reference in this tag map could be the only (implicitly weak)
1542 // reference to that object. If we hand it out, we need to keep it live wrt
1543 // SATB marking similar to other j.l.ref.Reference referents.
1544 oop o = RootAccess<GC_ACCESS_ON_PHANTOM>::oop_load(p);
1545 assert(o != NULL && Universe::heap()->is_in_reserved(o), "sanity check");
1546 jobject ref = JNIHandles::make_local(JavaThread::current(), o);
1547 _object_results->append(ref);
1548 _tag_results->append((uint64_t)entry->tag());
1549 }
1550 }
1551 }
1552
1553 // return the results from the collection
1554 //
1555 jvmtiError result(jint* count_ptr, jobject** object_result_ptr, jlong** tag_result_ptr) {
1556 jvmtiError error;
1557 int count = _object_results->length();
1558 assert(count >= 0, "sanity check");
1559
1560 // if object_result_ptr is not NULL then allocate the result and copy
1561 // in the object references.
1562 if (object_result_ptr != NULL) {
1563 error = _env->Allocate(count * sizeof(jobject), (unsigned char**)object_result_ptr);
1564 if (error != JVMTI_ERROR_NONE) {
1565 return error;
3345
3346 // if the hashmap is empty then we can skip it
3347 if (hashmap->_entry_count == 0) {
3348 return;
3349 }
3350
3351 // now iterate through each entry in the table
3352
3353 JvmtiTagHashmapEntry** table = hashmap->table();
3354 int size = hashmap->size();
3355
3356 JvmtiTagHashmapEntry* delayed_add = NULL;
3357
3358 for (int pos = 0; pos < size; ++pos) {
3359 JvmtiTagHashmapEntry* entry = table[pos];
3360 JvmtiTagHashmapEntry* prev = NULL;
3361
3362 while (entry != NULL) {
3363 JvmtiTagHashmapEntry* next = entry->next();
3364
3365 // has object been GC'ed
3366 if (!is_alive->do_object_b(entry->load_object_weakly())) {
3367 // grab the tag
3368 jlong tag = entry->tag();
3369 guarantee(tag != 0, "checking");
3370
3371 // remove GC'ed entry from hashmap and return the
3372 // entry to the free list
3373 hashmap->remove(prev, pos, entry);
3374 destroy_entry(entry);
3375
3376 // post the event to the profiler
3377 if (post_object_free) {
3378 JvmtiExport::post_object_free(env(), tag);
3379 }
3380
3381 ++freed;
3382 } else {
3383 f->do_oop(entry->object_addr());
3384 oop new_oop = entry->load_object_weakly();
3385
3386 // if the object has moved then re-hash it and move its
3387 // entry to its new location.
3388 unsigned int new_pos = JvmtiTagHashmap::hash(new_oop, size);
3389 if (new_pos != (unsigned int)pos) {
3390 if (prev == NULL) {
3391 table[pos] = next;
3392 } else {
3393 prev->set_next(next);
3394 }
3395 if (new_pos < (unsigned int)pos) {
3396 entry->set_next(table[new_pos]);
3397 table[new_pos] = entry;
3398 } else {
3399 // Delay adding this entry to it's new position as we'd end up
3400 // hitting it again during this iteration.
3401 entry->set_next(delayed_add);
3402 delayed_add = entry;
3403 }
3404 moved++;
3405 } else {
3406 // object didn't move
3407 prev = entry;
3408 }
3409 }
3410
3411 entry = next;
3412 }
3413 }
3414
3415 // Re-add all the entries which were kept aside
3416 while (delayed_add != NULL) {
3417 JvmtiTagHashmapEntry* next = delayed_add->next();
3418 unsigned int pos = JvmtiTagHashmap::hash(delayed_add->load_object_weakly(), size);
3419 delayed_add->set_next(table[pos]);
3420 table[pos] = delayed_add;
3421 delayed_add = next;
3422 }
3423
3424 log_debug(jvmti, objecttagging)("(%d->%d, %d freed, %d total moves)",
3425 hashmap->_entry_count + freed, hashmap->_entry_count, freed, moved);
3426 }
|