@@ -2395,13 +2395,26 @@ jmethodID InstanceKlass::update_jmethod_id(jmethodID* jmeths, Method* method, in
23952395 return new_id;
23962396}
23972397
2398+ // Allocate the jmethodID cache.
2399+ static jmethodID* create_jmethod_id_cache (size_t size) {
2400+ jmethodID* jmeths = NEW_C_HEAP_ARRAY (jmethodID, size + 1 , mtClass);
2401+ memset (jmeths, 0 , (size + 1 ) * sizeof (jmethodID));
2402+ // cache size is stored in element[0], other elements offset by one
2403+ jmeths[0 ] = (jmethodID)size;
2404+ return jmeths;
2405+ }
2406+
2407+ // When reading outside a lock, use this.
2408+ jmethodID* InstanceKlass::methods_jmethod_ids_acquire () const {
2409+ return Atomic::load_acquire (&_methods_jmethod_ids);
2410+ }
2411+
2412+ void InstanceKlass::release_set_methods_jmethod_ids (jmethodID* jmeths) {
2413+ Atomic::release_store (&_methods_jmethod_ids, jmeths);
2414+ }
2415+
23982416// Lookup or create a jmethodID.
2399- // This code is called by the VMThread and JavaThreads so the
2400- // locking has to be done very carefully to avoid deadlocks
2401- // and/or other cache consistency problems.
2402- //
2403- jmethodID InstanceKlass::get_jmethod_id (const methodHandle& method_h) {
2404- Method* method = method_h ();
2417+ jmethodID InstanceKlass::get_jmethod_id (Method* method) {
24052418 int idnum = method->method_idnum ();
24062419 jmethodID* jmeths = methods_jmethod_ids_acquire ();
24072420
@@ -2422,15 +2435,12 @@ jmethodID InstanceKlass::get_jmethod_id(const methodHandle& method_h) {
24222435
24232436 if (jmeths == nullptr ) {
24242437 MutexLocker ml (JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag);
2425- jmeths = methods_jmethod_ids_acquire () ;
2438+ jmeths = _methods_jmethod_ids ;
24262439 // Still null?
24272440 if (jmeths == nullptr ) {
24282441 size_t size = idnum_allocated_count ();
24292442 assert (size > (size_t )idnum, " should already have space" );
2430- jmeths = NEW_C_HEAP_ARRAY (jmethodID, size + 1 , mtClass);
2431- memset (jmeths, 0 , (size + 1 ) * sizeof (jmethodID));
2432- // cache size is stored in element[0], other elements offset by one
2433- jmeths[0 ] = (jmethodID)size;
2443+ jmeths = create_jmethod_id_cache (size);
24342444 jmethodID new_id = update_jmethod_id (jmeths, method, idnum);
24352445
24362446 // publish jmeths
@@ -2460,10 +2470,7 @@ void InstanceKlass::update_methods_jmethod_cache() {
24602470 if (old_size < size + 1 ) {
24612471 // Allocate a larger one and copy entries to the new one.
24622472 // They've already been updated to point to new methods where applicable (i.e., not obsolete).
2463- jmethodID* new_cache = NEW_C_HEAP_ARRAY (jmethodID, size + 1 , mtClass);
2464- memset (new_cache, 0 , (size + 1 ) * sizeof (jmethodID));
2465- // The cache size is stored in element[0]; the other elements are offset by one.
2466- new_cache[0 ] = (jmethodID)size;
2473+ jmethodID* new_cache = create_jmethod_id_cache (size);
24672474
24682475 for (int i = 1 ; i <= (int )old_size; i++) {
24692476 new_cache[i] = cache[i];
@@ -2474,24 +2481,30 @@ void InstanceKlass::update_methods_jmethod_cache() {
24742481 }
24752482}
24762483
2477- // Figure out how many jmethodIDs haven't been allocated, and make
2478- // sure space for them is pre-allocated. This makes getting all
2479- // method ids much, much faster with classes with more than 8
2484+ // Make a jmethodID for all methods in this class. This makes getting all method
2485+ // ids much, much faster with classes with more than 8
24802486// methods, and has a *substantial* effect on performance with jvmti
24812487// code that loads all jmethodIDs for all classes.
2482- void InstanceKlass::ensure_space_for_methodids (int start_offset) {
2483- int new_jmeths = 0 ;
2488+ void InstanceKlass::make_methods_jmethod_ids () {
2489+ MutexLocker ml (JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag);
2490+ jmethodID* jmeths = _methods_jmethod_ids;
2491+ if (jmeths == nullptr ) {
2492+ jmeths = create_jmethod_id_cache (idnum_allocated_count ());
2493+ release_set_methods_jmethod_ids (jmeths);
2494+ }
2495+
24842496 int length = methods ()->length ();
2485- for (int index = start_offset ; index < length; index++) {
2497+ for (int index = 0 ; index < length; index++) {
24862498 Method* m = methods ()->at (index);
2487- jmethodID id = m->find_jmethod_id_or_null ();
2488- if (id == nullptr ) {
2489- new_jmeths++;
2499+ int idnum = m->method_idnum ();
2500+ assert (!m->is_old (), " should not have old methods or I'm confused" );
2501+ jmethodID id = Atomic::load_acquire (&jmeths[idnum + 1 ]);
2502+ if (!m->is_overpass () && // skip overpasses
2503+ id == nullptr ) {
2504+ id = Method::make_jmethod_id (class_loader_data (), m);
2505+ Atomic::release_store (&jmeths[idnum + 1 ], id);
24902506 }
24912507 }
2492- if (new_jmeths != 0 ) {
2493- Method::ensure_jmethod_ids (class_loader_data (), new_jmeths);
2494- }
24952508}
24962509
24972510// Lookup a jmethodID, null if not found. Do no blocking, no allocations, no handles
@@ -2923,7 +2936,7 @@ void InstanceKlass::release_C_heap_structures(bool release_sub_metadata) {
29232936 JNIid::deallocate (jni_ids ());
29242937 set_jni_ids (nullptr );
29252938
2926- jmethodID* jmeths = methods_jmethod_ids_acquire () ;
2939+ jmethodID* jmeths = _methods_jmethod_ids ;
29272940 if (jmeths != nullptr ) {
29282941 release_set_methods_jmethod_ids (nullptr );
29292942 FreeHeap (jmeths);
@@ -4275,17 +4288,14 @@ bool InstanceKlass::should_clean_previous_versions_and_reset() {
42754288 return ret;
42764289}
42774290
4278- // This nulls out jmethodIDs for all methods in 'klass'
4279- // It needs to be called explicitly for all previous versions of a class because these may not be cleaned up
4280- // during class unloading.
4281- // We can not use the jmethodID cache associated with klass directly because the 'previous' versions
4282- // do not have the jmethodID cache filled in. Instead, we need to lookup jmethodID for each method and this
4283- // is expensive - O(n) for one jmethodID lookup. For all contained methods it is O(n^2).
4284- // The reason for expensive jmethodID lookup for each method is that there is no direct link between method and jmethodID.
4285- void InstanceKlass::clear_jmethod_ids (InstanceKlass* klass) {
4291+ // This nulls out the jmethodID for all obsolete methods in the previous version of the 'klass'.
4292+ // These obsolete methods only exist in the previous version and we're about to delete the memory for them.
4293+ // The jmethodID for these are deallocated when we unload the class, so this doesn't remove them from the table.
4294+ void InstanceKlass::clear_obsolete_jmethod_ids (InstanceKlass* klass) {
42864295 Array<Method*>* method_refs = klass->methods ();
42874296 for (int k = 0 ; k < method_refs->length (); k++) {
42884297 Method* method = method_refs->at (k);
4298+ // Only need to clear obsolete methods.
42894299 if (method != nullptr && method->is_obsolete ()) {
42904300 method->clear_jmethod_id ();
42914301 }
@@ -4335,7 +4345,7 @@ void InstanceKlass::purge_previous_version_list() {
43354345 // Unlink from previous version list.
43364346 assert (pv_node->class_loader_data () == loader_data, " wrong loader_data" );
43374347 InstanceKlass* next = pv_node->previous_versions ();
4338- clear_jmethod_ids (pv_node); // jmethodID maintenance for the unloaded class
4348+ clear_obsolete_jmethod_ids (pv_node); // jmethodID maintenance for the unloaded class
43394349 pv_node->link_previous_versions (nullptr ); // point next to null
43404350 last->link_previous_versions (next);
43414351 // Delete this node directly. Nothing is referring to it and we don't
0 commit comments