< prev index next >

src/hotspot/share/code/codeHeapState.cpp

Print this page
rev 54099 : 8219586: CodeHeap State Analytics processes dead nmethods
Reviewed-by: thartmann, eosterlund

@@ -24,10 +24,11 @@
  */
 
 #include "precompiled.hpp"
 #include "code/codeHeapState.hpp"
 #include "compiler/compileBroker.hpp"
+#include "runtime/safepoint.hpp"
 #include "runtime/sweeper.hpp"
 
 // -------------------------
 // |  General Description  |
 // -------------------------

@@ -214,11 +215,11 @@
 #endif
 #define HEX32_FORMAT  "0x%x"  // just a helper format string used below multiple times
 
 const char  blobTypeChar[] = {' ', 'C', 'N', 'I', 'X', 'Z', 'U', 'R', '?', 'D', 'T', 'E', 'S', 'A', 'M', 'B', 'L' };
 const char* blobTypeName[] = {"noType"
-                             ,     "nMethod (under construction)"
+                             ,     "nMethod (under construction), cannot be observed"
                              ,          "nMethod (active)"
                              ,               "nMethod (inactive)"
                              ,                    "nMethod (deopt)"
                              ,                         "nMethod (zombie)"
                              ,                              "nMethod (unloaded)"

@@ -235,11 +236,11 @@
                              };
 const char* compTypeName[] = { "none", "c1", "c2", "jvmci" };
 
 // Be prepared for ten different CodeHeap segments. Should be enough for a few years.
 const  unsigned int        nSizeDistElements = 31;  // logarithmic range growth, max size: 2**32
-const  unsigned int        maxTopSizeBlocks  = 50;
+const  unsigned int        maxTopSizeBlocks  = 100;
 const  unsigned int        tsbStopper        = 2 * maxTopSizeBlocks;
 const  unsigned int        maxHeaps          = 10;
 static unsigned int        nHeaps            = 0;
 static struct CodeHeapStat CodeHeapStatArray[maxHeaps];
 

@@ -252,11 +253,10 @@
 static bool         segment_granules      = false;
 static unsigned int nBlocks_t1            = 0;  // counting "in_use" nmethods only.
 static unsigned int nBlocks_t2            = 0;  // counting "in_use" nmethods only.
 static unsigned int nBlocks_alive         = 0;  // counting "not_used" and "not_entrant" nmethods only.
 static unsigned int nBlocks_dead          = 0;  // counting "zombie" and "unloaded" methods only.
-static unsigned int nBlocks_inconstr      = 0;  // counting "inconstruction" nmethods only. This is a transient state.
 static unsigned int nBlocks_unloaded      = 0;  // counting "unloaded" nmethods only. This is a transient state.
 static unsigned int nBlocks_stub          = 0;
 
 static struct FreeBlk*          FreeArray = NULL;
 static unsigned int      alloc_freeBlocks = 0;

@@ -323,11 +323,10 @@
     segment_granules      = CodeHeapStatArray[ix].segment_granules;
     nBlocks_t1            = CodeHeapStatArray[ix].nBlocks_t1;
     nBlocks_t2            = CodeHeapStatArray[ix].nBlocks_t2;
     nBlocks_alive         = CodeHeapStatArray[ix].nBlocks_alive;
     nBlocks_dead          = CodeHeapStatArray[ix].nBlocks_dead;
-    nBlocks_inconstr      = CodeHeapStatArray[ix].nBlocks_inconstr;
     nBlocks_unloaded      = CodeHeapStatArray[ix].nBlocks_unloaded;
     nBlocks_stub          = CodeHeapStatArray[ix].nBlocks_stub;
     FreeArray             = CodeHeapStatArray[ix].FreeArray;
     alloc_freeBlocks      = CodeHeapStatArray[ix].alloc_freeBlocks;
     TopSizeArray          = CodeHeapStatArray[ix].TopSizeArray;

@@ -346,11 +345,10 @@
     segment_granules      = false;
     nBlocks_t1            = 0;
     nBlocks_t2            = 0;
     nBlocks_alive         = 0;
     nBlocks_dead          = 0;
-    nBlocks_inconstr      = 0;
     nBlocks_unloaded      = 0;
     nBlocks_stub          = 0;
     FreeArray             = NULL;
     alloc_freeBlocks      = 0;
     TopSizeArray          = NULL;

