1 /* |
1 /* |
2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. |
3 * Copyright (c) 2018 SAP SE. All rights reserved. |
3 * Copyright (c) 2018, 2019 SAP SE. All rights reserved. |
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
5 * |
5 * |
6 * This code is free software; you can redistribute it and/or modify it |
6 * This code is free software; you can redistribute it and/or modify it |
7 * under the terms of the GNU General Public License version 2 only, as |
7 * under the terms of the GNU General Public License version 2 only, as |
8 * published by the Free Software Foundation. |
8 * published by the Free Software Foundation. |
38 // Aggregation condenses the information of a piece of the CodeHeap |
38 // Aggregation condenses the information of a piece of the CodeHeap |
39 // (4096 bytes by default) into an analysis granule. These granules |
39 // (4096 bytes by default) into an analysis granule. These granules |
40 // contain enough detail to gain initial insight while keeping the |
40 // contain enough detail to gain initial insight while keeping the |
41 // internal structure sizes in check. |
41 // internal structure sizes in check. |
42 // |
42 // |
43 // The CodeHeap is a living thing. Therefore, the aggregate is collected |
|
44 // under the CodeCache_lock. The subsequent print steps are only locked |
|
45 // against concurrent aggregations. That keeps the impact on |
|
46 // "normal operation" (JIT compiler and sweeper activity) to a minimum. |
|
47 // |
|
48 // The second part, which consists of several, independent steps, |
43 // The second part, which consists of several, independent steps, |
49 // prints the previously collected information with emphasis on |
44 // prints the previously collected information with emphasis on |
50 // various aspects. |
45 // various aspects. |
|
46 // |
|
47 // The CodeHeap is a living thing. Therefore, protection against concurrent |
|
48 // modification (by acquiring the CodeCache_lock) is necessary. It has |
|
49 // to be provided by the caller of the analysis functions. |
|
50 // If the CodeCache_lock is not held, the analysis functions may print |
|
51 // less detailed information or may just do nothing. It is by intention |
|
52 // that an unprotected invocation is not abnormally terminated. |
51 // |
53 // |
52 // Data collection and printing is done on an "on request" basis. |
54 // Data collection and printing is done on an "on request" basis. |
53 // While no request is being processed, there is no impact on performance. |
55 // While no request is being processed, there is no impact on performance. |
54 // The CodeHeap state analytics do have some memory footprint. |
56 // The CodeHeap state analytics do have some memory footprint. |
55 // The "aggregate" step allocates some data structures to hold the aggregated |
57 // The "aggregate" step allocates some data structures to hold the aggregated |
454 unsigned long total_iterations = 0; |
456 unsigned long total_iterations = 0; |
455 |
457 |
456 bool done = false; |
458 bool done = false; |
457 const int min_granules = 256; |
459 const int min_granules = 256; |
458 const int max_granules = 512*K; // limits analyzable CodeHeap (with segment_granules) to 32M..128M |
460 const int max_granules = 512*K; // limits analyzable CodeHeap (with segment_granules) to 32M..128M |
459 // results in StatArray size of 20M (= max_granules * 40 Bytes per element) |
461 // results in StatArray size of 24M (= max_granules * 48 Bytes per element) |
460 // For a 1GB CodeHeap, the granule size must be at least 2kB to not violate the max_granles limit. |
462 // For a 1GB CodeHeap, the granule size must be at least 2kB to not violate the max_granles limit. |
461 const char* heapName = get_heapName(heap); |
463 const char* heapName = get_heapName(heap); |
462 STRINGSTREAM_DECL(ast, out) |
464 STRINGSTREAM_DECL(ast, out) |
463 |
465 |
464 if (!initialization_complete) { |
466 if (!initialization_complete) { |
489 seg_size = heap->segment_size(); |
491 seg_size = heap->segment_size(); |
490 log2_seg_size = seg_size == 0 ? 0 : exact_log2(seg_size); // This is a global static value. |
492 log2_seg_size = seg_size == 0 ? 0 : exact_log2(seg_size); // This is a global static value. |
491 |
493 |
492 if (seg_size == 0) { |
494 if (seg_size == 0) { |
493 printBox(ast, '-', "Heap not fully initialized yet, segment size is zero for segment ", heapName); |
495 printBox(ast, '-', "Heap not fully initialized yet, segment size is zero for segment ", heapName); |
|
496 STRINGSTREAM_FLUSH("") |
|
497 return; |
|
498 } |
|
499 |
|
500 if (!CodeCache_lock->owned_by_self()) { |
|
501 printBox(ast, '-', "aggregate function called without holding the CodeCache_lock for ", heapName); |
494 STRINGSTREAM_FLUSH("") |
502 STRINGSTREAM_FLUSH("") |
495 return; |
503 return; |
496 } |
504 } |
497 |
505 |
498 // Calculate granularity of analysis (and output). |
506 // Calculate granularity of analysis (and output). |
1026 ast->print_cr("No hotness data available"); |
1034 ast->print_cr("No hotness data available"); |
1027 } |
1035 } |
1028 STRINGSTREAM_FLUSH("\n") |
1036 STRINGSTREAM_FLUSH("\n") |
1029 |
1037 |
1030 // This loop is intentionally printing directly to "out". |
1038 // This loop is intentionally printing directly to "out". |
|
1039 // It should not print anything, anyway. |
1031 out->print("Verifying collected data..."); |
1040 out->print("Verifying collected data..."); |
1032 size_t granule_segs = granule_size>>log2_seg_size; |
1041 size_t granule_segs = granule_size>>log2_seg_size; |
1033 for (unsigned int ix = 0; ix < granules; ix++) { |
1042 for (unsigned int ix = 0; ix < granules; ix++) { |
1034 if (StatArray[ix].t1_count > granule_segs) { |
1043 if (StatArray[ix].t1_count > granule_segs) { |
1035 out->print_cr("t1_count[%d] = %d", ix, StatArray[ix].t1_count); |
1044 out->print_cr("t1_count[%d] = %d", ix, StatArray[ix].t1_count); |
1069 out->print_cr("t1_space[%d] = %d, t2_space[%d] = %d, tx_space[%d] = %d, stub_space[%d] = %d", ix, StatArray[ix].t1_space, ix, StatArray[ix].t2_space, ix, StatArray[ix].tx_space, ix, StatArray[ix].stub_space); |
1078 out->print_cr("t1_space[%d] = %d, t2_space[%d] = %d, tx_space[%d] = %d, stub_space[%d] = %d", ix, StatArray[ix].t1_space, ix, StatArray[ix].t2_space, ix, StatArray[ix].tx_space, ix, StatArray[ix].stub_space); |
1070 } |
1079 } |
1071 } |
1080 } |
1072 |
1081 |
1073 // This loop is intentionally printing directly to "out". |
1082 // This loop is intentionally printing directly to "out". |
|
1083 // It should not print anything, anyway. |
1074 if (used_topSizeBlocks > 0) { |
1084 if (used_topSizeBlocks > 0) { |
1075 unsigned int j = 0; |
1085 unsigned int j = 0; |
1076 if (TopSizeArray[0].len != currMax) { |
1086 if (TopSizeArray[0].len != currMax) { |
1077 out->print_cr("currMax(%d) differs from TopSizeArray[0].len(%d)", currMax, TopSizeArray[0].len); |
1087 out->print_cr("currMax(%d) differs from TopSizeArray[0].len(%d)", currMax, TopSizeArray[0].len); |
1078 } |
1088 } |
1164 } |
1174 } |
1165 |
1175 |
1166 //---< calculate and fill remaining fields >--- |
1176 //---< calculate and fill remaining fields >--- |
1167 if (FreeArray != NULL) { |
1177 if (FreeArray != NULL) { |
1168 // This loop is intentionally printing directly to "out". |
1178 // This loop is intentionally printing directly to "out". |
|
1179 // It should not print anything, anyway. |
1169 for (unsigned int ix = 0; ix < alloc_freeBlocks-1; ix++) { |
1180 for (unsigned int ix = 0; ix < alloc_freeBlocks-1; ix++) { |
1170 size_t lenSum = 0; |
1181 size_t lenSum = 0; |
1171 FreeArray[ix].gap = (unsigned int)((address)FreeArray[ix+1].start - ((address)FreeArray[ix].start + FreeArray[ix].len)); |
1182 FreeArray[ix].gap = (unsigned int)((address)FreeArray[ix+1].start - ((address)FreeArray[ix].start + FreeArray[ix].len)); |
1172 for (HeapBlock *h = heap->next_block(FreeArray[ix].start); (h != NULL) && (h != FreeArray[ix+1].start); h = heap->next_block(h)) { |
1183 for (HeapBlock *h = heap->next_block(FreeArray[ix].start); (h != NULL) && (h != FreeArray[ix+1].start); h = heap->next_block(h)) { |
1173 CodeBlob *cb = (CodeBlob*)(heap->find_start(h)); |
1184 CodeBlob *cb = (CodeBlob*)(heap->find_start(h)); |
1221 //---------------------------- |
1232 //---------------------------- |
1222 //-- Print Top Used Blocks -- |
1233 //-- Print Top Used Blocks -- |
1223 //---------------------------- |
1234 //---------------------------- |
1224 { |
1235 { |
1225 char* low_bound = heap->low_boundary(); |
1236 char* low_bound = heap->low_boundary(); |
|
1237 bool have_CodeCache_lock = CodeCache_lock->owned_by_self(); |
1226 |
1238 |
1227 printBox(ast, '-', "Largest Used Blocks in ", heapName); |
1239 printBox(ast, '-', "Largest Used Blocks in ", heapName); |
1228 print_blobType_legend(ast); |
1240 print_blobType_legend(ast); |
1229 |
1241 |
1230 ast->fill_to(51); |
1242 ast->fill_to(51); |
1239 //---< print Top Ten Used Blocks >--- |
1251 //---< print Top Ten Used Blocks >--- |
1240 if (used_topSizeBlocks > 0) { |
1252 if (used_topSizeBlocks > 0) { |
1241 unsigned int printed_topSizeBlocks = 0; |
1253 unsigned int printed_topSizeBlocks = 0; |
1242 for (unsigned int i = 0; i != tsbStopper; i = TopSizeArray[i].index) { |
1254 for (unsigned int i = 0; i != tsbStopper; i = TopSizeArray[i].index) { |
1243 printed_topSizeBlocks++; |
1255 printed_topSizeBlocks++; |
1244 CodeBlob* this_blob = (CodeBlob*)(heap->find_start(TopSizeArray[i].start)); |
|
1245 nmethod* nm = NULL; |
1256 nmethod* nm = NULL; |
1246 const char* blob_name = "unnamed blob"; |
1257 const char* blob_name = "unnamed blob or blob name unavailable"; |
1247 if (this_blob != NULL) { |
1258 // heap->find_start() is safe. Only works on _segmap. |
1248 blob_name = this_blob->name(); |
1259 // Returns NULL or void*. Returned CodeBlob may be uninitialized. |
1249 nm = this_blob->as_nmethod_or_null(); |
1260 HeapBlock* heapBlock = TopSizeArray[i].start; |
|
1261 CodeBlob* this_blob = (CodeBlob*)(heap->find_start(heapBlock)); |
|
1262 bool blob_is_safe = blob_access_is_safe(this_blob, NULL); |
|
1263 if (blob_is_safe) { |
|
1264 //---< access these fields only if we own the CodeCache_lock >--- |
|
1265 if (have_CodeCache_lock) { |
|
1266 blob_name = this_blob->name(); |
|
1267 nm = this_blob->as_nmethod_or_null(); |
|
1268 } |
1250 //---< blob address >--- |
1269 //---< blob address >--- |
1251 ast->print(INTPTR_FORMAT, p2i(this_blob)); |
1270 ast->print(INTPTR_FORMAT, p2i(this_blob)); |
1252 ast->fill_to(19); |
1271 ast->fill_to(19); |
1253 //---< blob offset from CodeHeap begin >--- |
1272 //---< blob offset from CodeHeap begin >--- |
1254 ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound)); |
1273 ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound)); |
1260 //---< block offset from CodeHeap begin >--- |
1279 //---< block offset from CodeHeap begin >--- |
1261 ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)TopSizeArray[i].start-low_bound)); |
1280 ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)TopSizeArray[i].start-low_bound)); |
1262 ast->fill_to(33); |
1281 ast->fill_to(33); |
1263 } |
1282 } |
1264 |
1283 |
1265 |
|
1266 //---< print size, name, and signature (for nMethods) >--- |
1284 //---< print size, name, and signature (for nMethods) >--- |
1267 if ((nm != NULL) && (nm->method() != NULL)) { |
1285 // access nmethod and Method fields only if we own the CodeCache_lock. |
|
1286 // This fact is implicitly transported via nm != NULL. |
|
1287 if (CompiledMethod::nmethod_access_is_safe(nm)) { |
1268 ResourceMark rm; |
1288 ResourceMark rm; |
|
1289 Method* method = nm->method(); |
|
1290 if (nm->is_in_use()) { |
|
1291 blob_name = method->name_and_sig_as_C_string(); |
|
1292 } |
|
1293 if (nm->is_not_entrant()) { |
|
1294 blob_name = method->name_and_sig_as_C_string(); |
|
1295 } |
1269 //---< nMethod size in hex >--- |
1296 //---< nMethod size in hex >--- |
1270 unsigned int total_size = nm->total_size(); |
1297 unsigned int total_size = nm->total_size(); |
1271 ast->print(PTR32_FORMAT, total_size); |
1298 ast->print(PTR32_FORMAT, total_size); |
1272 ast->print("(" SIZE_FORMAT_W(4) "K)", total_size/K); |
1299 ast->print("(" SIZE_FORMAT_W(4) "K)", total_size/K); |
1273 ast->fill_to(51); |
1300 ast->fill_to(51); |
1278 //---< method temperature >--- |
1305 //---< method temperature >--- |
1279 ast->fill_to(67); |
1306 ast->fill_to(67); |
1280 ast->print("%5d", nm->hotness_counter()); |
1307 ast->print("%5d", nm->hotness_counter()); |
1281 //---< name and signature >--- |
1308 //---< name and signature >--- |
1282 ast->fill_to(67+6); |
1309 ast->fill_to(67+6); |
1283 if (nm->is_in_use()) {blob_name = nm->method()->name_and_sig_as_C_string(); } |
1310 if (nm->is_not_installed()) { |
1284 if (nm->is_not_entrant()) {blob_name = nm->method()->name_and_sig_as_C_string(); } |
1311 ast->print(" not (yet) installed method "); |
1285 if (nm->is_not_installed()) {ast->print("%s", " not (yet) installed method "); } |
1312 } |
1286 if (nm->is_zombie()) {ast->print("%s", " zombie method "); } |
1313 if (nm->is_zombie()) { |
|
1314 ast->print(" zombie method "); |
|
1315 } |
1287 ast->print("%s", blob_name); |
1316 ast->print("%s", blob_name); |
1288 } else { |
1317 } else { |
1289 //---< block size in hex >--- |
1318 //---< block size in hex >--- |
1290 ast->print(PTR32_FORMAT, (unsigned int)(TopSizeArray[i].len<<log2_seg_size)); |
1319 ast->print(PTR32_FORMAT, (unsigned int)(TopSizeArray[i].len<<log2_seg_size)); |
1291 ast->print("(" SIZE_FORMAT_W(4) "K)", (TopSizeArray[i].len<<log2_seg_size)/K); |
1320 ast->print("(" SIZE_FORMAT_W(4) "K)", (TopSizeArray[i].len<<log2_seg_size)/K); |
2081 if ((StatArray == NULL) || (alloc_granules == 0)) { |
2110 if ((StatArray == NULL) || (alloc_granules == 0)) { |
2082 return; |
2111 return; |
2083 } |
2112 } |
2084 STRINGSTREAM_DECL(ast, out) |
2113 STRINGSTREAM_DECL(ast, out) |
2085 |
2114 |
2086 unsigned int granules_per_line = 128; |
2115 unsigned int granules_per_line = 128; |
2087 char* low_bound = heap->low_boundary(); |
2116 char* low_bound = heap->low_boundary(); |
2088 CodeBlob* last_blob = NULL; |
2117 CodeBlob* last_blob = NULL; |
2089 bool name_in_addr_range = true; |
2118 bool name_in_addr_range = true; |
|
2119 bool have_CodeCache_lock = CodeCache_lock->owned_by_self(); |
2090 |
2120 |
2091 //---< print at least 128K per block (i.e. between headers) >--- |
2121 //---< print at least 128K per block (i.e. between headers) >--- |
2092 if (granules_per_line*granule_size < 128*K) { |
2122 if (granules_per_line*granule_size < 128*K) { |
2093 granules_per_line = (unsigned int)((128*K)/granule_size); |
2123 granules_per_line = (unsigned int)((128*K)/granule_size); |
2094 } |
2124 } |
2119 // Only check granule if it contains at least one blob. |
2149 // Only check granule if it contains at least one blob. |
2120 unsigned int nBlobs = StatArray[ix].t1_count + StatArray[ix].t2_count + StatArray[ix].tx_count + |
2150 unsigned int nBlobs = StatArray[ix].t1_count + StatArray[ix].t2_count + StatArray[ix].tx_count + |
2121 StatArray[ix].stub_count + StatArray[ix].dead_count; |
2151 StatArray[ix].stub_count + StatArray[ix].dead_count; |
2122 if (nBlobs > 0 ) { |
2152 if (nBlobs > 0 ) { |
2123 for (unsigned int is = 0; is < granule_size; is+=(unsigned int)seg_size) { |
2153 for (unsigned int is = 0; is < granule_size; is+=(unsigned int)seg_size) { |
2124 // heap->find_start() is safe. Only working with _segmap. Returns NULL or void*. Returned CodeBlob may be uninitialized. |
2154 // heap->find_start() is safe. Only works on _segmap. |
2125 CodeBlob* this_blob = (CodeBlob *)(heap->find_start(low_bound+ix*granule_size+is)); |
2155 // Returns NULL or void*. Returned CodeBlob may be uninitialized. |
2126 bool blob_initialized = (this_blob != NULL) && (this_blob->header_size() >= 0) && (this_blob->relocation_size() >= 0) && |
2156 char* this_seg = low_bound + ix*granule_size + is; |
2127 ((address)this_blob + this_blob->header_size() == (address)(this_blob->relocation_begin())) && |
2157 CodeBlob* this_blob = (CodeBlob*)(heap->find_start(this_seg)); |
2128 ((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin())) && |
2158 bool blob_is_safe = blob_access_is_safe(this_blob, NULL); |
2129 os::is_readable_pointer((address)(this_blob->relocation_begin())) && |
|
2130 os::is_readable_pointer(this_blob->content_begin()); |
|
2131 // blob could have been flushed, freed, and merged. |
2159 // blob could have been flushed, freed, and merged. |
2132 // this_blob < last_blob is an indicator for that. |
2160 // this_blob < last_blob is an indicator for that. |
2133 if (blob_initialized && (this_blob > last_blob)) { |
2161 if (blob_is_safe && (this_blob > last_blob)) { |
2134 last_blob = this_blob; |
2162 last_blob = this_blob; |
2135 |
2163 |
2136 //---< get type and name >--- |
2164 //---< get type and name >--- |
2137 blobType cbType = noType; |
2165 blobType cbType = noType; |
2138 if (segment_granules) { |
2166 if (segment_granules) { |
2139 cbType = (blobType)StatArray[ix].type; |
2167 cbType = (blobType)StatArray[ix].type; |
2140 } else { |
2168 } else { |
2141 cbType = get_cbType(this_blob); |
2169 //---< access these fields only if we own the CodeCache_lock >--- |
2142 } |
2170 if (have_CodeCache_lock) { |
2143 // this_blob->name() could return NULL if no name was given to CTOR. Inlined, maybe invisible on stack |
2171 cbType = get_cbType(this_blob); |
2144 const char* blob_name = this_blob->name(); |
2172 } |
2145 if ((blob_name == NULL) || !os::is_readable_pointer(blob_name)) { |
2173 } |
2146 blob_name = "<unavailable>"; |
2174 |
|
2175 //---< access these fields only if we own the CodeCache_lock >--- |
|
2176 const char* blob_name = "<unavailable>"; |
|
2177 nmethod* nm = NULL; |
|
2178 if (have_CodeCache_lock) { |
|
2179 blob_name = this_blob->name(); |
|
2180 nm = this_blob->as_nmethod_or_null(); |
|
2181 // this_blob->name() could return NULL if no name was given to CTOR. Inlined, maybe invisible on stack |
|
2182 if ((blob_name == NULL) || !os::is_readable_pointer(blob_name)) { |
|
2183 blob_name = "<unavailable>"; |
|
2184 } |
2147 } |
2185 } |
2148 |
2186 |
2149 //---< print table header for new print range >--- |
2187 //---< print table header for new print range >--- |
2150 if (!name_in_addr_range) { |
2188 if (!name_in_addr_range) { |
2151 name_in_addr_range = true; |
2189 name_in_addr_range = true; |
2161 ast->print(INTPTR_FORMAT, p2i(this_blob)); |
2199 ast->print(INTPTR_FORMAT, p2i(this_blob)); |
2162 ast->fill_to(19); |
2200 ast->fill_to(19); |
2163 ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound)); |
2201 ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound)); |
2164 ast->fill_to(33); |
2202 ast->fill_to(33); |
2165 |
2203 |
2166 // this_blob->as_nmethod_or_null() is safe. Inlined, maybe invisible on stack. |
2204 // access nmethod and Method fields only if we own the CodeCache_lock. |
2167 nmethod* nm = this_blob->as_nmethod_or_null(); |
2205 // This fact is implicitly transported via nm != NULL. |
2168 if (CompiledMethod::nmethod_access_is_safe(nm)) { |
2206 if (CompiledMethod::nmethod_access_is_safe(nm)) { |
2169 Method* method = nm->method(); |
2207 Method* method = nm->method(); |
2170 ResourceMark rm; |
2208 ResourceMark rm; |
2171 //---< collect all data to locals as quickly as possible >--- |
2209 //---< collect all data to locals as quickly as possible >--- |
2172 unsigned int total_size = nm->total_size(); |
2210 unsigned int total_size = nm->total_size(); |
2199 ast->print("%s", methNameS); |
2237 ast->print("%s", methNameS); |
2200 ast->print("%s", methSigS); |
2238 ast->print("%s", methSigS); |
2201 } else { |
2239 } else { |
2202 ast->print("%s", blob_name); |
2240 ast->print("%s", blob_name); |
2203 } |
2241 } |
2204 } else { |
2242 } else if (blob_is_safe) { |
2205 ast->fill_to(62+6); |
2243 ast->fill_to(62+6); |
2206 ast->print("%s", blobTypeName[cbType]); |
2244 ast->print("%s", blobTypeName[cbType]); |
2207 ast->fill_to(82+6); |
2245 ast->fill_to(82+6); |
2208 ast->print("%s", blob_name); |
2246 ast->print("%s", blob_name); |
|
2247 } else { |
|
2248 ast->fill_to(62+6); |
|
2249 ast->print("<stale blob>"); |
2209 } |
2250 } |
2210 STRINGSTREAM_FLUSH_LOCKED("\n") |
2251 STRINGSTREAM_FLUSH_LOCKED("\n") |
2211 } else if (!blob_initialized && (this_blob != last_blob) && (this_blob != NULL)) { |
2252 } else if (!blob_is_safe && (this_blob != last_blob) && (this_blob != NULL)) { |
2212 last_blob = this_blob; |
2253 last_blob = this_blob; |
2213 STRINGSTREAM_FLUSH_LOCKED("\n") |
2254 STRINGSTREAM_FLUSH_LOCKED("\n") |
2214 } |
2255 } |
2215 } |
2256 } |
2216 } // nBlobs > 0 |
2257 } // nBlobs > 0 |
2373 if (cb->is_safepoint_stub()) return safepointStub; |
2414 if (cb->is_safepoint_stub()) return safepointStub; |
2374 if (cb->is_adapter_blob()) return adapterBlob; |
2415 if (cb->is_adapter_blob()) return adapterBlob; |
2375 if (cb->is_method_handles_adapter_blob()) return mh_adapterBlob; |
2416 if (cb->is_method_handles_adapter_blob()) return mh_adapterBlob; |
2376 if (cb->is_buffer_blob()) return bufferBlob; |
2417 if (cb->is_buffer_blob()) return bufferBlob; |
2377 |
2418 |
2378 nmethod* nm = cb->as_nmethod_or_null(); |
2419 //---< access these fields only if we own the CodeCache_lock >--- |
2379 if (nm != NULL) { // no is_readable check required, nm = (nmethod*)cb. |
2420 // Should be ensured by caller. aggregate() amd print_names() do that. |
2380 if (nm->is_not_installed()) return nMethod_inconstruction; |
2421 if (CodeCache_lock->owned_by_self()) { |
2381 if (nm->is_zombie()) return nMethod_dead; |
2422 nmethod* nm = cb->as_nmethod_or_null(); |
2382 if (nm->is_unloaded()) return nMethod_unloaded; |
2423 if (nm != NULL) { // no is_readable check required, nm = (nmethod*)cb. |
2383 if (nm->is_in_use()) return nMethod_inuse; |
2424 if (nm->is_not_installed()) return nMethod_inconstruction; |
2384 if (nm->is_alive() && !(nm->is_not_entrant())) return nMethod_notused; |
2425 if (nm->is_zombie()) return nMethod_dead; |
2385 if (nm->is_alive()) return nMethod_alive; |
2426 if (nm->is_unloaded()) return nMethod_unloaded; |
2386 return nMethod_dead; |
2427 if (nm->is_in_use()) return nMethod_inuse; |
|
2428 if (nm->is_alive() && !(nm->is_not_entrant())) return nMethod_notused; |
|
2429 if (nm->is_alive()) return nMethod_alive; |
|
2430 return nMethod_dead; |
|
2431 } |
2387 } |
2432 } |
2388 } |
2433 } |
2389 return noType; |
2434 return noType; |
2390 } |
2435 } |
|
2436 |
|
2437 bool CodeHeapState::blob_access_is_safe(CodeBlob* this_blob, CodeBlob* prev_blob) { |
|
2438 return (this_blob != NULL) && // a blob must have been found, obviously |
|
2439 ((this_blob == prev_blob) || (prev_blob == NULL)) && // when re-checking, the same blob must have been found |
|
2440 (this_blob->header_size() >= 0) && |
|
2441 (this_blob->relocation_size() >= 0) && |
|
2442 ((address)this_blob + this_blob->header_size() == (address)(this_blob->relocation_begin())) && |
|
2443 ((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin())) && |
|
2444 os::is_readable_pointer((address)(this_blob->relocation_begin())) && |
|
2445 os::is_readable_pointer(this_blob->content_begin()); |
|
2446 } |