comparison src/share/vm/prims/jvmtiTagMap.cpp @ 2125:7246a374a9f2

6458402: 3 jvmti tests fail with CMS and +ExplicitGCInvokesConcurrent Summary: Make JvmtiGCMark safe to run non-safepoint and instrument CMS Reviewed-by: ysr, dcubed
author kamg
date Mon, 10 Jan 2011 17:14:53 -0500
parents f95d63e2154a
children c1a0ede55d6f
comparison
equal deleted inserted replaced
2124:e31d8c656c5b 2125:7246a374a9f2
48 #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" 48 #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp"
49 #endif 49 #endif
50 50
51 // JvmtiTagHashmapEntry 51 // JvmtiTagHashmapEntry
52 // 52 //
53 // Each entry encapsulates a JNI weak reference to the tagged object 53 // Each entry encapsulates a reference to the tagged object
54 // and the tag value. In addition an entry includes a next pointer which 54 // and the tag value. In addition an entry includes a next pointer which
55 // is used to chain entries together. 55 // is used to chain entries together.
56 56
57 class JvmtiTagHashmapEntry : public CHeapObj { 57 class JvmtiTagHashmapEntry : public CHeapObj {
58 private: 58 private:
59 friend class JvmtiTagMap; 59 friend class JvmtiTagMap;
60 60
61 jweak _object; // JNI weak ref to tagged object 61 oop _object; // tagged object
62 jlong _tag; // the tag 62 jlong _tag; // the tag
63 JvmtiTagHashmapEntry* _next; // next on the list 63 JvmtiTagHashmapEntry* _next; // next on the list
64 64
65 inline void init(jweak object, jlong tag) { 65 inline void init(oop object, jlong tag) {
66 _object = object; 66 _object = object;
67 _tag = tag; 67 _tag = tag;
68 _next = NULL; 68 _next = NULL;
69 } 69 }
70 70
71 // constructor 71 // constructor
72 JvmtiTagHashmapEntry(jweak object, jlong tag) { init(object, tag); } 72 JvmtiTagHashmapEntry(oop object, jlong tag) { init(object, tag); }
73 73
74 public: 74 public:
75 75
76 // accessor methods 76 // accessor methods
77 inline jweak object() const { return _object; } 77 inline oop object() const { return _object; }
78 inline jlong tag() const { return _tag; } 78 inline oop* object_addr() { return &_object; }
79 inline jlong tag() const { return _tag; }
79 80
80 inline void set_tag(jlong tag) { 81 inline void set_tag(jlong tag) {
81 assert(tag != 0, "can't be zero"); 82 assert(tag != 0, "can't be zero");
82 _tag = tag; 83 _tag = tag;
83 } 84 }
90 // JvmtiTagHashmap 91 // JvmtiTagHashmap
91 // 92 //
92 // A hashmap is essentially a table of pointers to entries. Entries 93 // A hashmap is essentially a table of pointers to entries. Entries
93 // are hashed to a location, or position in the table, and then 94 // are hashed to a location, or position in the table, and then
94 // chained from that location. The "key" for hashing is address of 95 // chained from that location. The "key" for hashing is address of
95 // the object, or oop. The "value" is the JNI weak reference to the 96 // the object, or oop. The "value" is the tag value.
96 // object and the tag value. Keys are not stored with the entry.
97 // Instead the weak reference is resolved to obtain the key.
98 // 97 //
99 // A hashmap maintains a count of the number entries in the hashmap 98 // A hashmap maintains a count of the number entries in the hashmap
100 // and resizes if the number of entries exceeds a given threshold. 99 // and resizes if the number of entries exceeds a given threshold.
101 // The threshold is specified as a percentage of the size - for 100 // The threshold is specified as a percentage of the size - for
102 // example a threshold of 0.75 will trigger the hashmap to resize 101 // example a threshold of 0.75 will trigger the hashmap to resize
204 // rehash all entries into the new table 203 // rehash all entries into the new table
205 for (i=0; i<_size; i++) { 204 for (i=0; i<_size; i++) {
206 JvmtiTagHashmapEntry* entry = _table[i]; 205 JvmtiTagHashmapEntry* entry = _table[i];
207 while (entry != NULL) { 206 while (entry != NULL) {
208 JvmtiTagHashmapEntry* next = entry->next(); 207 JvmtiTagHashmapEntry* next = entry->next();
209 oop key = JNIHandles::resolve(entry->object()); 208 oop key = entry->object();
210 assert(key != NULL, "jni weak reference cleared!!"); 209 assert(key != NULL, "jni weak reference cleared!!");
211 unsigned int h = hash(key, new_size); 210 unsigned int h = hash(key, new_size);
212 JvmtiTagHashmapEntry* anchor = new_table[h]; 211 JvmtiTagHashmapEntry* anchor = new_table[h];
213 if (anchor == NULL) { 212 if (anchor == NULL) {
214 new_table[h] = entry; 213 new_table[h] = entry;
297 // find an entry in the hashmap, returns NULL if not found. 296 // find an entry in the hashmap, returns NULL if not found.
298 inline JvmtiTagHashmapEntry* find(oop key) { 297 inline JvmtiTagHashmapEntry* find(oop key) {
299 unsigned int h = hash(key); 298 unsigned int h = hash(key);
300 JvmtiTagHashmapEntry* entry = _table[h]; 299 JvmtiTagHashmapEntry* entry = _table[h];
301 while (entry != NULL) { 300 while (entry != NULL) {
302 oop orig_key = JNIHandles::resolve(entry->object()); 301 if (entry->object() == key) {
303 assert(orig_key != NULL, "jni weak reference cleared!!"); 302 return entry;
304 if (key == orig_key) {
305 break;
306 } 303 }
307 entry = entry->next(); 304 entry = entry->next();
308 } 305 }
309 return entry; 306 return NULL;
310 } 307 }
311 308
312 309
313 // add a new entry to hashmap 310 // add a new entry to hashmap
314 inline void add(oop key, JvmtiTagHashmapEntry* entry) { 311 inline void add(oop key, JvmtiTagHashmapEntry* entry) {
341 inline JvmtiTagHashmapEntry* remove(oop key) { 338 inline JvmtiTagHashmapEntry* remove(oop key) {
342 unsigned int h = hash(key); 339 unsigned int h = hash(key);
343 JvmtiTagHashmapEntry* entry = _table[h]; 340 JvmtiTagHashmapEntry* entry = _table[h];
344 JvmtiTagHashmapEntry* prev = NULL; 341 JvmtiTagHashmapEntry* prev = NULL;
345 while (entry != NULL) { 342 while (entry != NULL) {
346 oop orig_key = JNIHandles::resolve(entry->object()); 343 if (key == entry->object()) {
347 assert(orig_key != NULL, "jni weak reference cleared!!");
348 if (key == orig_key) {
349 break; 344 break;
350 } 345 }
351 prev = entry; 346 prev = entry;
352 entry = entry->next(); 347 entry = entry->next();
353 } 348 }
416 _trace_threshold += large_trace_threshold; 411 _trace_threshold += large_trace_threshold;
417 } 412 }
418 } 413 }
419 } 414 }
420 415
421 // memory region for young generation
422 MemRegion JvmtiTagMap::_young_gen;
423
424 // get the memory region used for the young generation
425 void JvmtiTagMap::get_young_generation() {
426 CollectedHeap* ch = Universe::heap();
427 switch (ch->kind()) {
428 case (CollectedHeap::GenCollectedHeap): {
429 _young_gen = ((GenCollectedHeap*)ch)->get_gen(0)->reserved();
430 break;
431 }
432 #ifndef SERIALGC
433 case (CollectedHeap::ParallelScavengeHeap): {
434 _young_gen = ((ParallelScavengeHeap*)ch)->young_gen()->reserved();
435 break;
436 }
437 case (CollectedHeap::G1CollectedHeap): {
438 // Until a more satisfactory solution is implemented, all
439 // oops in the tag map will require rehash at each gc.
440 // This is a correct, if extremely inefficient solution.
441 // See RFE 6621729 for related commentary.
442 _young_gen = ch->reserved_region();
443 break;
444 }
445 #endif // !SERIALGC
446 default:
447 ShouldNotReachHere();
448 }
449 }
450
451 // returns true if oop is in the young generation
452 inline bool JvmtiTagMap::is_in_young(oop o) {
453 assert(_young_gen.start() != NULL, "checking");
454 void* p = (void*)o;
455 bool in_young = _young_gen.contains(p);
456 return in_young;
457 }
458
459 // returns the appropriate hashmap for a given object
460 inline JvmtiTagHashmap* JvmtiTagMap::hashmap_for(oop o) {
461 if (is_in_young(o)) {
462 return _hashmap[0];
463 } else {
464 return _hashmap[1];
465 }
466 }
467
468
469 // create a JvmtiTagMap 416 // create a JvmtiTagMap
470 JvmtiTagMap::JvmtiTagMap(JvmtiEnv* env) : 417 JvmtiTagMap::JvmtiTagMap(JvmtiEnv* env) :
471 _env(env), 418 _env(env),
472 _lock(Mutex::nonleaf+2, "JvmtiTagMap._lock", false), 419 _lock(Mutex::nonleaf+2, "JvmtiTagMap._lock", false),
473 _free_entries(NULL), 420 _free_entries(NULL),
474 _free_entries_count(0) 421 _free_entries_count(0)
475 { 422 {
476 assert(JvmtiThreadState_lock->is_locked(), "sanity check"); 423 assert(JvmtiThreadState_lock->is_locked(), "sanity check");
477 assert(((JvmtiEnvBase *)env)->tag_map() == NULL, "tag map already exists for environment"); 424 assert(((JvmtiEnvBase *)env)->tag_map() == NULL, "tag map already exists for environment");
478 425
479 // create the hashmaps 426 _hashmap = new JvmtiTagHashmap();
480 for (int i=0; i<n_hashmaps; i++) {
481 _hashmap[i] = new JvmtiTagHashmap();
482 }
483
484 // get the memory region used by the young generation
485 get_young_generation();
486 427
487 // finally add us to the environment 428 // finally add us to the environment
488 ((JvmtiEnvBase *)env)->set_tag_map(this); 429 ((JvmtiEnvBase *)env)->set_tag_map(this);
489 } 430 }
490 431
494 435
495 // no lock acquired as we assume the enclosing environment is 436 // no lock acquired as we assume the enclosing environment is
496 // also being destroryed. 437 // also being destroryed.
497 ((JvmtiEnvBase *)_env)->set_tag_map(NULL); 438 ((JvmtiEnvBase *)_env)->set_tag_map(NULL);
498 439
499 // iterate over the hashmaps and destroy each of the entries 440 JvmtiTagHashmapEntry** table = _hashmap->table();
500 for (int i=0; i<n_hashmaps; i++) { 441 for (int j = 0; j < _hashmap->size(); j++) {
501 JvmtiTagHashmap* hashmap = _hashmap[i]; 442 JvmtiTagHashmapEntry* entry = table[j];
502 JvmtiTagHashmapEntry** table = hashmap->table(); 443 while (entry != NULL) {
503 for (int j=0; j<hashmap->size(); j++) { 444 JvmtiTagHashmapEntry* next = entry->next();
504 JvmtiTagHashmapEntry *entry = table[j]; 445 delete entry;
505 while (entry != NULL) { 446 entry = next;
506 JvmtiTagHashmapEntry* next = entry->next(); 447 }
507 jweak ref = entry->object(); 448 }
508 JNIHandles::destroy_weak_global(ref); 449
509 delete entry; 450 // finally destroy the hashmap
510 entry = next; 451 delete _hashmap;
511 } 452 _hashmap = NULL;
512 }
513
514 // finally destroy the hashmap
515 delete hashmap;
516 }
517 453
518 // remove any entries on the free list 454 // remove any entries on the free list
519 JvmtiTagHashmapEntry* entry = _free_entries; 455 JvmtiTagHashmapEntry* entry = _free_entries;
520 while (entry != NULL) { 456 while (entry != NULL) {
521 JvmtiTagHashmapEntry* next = entry->next(); 457 JvmtiTagHashmapEntry* next = entry->next();
522 delete entry; 458 delete entry;
523 entry = next; 459 entry = next;
524 } 460 }
461 _free_entries = NULL;
525 } 462 }
526 463
527 // create a hashmap entry 464 // create a hashmap entry
528 // - if there's an entry on the (per-environment) free list then this 465 // - if there's an entry on the (per-environment) free list then this
529 // is returned. Otherwise an new entry is allocated. 466 // is returned. Otherwise an new entry is allocated.
530 JvmtiTagHashmapEntry* JvmtiTagMap::create_entry(jweak ref, jlong tag) { 467 JvmtiTagHashmapEntry* JvmtiTagMap::create_entry(oop ref, jlong tag) {
531 assert(Thread::current()->is_VM_thread() || is_locked(), "checking"); 468 assert(Thread::current()->is_VM_thread() || is_locked(), "checking");
532 JvmtiTagHashmapEntry* entry; 469 JvmtiTagHashmapEntry* entry;
533 if (_free_entries == NULL) { 470 if (_free_entries == NULL) {
534 entry = new JvmtiTagHashmapEntry(ref, tag); 471 entry = new JvmtiTagHashmapEntry(ref, tag);
535 } else { 472 } else {
556 } 493 }
557 494
558 // returns the tag map for the given environments. If the tag map 495 // returns the tag map for the given environments. If the tag map
559 // doesn't exist then it is created. 496 // doesn't exist then it is created.
560 JvmtiTagMap* JvmtiTagMap::tag_map_for(JvmtiEnv* env) { 497 JvmtiTagMap* JvmtiTagMap::tag_map_for(JvmtiEnv* env) {
561 JvmtiTagMap* tag_map = ((JvmtiEnvBase *)env)->tag_map(); 498 JvmtiTagMap* tag_map = ((JvmtiEnvBase*)env)->tag_map();
562 if (tag_map == NULL) { 499 if (tag_map == NULL) {
563 MutexLocker mu(JvmtiThreadState_lock); 500 MutexLocker mu(JvmtiThreadState_lock);
564 tag_map = ((JvmtiEnvBase *)env)->tag_map(); 501 tag_map = ((JvmtiEnvBase*)env)->tag_map();
565 if (tag_map == NULL) { 502 if (tag_map == NULL) {
566 tag_map = new JvmtiTagMap(env); 503 tag_map = new JvmtiTagMap(env);
567 } 504 }
568 } else { 505 } else {
569 CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); 506 CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
571 return tag_map; 508 return tag_map;
572 } 509 }
573 510
574 // iterate over all entries in the tag map. 511 // iterate over all entries in the tag map.
575 void JvmtiTagMap::entry_iterate(JvmtiTagHashmapEntryClosure* closure) { 512 void JvmtiTagMap::entry_iterate(JvmtiTagHashmapEntryClosure* closure) {
576 for (int i=0; i<n_hashmaps; i++) { 513 hashmap()->entry_iterate(closure);
577 JvmtiTagHashmap* hashmap = _hashmap[i];
578 hashmap->entry_iterate(closure);
579 }
580 } 514 }
581 515
582 // returns true if the hashmaps are empty 516 // returns true if the hashmaps are empty
583 bool JvmtiTagMap::is_empty() { 517 bool JvmtiTagMap::is_empty() {
584 assert(SafepointSynchronize::is_at_safepoint() || is_locked(), "checking"); 518 assert(SafepointSynchronize::is_at_safepoint() || is_locked(), "checking");
585 assert(n_hashmaps == 2, "not implemented"); 519 return hashmap()->entry_count() == 0;
586 return ((_hashmap[0]->entry_count() == 0) && (_hashmap[1]->entry_count() == 0));
587 } 520 }
588 521
589 522
590 // Return the tag value for an object, or 0 if the object is 523 // Return the tag value for an object, or 0 if the object is
591 // not tagged 524 // not tagged
592 // 525 //
593 static inline jlong tag_for(JvmtiTagMap* tag_map, oop o) { 526 static inline jlong tag_for(JvmtiTagMap* tag_map, oop o) {
594 JvmtiTagHashmapEntry* entry = tag_map->hashmap_for(o)->find(o); 527 JvmtiTagHashmapEntry* entry = tag_map->hashmap()->find(o);
595 if (entry == NULL) { 528 if (entry == NULL) {
596 return 0; 529 return 0;
597 } else { 530 } else {
598 return entry->tag(); 531 return entry->tag();
599 } 532 }
653 // object size 586 // object size
654 _obj_size = _o->size() * wordSize; 587 _obj_size = _o->size() * wordSize;
655 588
656 // record the context 589 // record the context
657 _tag_map = tag_map; 590 _tag_map = tag_map;
658 _hashmap = tag_map->hashmap_for(_o); 591 _hashmap = tag_map->hashmap();
659 _entry = _hashmap->find(_o); 592 _entry = _hashmap->find(_o);
660 593
661 // get object tag 594 // get object tag
662 _obj_tag = (_entry == NULL) ? 0 : _entry->tag(); 595 _obj_tag = (_entry == NULL) ? 0 : _entry->tag();
663 596
692 jlong obj_tag) { 625 jlong obj_tag) {
693 if (entry == NULL) { 626 if (entry == NULL) {
694 if (obj_tag != 0) { 627 if (obj_tag != 0) {
695 // callback has tagged the object 628 // callback has tagged the object
696 assert(Thread::current()->is_VM_thread(), "must be VMThread"); 629 assert(Thread::current()->is_VM_thread(), "must be VMThread");
697 HandleMark hm; 630 entry = tag_map()->create_entry(o, obj_tag);
698 Handle h(o);
699 jweak ref = JNIHandles::make_weak_global(h);
700 entry = tag_map()->create_entry(ref, obj_tag);
701 hashmap->add(o, entry); 631 hashmap->add(o, entry);
702 } 632 }
703 } else { 633 } else {
704 // object was previously tagged - the callback may have untagged 634 // object was previously tagged - the callback may have untagged
705 // the object or changed the tag value 635 // the object or changed the tag value
706 if (obj_tag == 0) { 636 if (obj_tag == 0) {
707 jweak ref = entry->object();
708 637
709 JvmtiTagHashmapEntry* entry_removed = hashmap->remove(o); 638 JvmtiTagHashmapEntry* entry_removed = hashmap->remove(o);
710 assert(entry_removed == entry, "checking"); 639 assert(entry_removed == entry, "checking");
711 tag_map()->destroy_entry(entry); 640 tag_map()->destroy_entry(entry);
712 641
713 JNIHandles::destroy_weak_global(ref);
714 } else { 642 } else {
715 if (obj_tag != entry->tag()) { 643 if (obj_tag != entry->tag()) {
716 entry->set_tag(obj_tag); 644 entry->set_tag(obj_tag);
717 } 645 }
718 } 646 }
758 _referrer_tag_p = obj_tag_p(); 686 _referrer_tag_p = obj_tag_p();
759 } else { 687 } else {
760 // for Classes the klassOop is tagged 688 // for Classes the klassOop is tagged
761 _referrer = klassOop_if_java_lang_Class(referrer); 689 _referrer = klassOop_if_java_lang_Class(referrer);
762 // record the context 690 // record the context
763 _referrer_hashmap = tag_map->hashmap_for(_referrer); 691 _referrer_hashmap = tag_map->hashmap();
764 _referrer_entry = _referrer_hashmap->find(_referrer); 692 _referrer_entry = _referrer_hashmap->find(_referrer);
765 693
766 // get object tag 694 // get object tag
767 _referrer_obj_tag = (_referrer_entry == NULL) ? 0 : _referrer_entry->tag(); 695 _referrer_obj_tag = (_referrer_entry == NULL) ? 0 : _referrer_entry->tag();
768 _referrer_tag_p = &_referrer_obj_tag; 696 _referrer_tag_p = &_referrer_obj_tag;
794 722
795 // tag an object 723 // tag an object
796 // 724 //
797 // This function is performance critical. If many threads attempt to tag objects 725 // This function is performance critical. If many threads attempt to tag objects
798 // around the same time then it's possible that the Mutex associated with the 726 // around the same time then it's possible that the Mutex associated with the
799 // tag map will be a hot lock. Eliminating this lock will not eliminate the issue 727 // tag map will be a hot lock.
800 // because creating a JNI weak reference requires acquiring a global lock also.
801 void JvmtiTagMap::set_tag(jobject object, jlong tag) { 728 void JvmtiTagMap::set_tag(jobject object, jlong tag) {
802 MutexLocker ml(lock()); 729 MutexLocker ml(lock());
803 730
804 // resolve the object 731 // resolve the object
805 oop o = JNIHandles::resolve_non_null(object); 732 oop o = JNIHandles::resolve_non_null(object);
806 733
807 // for Classes we tag the klassOop 734 // for Classes we tag the klassOop
808 o = klassOop_if_java_lang_Class(o); 735 o = klassOop_if_java_lang_Class(o);
809 736
810 // see if the object is already tagged 737 // see if the object is already tagged
811 JvmtiTagHashmap* hashmap = hashmap_for(o); 738 JvmtiTagHashmap* hashmap = _hashmap;
812 JvmtiTagHashmapEntry* entry = hashmap->find(o); 739 JvmtiTagHashmapEntry* entry = hashmap->find(o);
813 740
814 // if the object is not already tagged then we tag it 741 // if the object is not already tagged then we tag it
815 if (entry == NULL) { 742 if (entry == NULL) {
816 if (tag != 0) { 743 if (tag != 0) {
817 HandleMark hm; 744 entry = create_entry(o, tag);
818 Handle h(o); 745 hashmap->add(o, entry);
819 jweak ref = JNIHandles::make_weak_global(h);
820
821 // the object may have moved because make_weak_global may
822 // have blocked - thus it is necessary resolve the handle
823 // and re-hash the object.
824 o = h();
825 entry = create_entry(ref, tag);
826 hashmap_for(o)->add(o, entry);
827 } else { 746 } else {
828 // no-op 747 // no-op
829 } 748 }
830 } else { 749 } else {
831 // if the object is already tagged then we either update 750 // if the object is already tagged then we either update
832 // the tag (if a new tag value has been provided) 751 // the tag (if a new tag value has been provided)
833 // or remove the object if the new tag value is 0. 752 // or remove the object if the new tag value is 0.
834 // Removing the object requires that we also delete the JNI
835 // weak ref to the object.
836 if (tag == 0) { 753 if (tag == 0) {
837 jweak ref = entry->object();
838 hashmap->remove(o); 754 hashmap->remove(o);
839 destroy_entry(entry); 755 destroy_entry(entry);
840 JNIHandles::destroy_weak_global(ref);
841 } else { 756 } else {
842 entry->set_tag(tag); 757 entry->set_tag(tag);
843 } 758 }
844 } 759 }
845 } 760 }
1624 // and record the reference and tag value. 1539 // and record the reference and tag value.
1625 // 1540 //
1626 void do_entry(JvmtiTagHashmapEntry* entry) { 1541 void do_entry(JvmtiTagHashmapEntry* entry) {
1627 for (int i=0; i<_tag_count; i++) { 1542 for (int i=0; i<_tag_count; i++) {
1628 if (_tags[i] == entry->tag()) { 1543 if (_tags[i] == entry->tag()) {
1629 oop o = JNIHandles::resolve(entry->object()); 1544 oop o = entry->object();
1630 assert(o != NULL && o != JNIHandles::deleted_handle(), "sanity check"); 1545 assert(o != NULL, "sanity check");
1631 1546
1632 // the mirror is tagged 1547 // the mirror is tagged
1633 if (o->is_klass()) { 1548 if (o->is_klass()) {
1634 klassOop k = (klassOop)o; 1549 klassOop k = (klassOop)o;
1635 o = Klass::cast(k)->java_mirror(); 1550 o = Klass::cast(k)->java_mirror();
3372 VM_HeapWalkOperation op(this, initial_object, context, user_data); 3287 VM_HeapWalkOperation op(this, initial_object, context, user_data);
3373 VMThread::execute(&op); 3288 VMThread::execute(&op);
3374 } 3289 }
3375 3290
3376 3291
3377 // called post-GC 3292 void JvmtiTagMap::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
3378 // - for each JVMTI environment with an object tag map, call its rehash 3293 assert(SafepointSynchronize::is_at_safepoint(),
3379 // function to re-sync with the new object locations. 3294 "must be executed at a safepoint");
3380 void JvmtiTagMap::gc_epilogue(bool full) {
3381 assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint");
3382 if (JvmtiEnv::environments_might_exist()) { 3295 if (JvmtiEnv::environments_might_exist()) {
3383 // re-obtain the memory region for the young generation (might
3384 // changed due to adaptive resizing policy)
3385 get_young_generation();
3386
3387 JvmtiEnvIterator it; 3296 JvmtiEnvIterator it;
3388 for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) { 3297 for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) {
3389 JvmtiTagMap* tag_map = env->tag_map(); 3298 JvmtiTagMap* tag_map = env->tag_map();
3390 if (tag_map != NULL && !tag_map->is_empty()) { 3299 if (tag_map != NULL && !tag_map->is_empty()) {
3391 TraceTime t(full ? "JVMTI Full Rehash " : "JVMTI Rehash ", TraceJVMTIObjectTagging); 3300 tag_map->do_weak_oops(is_alive, f);
3392 if (full) {
3393 tag_map->rehash(0, n_hashmaps);
3394 } else {
3395 tag_map->rehash(0, 0); // tag map for young gen only
3396 }
3397 } 3301 }
3398 } 3302 }
3399 } 3303 }
3400 } 3304 }
3401 3305
3402 // CMS has completed referencing processing so we may have JNI weak refs 3306 void JvmtiTagMap::do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f) {
3403 // to objects in the CMS generation that have been GC'ed.
3404 void JvmtiTagMap::cms_ref_processing_epilogue() {
3405 assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint");
3406 assert(UseConcMarkSweepGC, "should only be used with CMS");
3407 if (JvmtiEnv::environments_might_exist()) {
3408 JvmtiEnvIterator it;
3409 for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) {
3410 JvmtiTagMap* tag_map = ((JvmtiEnvBase *)env)->tag_map();
3411 if (tag_map != NULL && !tag_map->is_empty()) {
3412 TraceTime t("JVMTI Rehash (CMS) ", TraceJVMTIObjectTagging);
3413 tag_map->rehash(1, n_hashmaps); // assume CMS not used in young gen
3414 }
3415 }
3416 }
3417 }
3418
3419
3420 // For each entry in the hashmaps 'start' to 'end' :
3421 //
3422 // 1. resolve the JNI weak reference
3423 //
3424 // 2. If it resolves to NULL it means the object has been freed so the entry
3425 // is removed, the weak reference destroyed, and the object free event is
3426 // posted (if enabled).
3427 //
3428 // 3. If the weak reference resolves to an object then we re-hash the object
3429 // to see if it has moved or has been promoted (from the young to the old
3430 // generation for example).
3431 //
3432 void JvmtiTagMap::rehash(int start, int end) {
3433 3307
3434 // does this environment have the OBJECT_FREE event enabled 3308 // does this environment have the OBJECT_FREE event enabled
3435 bool post_object_free = env()->is_enabled(JVMTI_EVENT_OBJECT_FREE); 3309 bool post_object_free = env()->is_enabled(JVMTI_EVENT_OBJECT_FREE);
3436 3310
3437 // counters used for trace message 3311 // counters used for trace message
3438 int freed = 0; 3312 int freed = 0;
3439 int moved = 0; 3313 int moved = 0;
3440 int promoted = 0; 3314
3441 3315 JvmtiTagHashmap* hashmap = this->hashmap();
3442 // we assume there are two hashmaps - one for the young generation
3443 // and the other for all other spaces.
3444 assert(n_hashmaps == 2, "not implemented");
3445 JvmtiTagHashmap* young_hashmap = _hashmap[0];
3446 JvmtiTagHashmap* other_hashmap = _hashmap[1];
3447 3316
3448 // reenable sizing (if disabled) 3317 // reenable sizing (if disabled)
3449 young_hashmap->set_resizing_enabled(true); 3318 hashmap->set_resizing_enabled(true);
3450 other_hashmap->set_resizing_enabled(true); 3319
3451 3320 // if the hashmap is empty then we can skip it
3452 // when re-hashing the hashmap corresponding to the young generation we 3321 if (hashmap->_entry_count == 0) {
3453 // collect the entries corresponding to objects that have been promoted. 3322 return;
3454 JvmtiTagHashmapEntry* promoted_entries = NULL; 3323 }
3455 3324
3456 if (end >= n_hashmaps) { 3325 // now iterate through each entry in the table
3457 end = n_hashmaps - 1; 3326
3458 } 3327 JvmtiTagHashmapEntry** table = hashmap->table();
3459 3328 int size = hashmap->size();
3460 for (int i=start; i <= end; i++) { 3329
3461 JvmtiTagHashmap* hashmap = _hashmap[i]; 3330 JvmtiTagHashmapEntry* delayed_add = NULL;
3462 3331
3463 // if the hashmap is empty then we can skip it 3332 for (int pos = 0; pos < size; ++pos) {
3464 if (hashmap->_entry_count == 0) { 3333 JvmtiTagHashmapEntry* entry = table[pos];
3465 continue; 3334 JvmtiTagHashmapEntry* prev = NULL;
3466 } 3335
3467 3336 while (entry != NULL) {
3468 // now iterate through each entry in the table 3337 JvmtiTagHashmapEntry* next = entry->next();
3469 3338
3470 JvmtiTagHashmapEntry** table = hashmap->table(); 3339 oop* obj = entry->object_addr();
3471 int size = hashmap->size(); 3340
3472 3341 // has object been GC'ed
3473 for (int pos=0; pos<size; pos++) { 3342 if (!is_alive->do_object_b(entry->object())) {
3474 JvmtiTagHashmapEntry* entry = table[pos]; 3343 // grab the tag
3475 JvmtiTagHashmapEntry* prev = NULL; 3344 jlong tag = entry->tag();
3476 3345 guarantee(tag != 0, "checking");
3477 while (entry != NULL) { 3346
3478 JvmtiTagHashmapEntry* next = entry->next(); 3347 // remove GC'ed entry from hashmap and return the
3479 3348 // entry to the free list
3480 jweak ref = entry->object(); 3349 hashmap->remove(prev, pos, entry);
3481 oop oop = JNIHandles::resolve(ref); 3350 destroy_entry(entry);
3482 3351
3483 // has object been GC'ed 3352 // post the event to the profiler
3484 if (oop == NULL) { 3353 if (post_object_free) {
3485 // grab the tag 3354 JvmtiExport::post_object_free(env(), tag);
3486 jlong tag = entry->tag(); 3355 }
3487 guarantee(tag != 0, "checking"); 3356
3488 3357 ++freed;
3489 // remove GC'ed entry from hashmap and return the 3358 } else {
3490 // entry to the free list 3359 f->do_oop(entry->object_addr());
3491 hashmap->remove(prev, pos, entry); 3360 oop new_oop = entry->object();
3492 destroy_entry(entry); 3361
3493 3362 // if the object has moved then re-hash it and move its
3494 // destroy the weak ref 3363 // entry to its new location.
3495 JNIHandles::destroy_weak_global(ref); 3364 unsigned int new_pos = JvmtiTagHashmap::hash(new_oop, size);
3496 3365 if (new_pos != (unsigned int)pos) {
3497 // post the event to the profiler 3366 if (prev == NULL) {
3498 if (post_object_free) { 3367 table[pos] = next;
3499 JvmtiExport::post_object_free(env(), tag); 3368 } else {
3369 prev->set_next(next);
3500 } 3370 }
3501 3371 if (new_pos < (unsigned int)pos) {
3502 freed++;
3503 entry = next;
3504 continue;
3505 }
3506
3507 // if this is the young hashmap then the object is either promoted
3508 // or moved.
3509 // if this is the other hashmap then the object is moved.
3510
3511 bool same_gen;
3512 if (i == 0) {
3513 assert(hashmap == young_hashmap, "checking");
3514 same_gen = is_in_young(oop);
3515 } else {
3516 same_gen = true;
3517 }
3518
3519
3520 if (same_gen) {
3521 // if the object has moved then re-hash it and move its
3522 // entry to its new location.
3523 unsigned int new_pos = JvmtiTagHashmap::hash(oop, size);
3524 if (new_pos != (unsigned int)pos) {
3525 if (prev == NULL) {
3526 table[pos] = next;
3527 } else {
3528 prev->set_next(next);
3529 }
3530 entry->set_next(table[new_pos]); 3372 entry->set_next(table[new_pos]);
3531 table[new_pos] = entry; 3373 table[new_pos] = entry;
3532 moved++;
3533 } else { 3374 } else {
3534 // object didn't move 3375 // Delay adding this entry to it's new position as we'd end up
3535 prev = entry; 3376 // hitting it again during this iteration.
3377 entry->set_next(delayed_add);
3378 delayed_add = entry;
3536 } 3379 }
3380 moved++;
3537 } else { 3381 } else {
3538 // object has been promoted so remove the entry from the 3382 // object didn't move
3539 // young hashmap 3383 prev = entry;
3540 assert(hashmap == young_hashmap, "checking");
3541 hashmap->remove(prev, pos, entry);
3542
3543 // move the entry to the promoted list
3544 entry->set_next(promoted_entries);
3545 promoted_entries = entry;
3546 } 3384 }
3547
3548 entry = next;
3549 } 3385 }
3550 } 3386
3551 } 3387 entry = next;
3552 3388 }
3553 3389 }
3554 // add the entries, corresponding to the promoted objects, to the 3390
3555 // other hashmap. 3391 // Re-add all the entries which were kept aside
3556 JvmtiTagHashmapEntry* entry = promoted_entries; 3392 while (delayed_add != NULL) {
3557 while (entry != NULL) { 3393 JvmtiTagHashmapEntry* next = delayed_add->next();
3558 oop o = JNIHandles::resolve(entry->object()); 3394 unsigned int pos = JvmtiTagHashmap::hash(delayed_add->object(), size);
3559 assert(hashmap_for(o) == other_hashmap, "checking"); 3395 delayed_add->set_next(table[pos]);
3560 JvmtiTagHashmapEntry* next = entry->next(); 3396 table[pos] = delayed_add;
3561 other_hashmap->add(o, entry); 3397 delayed_add = next;
3562 entry = next;
3563 promoted++;
3564 } 3398 }
3565 3399
3566 // stats 3400 // stats
3567 if (TraceJVMTIObjectTagging) { 3401 if (TraceJVMTIObjectTagging) {
3568 int total_moves = promoted + moved; 3402 int post_total = hashmap->_entry_count;
3569
3570 int post_total = 0;
3571 for (int i=0; i<n_hashmaps; i++) {
3572 post_total += _hashmap[i]->_entry_count;
3573 }
3574 int pre_total = post_total + freed; 3403 int pre_total = post_total + freed;
3575 3404
3576 tty->print("(%d->%d, %d freed, %d promoted, %d total moves)", 3405 tty->print_cr("(%d->%d, %d freed, %d total moves)",
3577 pre_total, post_total, freed, promoted, total_moves); 3406 pre_total, post_total, freed, moved);
3578 } 3407 }
3579 } 3408 }