@@ -373,11 +371,10 @@
     CodeHeapStatArray[ix].segment_granules      = segment_granules;
     CodeHeapStatArray[ix].nBlocks_t1            = nBlocks_t1;
     CodeHeapStatArray[ix].nBlocks_t2            = nBlocks_t2;
     CodeHeapStatArray[ix].nBlocks_alive         = nBlocks_alive;
     CodeHeapStatArray[ix].nBlocks_dead          = nBlocks_dead;
-    CodeHeapStatArray[ix].nBlocks_inconstr      = nBlocks_inconstr;
     CodeHeapStatArray[ix].nBlocks_unloaded      = nBlocks_unloaded;
     CodeHeapStatArray[ix].nBlocks_stub          = nBlocks_stub;
     CodeHeapStatArray[ix].FreeArray             = FreeArray;
     CodeHeapStatArray[ix].alloc_freeBlocks      = alloc_freeBlocks;
     CodeHeapStatArray[ix].TopSizeArray          = TopSizeArray;

@@ -500,10 +497,15 @@
   }
 }
 
 void CodeHeapState::discard_TopSizeArray(outputStream* out) {
   if (TopSizeArray != NULL) {
+    for (unsigned int i = 0; i < alloc_topSizeBlocks; i++) {
+      if (TopSizeArray[i].blob_name != NULL) {
+        os::free((void*)TopSizeArray[i].blob_name);
+      }
+    }
     delete[] TopSizeArray;
     TopSizeArray        = NULL;
     alloc_topSizeBlocks = 0;
     used_topSizeBlocks  = 0;
   }

@@ -593,12 +595,12 @@
     printBox(ast, '-', "Heap not fully initialized yet, segment size is zero for segment ", heapName);
     BUFFEREDSTREAM_FLUSH("")
     return;
   }
 
