Mercurial > hg > truffle
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 } |