< prev index next >

src/share/vm/prims/jvmtiTagMap.cpp

Print this page
rev 12906 : [mq]: gc_interface


  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 }
< prev index next >