-  if (!CodeCache_lock->owned_by_self()) {
-    printBox(ast, '-', "aggregate function called without holding the CodeCache_lock for ", heapName);
+  if (!holding_required_locks()) {
+    printBox(ast, '-', "Must be at safepoint or hold Compile_lock and CodeCache_lock when calling aggregate function for ", heapName);
     BUFFEREDSTREAM_FLUSH("")
     return;
   }
 
   // Calculate granularity of analysis (and output).

@@ -661,11 +663,10 @@
     //---<  reset counters with every aggregation  >---
     nBlocks_t1       = 0;
     nBlocks_t2       = 0;
     nBlocks_alive    = 0;
     nBlocks_dead     = 0;
-    nBlocks_inconstr = 0;
     nBlocks_unloaded = 0;
     nBlocks_stub     = 0;
 
     nBlocks_free     = 0;
     nBlocks_used     = 0;

@@ -695,11 +696,10 @@
     size_t       t2Space       = 0;
     size_t       aliveSpace    = 0;
     size_t       disconnSpace  = 0;
     size_t       notentrSpace  = 0;
     size_t       deadSpace     = 0;
-    size_t       inconstrSpace = 0;
     size_t       unloadedSpace = 0;
     size_t       stubSpace     = 0;
     size_t       freeSpace     = 0;
     size_t       maxFreeSize   = 0;
     HeapBlock*   maxFreeBlock  = NULL;

@@ -757,28 +757,42 @@
       } else {
         update_SizeDistArray(out, hb_len);
         nBlocks_used++;
         usedSpace    += hb_bytelen;
         CodeBlob* cb  = (CodeBlob*)heap->find_start(h);
-        if (cb != NULL) {
-          cbType = get_cbType(cb);
-          if (cb->is_nmethod()) {
-            compile_id = ((nmethod*)cb)->compile_id();
-            comp_lvl   = (CompLevel)((nmethod*)cb)->comp_level();
-            if (((nmethod*)cb)->is_compiled_by_c1()) {
+        cbType = get_cbType(cb);  // Will check for cb == NULL and other safety things.
+        if (cbType != noType) {
+          const char* blob_name  = os::strdup(cb->name());
+          unsigned int nm_size   = 0;
+          int temperature        = 0;
+          nmethod*  nm = cb->as_nmethod_or_null();
+          if (nm != NULL) { // no is_readable check required, nm = (nmethod*)cb.
+            ResourceMark rm;
+            Method* method = nm->method();
+            if (nm->is_in_use()) {
+              blob_name = os::strdup(method->name_and_sig_as_C_string());
+            }
+            if (nm->is_not_entrant()) {
+              blob_name = os::strdup(method->name_and_sig_as_C_string());
+            }
+
+            nm_size    = nm->total_size();
+            compile_id = nm->compile_id();
+            comp_lvl   = (CompLevel)(nm->comp_level());
+            if (nm->is_compiled_by_c1()) {
               cType = c1;
             }
-            if (((nmethod*)cb)->is_compiled_by_c2()) {
+            if (nm->is_compiled_by_c2()) {
               cType = c2;
             }
-            if (((nmethod*)cb)->is_compiled_by_jvmci()) {
+            if (nm->is_compiled_by_jvmci()) {
               cType = jvmci;
             }
             switch (cbType) {
               case nMethod_inuse: { // only for executable methods!!!
                 // space for these cbs is accounted for later.
-                int temperature = ((nmethod*)cb)->hotness_counter();
+                temperature = nm->hotness_counter();
                 hotnessAccumulator += temperature;
                 n_methods++;
                 maxTemp = (temperature > maxTemp) ? temperature : maxTemp;
                 minTemp = (temperature < minTemp) ? temperature : minTemp;
                 break;

@@ -801,14 +815,10 @@
                 break;
               case nMethod_dead:
                 nBlocks_dead++;
                 deadSpace      += hb_bytelen;
                 break;
-              case nMethod_inconstruction:
-                nBlocks_inconstr++;
-                inconstrSpace  += hb_bytelen;
-                break;
               default:
                 break;
             }
           }
 

@@ -816,32 +826,40 @@
           //---<  register block in TopSizeArray  >---
           //------------------------------------------
           if (alloc_topSizeBlocks > 0) {
             if (used_topSizeBlocks == 0) {
               TopSizeArray[0].start    = h;
+              TopSizeArray[0].blob_name   = blob_name;
               TopSizeArray[0].len      = hb_len;
               TopSizeArray[0].index    = tsbStopper;
+              TopSizeArray[0].nm_size     = nm_size;
+              TopSizeArray[0].temperature = temperature;
               TopSizeArray[0].compiler = cType;
               TopSizeArray[0].level    = comp_lvl;
               TopSizeArray[0].type     = cbType;
               currMax    = hb_len;
               currMin    = hb_len;
               currMin_ix = 0;
               used_topSizeBlocks++;
+              blob_name  = NULL; // indicate blob_name was consumed
             // This check roughly cuts 5000 iterations (JVM98, mixed, dbg, termination stats):
             } else if ((used_topSizeBlocks < alloc_topSizeBlocks) && (hb_len < currMin)) {
               //---<  all blocks in list are larger, but there is room left in array  >---
               TopSizeArray[currMin_ix].index = used_topSizeBlocks;
               TopSizeArray[used_topSizeBlocks].start    = h;
+              TopSizeArray[used_topSizeBlocks].blob_name   = blob_name;
               TopSizeArray[used_topSizeBlocks].len      = hb_len;
               TopSizeArray[used_topSizeBlocks].index    = tsbStopper;
+              TopSizeArray[used_topSizeBlocks].nm_size     = nm_size;
+              TopSizeArray[used_topSizeBlocks].temperature = temperature;
               TopSizeArray[used_topSizeBlocks].compiler = cType;
               TopSizeArray[used_topSizeBlocks].level    = comp_lvl;
               TopSizeArray[used_topSizeBlocks].type     = cbType;
               currMin    = hb_len;
               currMin_ix = used_topSizeBlocks;
               used_topSizeBlocks++;
+              blob_name  = NULL; // indicate blob_name was consumed
             } else {
               // This check cuts total_iterations by a factor of 6 (JVM98, mixed, dbg, termination stats):
               //   We don't need to search the list if we know beforehand that the current block size is
               //   smaller than the currently recorded minimum and there is no free entry left in the list.
               if (!((used_topSizeBlocks == alloc_topSizeBlocks) && (hb_len <= currMin))) {

@@ -869,18 +887,28 @@
                         assert(TopSizeArray[i].len == currMin, "sort error");
                         currMin_ix = used_topSizeBlocks;
                       }
                       memcpy((void*)&TopSizeArray[used_topSizeBlocks], (void*)&TopSizeArray[i], sizeof(TopSizeBlk));
                       TopSizeArray[i].start    = h;
+                      TopSizeArray[i].blob_name   = blob_name;
                       TopSizeArray[i].len      = hb_len;
                       TopSizeArray[i].index    = used_topSizeBlocks;
+                      TopSizeArray[i].nm_size     = nm_size;
+                      TopSizeArray[i].temperature = temperature;
                       TopSizeArray[i].compiler = cType;
                       TopSizeArray[i].level    = comp_lvl;
                       TopSizeArray[i].type     = cbType;
                       used_topSizeBlocks++;
+                      blob_name  = NULL; // indicate blob_name was consumed
                     } else { // no room for new entries, current block replaces entry for smallest block
                       //---<  Find last entry (entry for smallest remembered block)  >---
+                      // We either want to insert right before the smallest entry, which is when <i>
+                      // indexes the smallest entry. We then just overwrite the smallest entry.
+                      // What's more likely:
+                      // We want to insert somewhere in the list. The smallest entry (@<j>) then falls off the cliff.
+                      // The element at the insert point <i> takes it's slot. The second-smallest entry now becomes smallest.
+                      // Data of the current block is filled in at index <i>.
                       unsigned int      j  = i;
                       unsigned int prev_j  = tsbStopper;
                       unsigned int limit_j = 0;
                       while (TopSizeArray[j].index != tsbStopper) {
                         if (limit_j++ >= alloc_topSizeBlocks) {

@@ -892,35 +920,45 @@
                         total_iterations++;
                         prev_j = j;
                         j      = TopSizeArray[j].index;
                       }
                       if (!insane) {
+                        if (TopSizeArray[j].blob_name != NULL) {
+                          os::free((void*)TopSizeArray[j].blob_name);
+                        }
                         if (prev_j == tsbStopper) {
                           //---<  Above while loop did not iterate, we already are the min entry  >---
                           //---<  We have to just replace the smallest entry                      >---
                           currMin    = hb_len;
                           currMin_ix = j;
                           TopSizeArray[j].start    = h;
+                          TopSizeArray[j].blob_name   = blob_name;
                           TopSizeArray[j].len      = hb_len;
                           TopSizeArray[j].index    = tsbStopper; // already set!!
+                          TopSizeArray[i].nm_size     = nm_size;
+                          TopSizeArray[i].temperature = temperature;
                           TopSizeArray[j].compiler = cType;
                           TopSizeArray[j].level    = comp_lvl;
                           TopSizeArray[j].type     = cbType;
                         } else {
                           //---<  second-smallest entry is now smallest  >---
                           TopSizeArray[prev_j].index = tsbStopper;
                           currMin    = TopSizeArray[prev_j].len;
                           currMin_ix = prev_j;
-                          //---<  smallest entry gets overwritten  >---
+                          //---<  previously smallest entry gets overwritten  >---
                           memcpy((void*)&TopSizeArray[j], (void*)&TopSizeArray[i], sizeof(TopSizeBlk));
                           TopSizeArray[i].start    = h;
+                          TopSizeArray[i].blob_name   = blob_name;
                           TopSizeArray[i].len      = hb_len;
                           TopSizeArray[i].index    = j;
+                          TopSizeArray[i].nm_size     = nm_size;
+                          TopSizeArray[i].temperature = temperature;
                           TopSizeArray[i].compiler = cType;
                           TopSizeArray[i].level    = comp_lvl;
                           TopSizeArray[i].type     = cbType;
                         }
+                        blob_name  = NULL; // indicate blob_name was consumed
                       } // insane
                     }
                     break;
                   }
                   prev_i = i;

@@ -931,10 +969,14 @@
                   discard_TopSizeArray(out);
                 }
               }
             }
           }
+          if (blob_name != NULL) {
+            os::free((void*)blob_name);
+            blob_name = NULL;
+          }
           //----------------------------------------------
           //---<  END register block in TopSizeArray  >---
           //----------------------------------------------
         } else {
           nBlocks_zomb++;

@@ -959,11 +1001,10 @@
                 StatArray[ix_beg].t2_age    = StatArray[ix_beg].t2_age < compile_id ? compile_id : StatArray[ix_beg].t2_age;
               }
               StatArray[ix_beg].level     = comp_lvl;
               StatArray[ix_beg].compiler  = cType;
               break;
-            case nMethod_inconstruction: // let's count "in construction" nmethods here.
             case nMethod_alive:
               StatArray[ix_beg].tx_count++;
               StatArray[ix_beg].tx_space += (unsigned short)hb_len;
               StatArray[ix_beg].tx_age    = StatArray[ix_beg].tx_age < compile_id ? compile_id : StatArray[ix_beg].tx_age;
               StatArray[ix_beg].level     = comp_lvl;

@@ -1016,11 +1057,10 @@
               StatArray[ix_beg].level     = comp_lvl;
               StatArray[ix_beg].compiler  = cType;
               StatArray[ix_end].level     = comp_lvl;
               StatArray[ix_end].compiler  = cType;
               break;
-            case nMethod_inconstruction: // let's count "in construction" nmethods here.
             case nMethod_alive:
               StatArray[ix_beg].tx_count++;
               StatArray[ix_beg].tx_space += (unsigned short)beg_space;
               StatArray[ix_beg].tx_age    = StatArray[ix_beg].tx_age < compile_id ? compile_id : StatArray[ix_beg].tx_age;
 

@@ -1064,11 +1104,10 @@
                   StatArray[ix].t2_age    = StatArray[ix].t2_age < compile_id ? compile_id : StatArray[ix].t2_age;
                 }
                 StatArray[ix].level     = comp_lvl;
                 StatArray[ix].compiler  = cType;
                 break;
-              case nMethod_inconstruction: // let's count "in construction" nmethods here.
               case nMethod_alive:
                 StatArray[ix].tx_count++;
                 StatArray[ix].tx_space += (unsigned short)(granule_size>>log2_seg_size);
                 StatArray[ix].tx_age    = StatArray[ix].tx_age < compile_id ? compile_id : StatArray[ix].tx_age;
                 StatArray[ix].level     = comp_lvl;

@@ -1101,11 +1140,10 @@
       ast->print_cr("  Tier1 Space    = " SIZE_FORMAT_W(8) "k, nBlocks_t1       = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", t1Space/(size_t)K,       nBlocks_t1,       (100.0*t1Space)/size,       (100.0*t1Space)/res_size);
       ast->print_cr("  Tier2 Space    = " SIZE_FORMAT_W(8) "k, nBlocks_t2       = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", t2Space/(size_t)K,       nBlocks_t2,       (100.0*t2Space)/size,       (100.0*t2Space)/res_size);
       ast->print_cr("  Alive Space    = " SIZE_FORMAT_W(8) "k, nBlocks_alive    = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", aliveSpace/(size_t)K,    nBlocks_alive,    (100.0*aliveSpace)/size,    (100.0*aliveSpace)/res_size);
       ast->print_cr("    disconnected = " SIZE_FORMAT_W(8) "k, nBlocks_disconn  = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", disconnSpace/(size_t)K,  nBlocks_disconn,  (100.0*disconnSpace)/size,  (100.0*disconnSpace)/res_size);
       ast->print_cr("    not entrant  = " SIZE_FORMAT_W(8) "k, nBlocks_notentr  = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", notentrSpace/(size_t)K,  nBlocks_notentr,  (100.0*notentrSpace)/size,  (100.0*notentrSpace)/res_size);
-      ast->print_cr("  inconstrSpace  = " SIZE_FORMAT_W(8) "k, nBlocks_inconstr = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", inconstrSpace/(size_t)K, nBlocks_inconstr, (100.0*inconstrSpace)/size, (100.0*inconstrSpace)/res_size);
       ast->print_cr("  unloadedSpace  = " SIZE_FORMAT_W(8) "k, nBlocks_unloaded = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", unloadedSpace/(size_t)K, nBlocks_unloaded, (100.0*unloadedSpace)/size, (100.0*unloadedSpace)/res_size);
       ast->print_cr("  deadSpace      = " SIZE_FORMAT_W(8) "k, nBlocks_dead     = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", deadSpace/(size_t)K,     nBlocks_dead,     (100.0*deadSpace)/size,     (100.0*deadSpace)/res_size);
       ast->print_cr("  stubSpace      = " SIZE_FORMAT_W(8) "k, nBlocks_stub     = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", stubSpace/(size_t)K,     nBlocks_stub,     (100.0*stubSpace)/size,     (100.0*stubSpace)/res_size);
       ast->print_cr("ZombieBlocks     = %8d. These are HeapBlocks which could not be identified as CodeBlobs.", nBlocks_zomb);
       ast->cr();

@@ -1279,11 +1317,11 @@
     for (unsigned int ix = 0; ix < alloc_freeBlocks-1; ix++) {
       size_t lenSum = 0;
       FreeArray[ix].gap = (unsigned int)((address)FreeArray[ix+1].start - ((address)FreeArray[ix].start + FreeArray[ix].len));
       for (HeapBlock *h = heap->next_block(FreeArray[ix].start); (h != NULL) && (h != FreeArray[ix+1].start); h = heap->next_block(h)) {
         CodeBlob *cb  = (CodeBlob*)(heap->find_start(h));
-        if ((cb != NULL) && !cb->is_nmethod()) {
+        if ((cb != NULL) && !cb->is_nmethod()) { // checks equivalent to those in get_cbType()
           FreeArray[ix].stubs_in_gap = true;
         }
         FreeArray[ix].n_gapBlocks++;
         lenSum += h->length()<<log2_seg_size;
         if (((address)h < ((address)FreeArray[ix].start+FreeArray[ix].len)) || (h >= FreeArray[ix+1].start)) {

@@ -1331,11 +1369,10 @@
   //----------------------------
   //--  Print Top Used Blocks --
   //----------------------------
   {
     char*     low_bound = heap->low_boundary();
-    bool      have_CodeCache_lock = CodeCache_lock->owned_by_self();
 
     printBox(ast, '-', "Largest Used Blocks in ", heapName);
     print_blobType_legend(ast);
 
     ast->fill_to(51);

@@ -1350,23 +1387,19 @@
     //---<  print Top Ten Used Blocks  >---
     if (used_topSizeBlocks > 0) {
       unsigned int printed_topSizeBlocks = 0;
       for (unsigned int i = 0; i != tsbStopper; i = TopSizeArray[i].index) {
         printed_topSizeBlocks++;
-        nmethod*           nm = NULL;
-        const char* blob_name = "unnamed blob or blob name unavailable";
+        if (TopSizeArray[i].blob_name == NULL) {
+          TopSizeArray[i].blob_name = os::strdup("unnamed blob or blob name unavailable");
+        }
         // heap->find_start() is safe. Only works on _segmap.
         // Returns NULL or void*. Returned CodeBlob may be uninitialized.
         HeapBlock* heapBlock = TopSizeArray[i].start;
         CodeBlob*  this_blob = (CodeBlob*)(heap->find_start(heapBlock));
-        bool    blob_is_safe = blob_access_is_safe(this_blob, NULL);
-        if (blob_is_safe) {
+        if (this_blob != NULL) {
           //---<  access these fields only if we own the CodeCache_lock  >---
-          if (have_CodeCache_lock) {
-            blob_name = this_blob->name();
-            nm        = this_blob->as_nmethod_or_null();
-          }
           //---<  blob address  >---
           ast->print(INTPTR_FORMAT, p2i(this_blob));
           ast->fill_to(19);
           //---<  blob offset from CodeHeap begin  >---
           ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound));

@@ -1379,51 +1412,38 @@
           ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)TopSizeArray[i].start-low_bound));
           ast->fill_to(33);
         }
 
         //---<  print size, name, and signature (for nMethods)  >---
-        // access nmethod and Method fields only if we own the CodeCache_lock.
-        // This fact is implicitly transported via nm != NULL.
-        if (CompiledMethod::nmethod_access_is_safe(nm)) {
-          ResourceMark rm;
-          Method* method = nm->method();
-          if (nm->is_in_use()) {
-            blob_name = method->name_and_sig_as_C_string();
-          }
-          if (nm->is_not_entrant()) {
-            blob_name = method->name_and_sig_as_C_string();
-          }
+        bool is_nmethod = TopSizeArray[i].nm_size > 0;
+        if (is_nmethod) {
           //---<  nMethod size in hex  >---
-          unsigned int total_size = nm->total_size();
-          ast->print(PTR32_FORMAT, total_size);
-          ast->print("(" SIZE_FORMAT_W(4) "K)", total_size/K);
+          ast->print(PTR32_FORMAT, TopSizeArray[i].nm_size);
+          ast->print("(" SIZE_FORMAT_W(4) "K)", TopSizeArray[i].nm_size/K);
           ast->fill_to(51);
           ast->print("  %c", blobTypeChar[TopSizeArray[i].type]);
           //---<  compiler information  >---
           ast->fill_to(56);
           ast->print("%5s %3d", compTypeName[TopSizeArray[i].compiler], TopSizeArray[i].level);
           //---<  method temperature  >---
           ast->fill_to(67);
-          ast->print("%5d", nm->hotness_counter());
+          ast->print("%5d", TopSizeArray[i].temperature);
           //---<  name and signature  >---
           ast->fill_to(67+6);
-          if (nm->is_not_installed()) {
-            ast->print(" not (yet) installed method ");
-          }
-          if (nm->is_zombie()) {
+          if (TopSizeArray[i].type == nMethod_dead) {
             ast->print(" zombie method ");
           }
-          ast->print("%s", blob_name);
+          ast->print("%s", TopSizeArray[i].blob_name);
         } else {
           //---<  block size in hex  >---
           ast->print(PTR32_FORMAT, (unsigned int)(TopSizeArray[i].len<<log2_seg_size));
           ast->print("(" SIZE_FORMAT_W(4) "K)", (TopSizeArray[i].len<<log2_seg_size)/K);
           //---<  no compiler information  >---
           ast->fill_to(56);
           //---<  name and signature  >---
           ast->fill_to(67+6);
-          ast->print("%s", blob_name);
+          ast->print("%s", TopSizeArray[i].blob_name);
         }
         ast->cr();
         BUFFEREDSTREAM_FLUSH_AUTO("")
       }
       if (used_topSizeBlocks != printed_topSizeBlocks) {

@@ -2200,11 +2220,11 @@
 
   unsigned int granules_per_line   = 128;
   char*        low_bound           = heap->low_boundary();
   CodeBlob*    last_blob           = NULL;
   bool         name_in_addr_range  = true;
-  bool         have_CodeCache_lock = CodeCache_lock->owned_by_self();
+  bool         have_locks          = holding_required_locks();
 
   //---<  print at least 128K per block (i.e. between headers)  >---
   if (granules_per_line*granule_size < 128*K) {
     granules_per_line = (unsigned int)((128*K)/granule_size);
   }

@@ -2212,11 +2232,11 @@
   printBox(ast, '=', "M E T H O D   N A M E S   for ", heapName);
   ast->print_cr("  Method names are dynamically retrieved from the code cache at print time.\n"
                 "  Due to the living nature of the code heap and because the CodeCache_lock\n"
                 "  is not continuously held, the displayed name might be wrong or no name\n"
                 "  might be found at all. The likelihood for that to happen increases\n"
-                "  over time passed between aggregtion and print steps.\n");
+                "  over time passed between aggregation and print steps.\n");
   BUFFEREDSTREAM_FLUSH_LOCKED("")
 
   for (unsigned int ix = 0; ix < alloc_granules; ix++) {
     //---<  print a new blob on a new line  >---
     if (ix%granules_per_line == 0) {

@@ -2239,11 +2259,11 @@
     for (unsigned int is = 0; is < granule_size; is+=(unsigned int)seg_size) {
       // heap->find_start() is safe. Only works on _segmap.
       // Returns NULL or void*. Returned CodeBlob may be uninitialized.
       char*     this_seg  = low_bound + ix*granule_size + is;
       CodeBlob* this_blob = (CodeBlob*)(heap->find_start(this_seg));
-      bool   blob_is_safe = blob_access_is_safe(this_blob, NULL);
+      bool   blob_is_safe = blob_access_is_safe(this_blob);
       // blob could have been flushed, freed, and merged.
       // this_blob < last_blob is an indicator for that.
       if (blob_is_safe && (this_blob > last_blob)) {
         last_blob          = this_blob;
 

@@ -2251,23 +2271,23 @@
         blobType       cbType = noType;
         if (segment_granules) {
           cbType = (blobType)StatArray[ix].type;
         } else {
           //---<  access these fields only if we own the CodeCache_lock  >---
-          if (have_CodeCache_lock) {
+          if (have_locks) {
             cbType = get_cbType(this_blob);
           }
         }
 
         //---<  access these fields only if we own the CodeCache_lock  >---
         const char* blob_name = "<unavailable>";
         nmethod*           nm = NULL;
-        if (have_CodeCache_lock) {
+        if (have_locks) {
           blob_name = this_blob->name();
           nm        = this_blob->as_nmethod_or_null();
           // this_blob->name() could return NULL if no name was given to CTOR. Inlined, maybe invisible on stack
-          if ((blob_name == NULL) || !os::is_readable_pointer(blob_name)) {
+          if (blob_name == NULL) {
             blob_name = "<unavailable>";
           }
         }
 
         //---<  print table header for new print range  >---

@@ -2287,11 +2307,11 @@
         ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound));
         ast->fill_to(33);
 
         // access nmethod and Method fields only if we own the CodeCache_lock.
         // This fact is implicitly transported via nm != NULL.
-        if (CompiledMethod::nmethod_access_is_safe(nm)) {
+        if (nmethod_access_is_safe(nm)) {
           Method* method = nm->method();
           ResourceMark rm;
           //---<  collect all data to locals as quickly as possible  >---
           unsigned int total_size = nm->total_size();
           int          hotness    = nm->hotness_counter();

@@ -2493,27 +2513,28 @@
     ast->fill_to(19);
     ast->print("(+" PTR32_FORMAT "): |", (unsigned int)(ix*granule_size));
   }
 }
 
+// Find out which blob type we have at hand.
+// Return "noType" if anything abnormal is detected.
 CodeHeapState::blobType CodeHeapState::get_cbType(CodeBlob* cb) {
-  if ((cb != NULL) && os::is_readable_pointer(cb)) {
+  if (cb != NULL) {
     if (cb->is_runtime_stub())                return runtimeStub;
     if (cb->is_deoptimization_stub())         return deoptimizationStub;
     if (cb->is_uncommon_trap_stub())          return uncommonTrapStub;
     if (cb->is_exception_stub())              return exceptionStub;
     if (cb->is_safepoint_stub())              return safepointStub;
     if (cb->is_adapter_blob())                return adapterBlob;
     if (cb->is_method_handles_adapter_blob()) return mh_adapterBlob;
     if (cb->is_buffer_blob())                 return bufferBlob;
 
-    //---<  access these fields only if we own the CodeCache_lock  >---
-    // Should be ensured by caller. aggregate() amd print_names() do that.
-    if (CodeCache_lock->owned_by_self()) {
+    //---<  access these fields only if we own CodeCache_lock and Compile_lock  >---
+    // Should be ensured by caller. aggregate() and print_names() do that.
+    if (holding_required_locks()) {
       nmethod*  nm = cb->as_nmethod_or_null();
       if (nm != NULL) { // no is_readable check required, nm = (nmethod*)cb.
-        if (nm->is_not_installed()) return nMethod_inconstruction;
         if (nm->is_zombie())        return nMethod_dead;
         if (nm->is_unloaded())      return nMethod_unloaded;
         if (nm->is_in_use())        return nMethod_inuse;
         if (nm->is_alive() && !(nm->is_not_entrant()))   return nMethod_notused;
         if (nm->is_alive())         return nMethod_alive;

@@ -2522,15 +2543,24 @@
     }
   }
   return noType;
 }
 
-bool CodeHeapState::blob_access_is_safe(CodeBlob* this_blob, CodeBlob* prev_blob) {
+// make sure the blob at hand is not garbage.
+bool CodeHeapState::blob_access_is_safe(CodeBlob* this_blob) {
   return (this_blob != NULL) && // a blob must have been found, obviously
-         ((this_blob == prev_blob) || (prev_blob == NULL)) &&  // when re-checking, the same blob must have been found
          (this_blob->header_size() >= 0) &&
          (this_blob->relocation_size() >= 0) &&
          ((address)this_blob + this_blob->header_size() == (address)(this_blob->relocation_begin())) &&
-         ((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin())) &&
-         os::is_readable_pointer((address)(this_blob->relocation_begin())) &&
-         os::is_readable_pointer(this_blob->content_begin());
+         ((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin()));
+}
+
+// make sure the nmethod at hand (and the linked method) is not garbage.
+bool CodeHeapState::nmethod_access_is_safe(nmethod* nm) {
+  Method* method = (nm == NULL) ? NULL : nm->method(); // nm->method() was found to be uninitialized, i.e. != NULL, but invalid.
+  return (nm != NULL) && (method != NULL) && nm->is_alive() && (method->signature() != NULL);
+}
+
+bool CodeHeapState::holding_required_locks() {
+  return SafepointSynchronize::is_at_safepoint() ||
+        (CodeCache_lock->owned_by_self() && Compile_lock->owned_by_self());
 }
< prev index next >