1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 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 #include "precompiled.hpp" 25 #include "code/relocInfo.hpp" 26 #include "code/nativeInst.hpp" 27 #include "code/nmethod.hpp" 28 #include "gc/z/zHash.inline.hpp" 29 #include "gc/z/zNMethodTable.hpp" 30 #include "logging/log.hpp" 31 #include "memory/allocation.inline.hpp" 32 #include "memory/resourceArea.hpp" 33 #include "oops/oop.inline.hpp" 34 #include "runtime/atomic.hpp" 35 #include "utilities/debug.hpp" 36 37 class ZNMethodWithImmediateOops { 38 private: 39 nmethod* const _nm; 40 const size_t _nimmediate_oops; 41 42 static size_t header_size(); 43 44 ZNMethodWithImmediateOops(nmethod* nm, const GrowableArray<oop*>& immediate_oops); 45 46 public: 47 static ZNMethodWithImmediateOops* create(nmethod* nm, const GrowableArray<oop*>& immediate_oops); 48 static void destroy(ZNMethodWithImmediateOops* nmi); 49 50 nmethod* method() const; 51 size_t immediate_oops_count() const; 52 oop** immediate_oops_begin() const; 53 oop** immediate_oops_begin_safe() const; 54 oop** immediate_oops_end() const; 55 }; 56 57 size_t ZNMethodWithImmediateOops::header_size() { 58 const size_t size = sizeof(ZNMethodWithImmediateOops); 59 assert(is_aligned(size, sizeof(oop*)), "Header misaligned"); 60 return size; 61 } 62 63 ZNMethodWithImmediateOops::ZNMethodWithImmediateOops(nmethod* nm, const GrowableArray<oop*>& immediate_oops) : 64 _nm(nm), 65 _nimmediate_oops(immediate_oops.length()) { 66 // Save all immediate oops 67 for (size_t i = 0; i < _nimmediate_oops; i++) { 68 immediate_oops_begin()[i] = immediate_oops.at(i); 69 } 70 } 71 72 ZNMethodWithImmediateOops* ZNMethodWithImmediateOops::create(nmethod* nm, const GrowableArray<oop*>& immediate_oops) { 73 // Allocate memory for the ZNMethodWithImmediateOops object 74 // plus the immediate oop* array that follows right after. 75 const size_t size = header_size() + (sizeof(oop*) * immediate_oops.length()); 76 void* const method_with_immediate_oops = NEW_C_HEAP_ARRAY(uint8_t, size, mtGC); 77 return ::new (method_with_immediate_oops) ZNMethodWithImmediateOops(nm, immediate_oops); 78 } 79 80 void ZNMethodWithImmediateOops::destroy(ZNMethodWithImmediateOops* nmi) { 81 FREE_C_HEAP_ARRAY(uint8_t, nmi); 82 } 83 84 nmethod* ZNMethodWithImmediateOops::method() const { 85 return _nm; 86 } 87 88 size_t ZNMethodWithImmediateOops::immediate_oops_count() const { 89 return _nimmediate_oops; 90 } 91 92 oop** ZNMethodWithImmediateOops::immediate_oops_begin() const { 93 // The immediate oop* array starts immediately after this object 94 return (oop**)((uintptr_t)this + header_size()); 95 } 96 97 oop** ZNMethodWithImmediateOops::immediate_oops_begin_safe() const { 98 // Non-entrant nmethods have a jump instruction patched into the beginning 99 // of the verified entry point, which could have overwritten an immediate 100 // oop. If so, make sure we skip over that oop. 101 if (_nm->is_not_entrant()) { 102 oop* const first_immediate_oop = *immediate_oops_begin(); 103 oop* const safe_begin = (oop*)(_nm->verified_entry_point() + NativeJump::instruction_size); 104 if (first_immediate_oop < safe_begin) { 105 // First immediate oop overwritten, skip it 106 return immediate_oops_begin() + 1; 107 } 108 } 109 110 // First immediate oop not overwritten 111 return immediate_oops_begin(); 112 } 113 114 115 oop** ZNMethodWithImmediateOops::immediate_oops_end() const { 116 return immediate_oops_begin() + immediate_oops_count(); 117 } 118 119 ZNMethodTableEntry* ZNMethodTable::_table = NULL; 120 size_t ZNMethodTable::_size = 0; 121 size_t ZNMethodTable::_nregistered = 0; 122 size_t ZNMethodTable::_nunregistered = 0; 123 volatile size_t ZNMethodTable::_claimed = 0; 124 125 ZNMethodTableEntry ZNMethodTable::create_entry(nmethod* nm) { 126 GrowableArray<oop*> immediate_oops; 127 bool non_immediate_oops = false; 128 129 // Find all oops relocations 130 RelocIterator iter(nm); 131 while (iter.next()) { 132 if (iter.type() != relocInfo::oop_type) { 133 // Not an oop 134 continue; 135 } 136 137 oop_Relocation* r = iter.oop_reloc(); 138 139 if (!r->oop_is_immediate()) { 140 // Non-immediate oop found 141 non_immediate_oops = true; 142 continue; 143 } 144 145 if (r->oop_value() != NULL) { 146 // Non-NULL immediate oop found. NULL oops can safely be 147 // ignored since the method will be re-registered if they 148 // are later patched to be non-NULL. 149 immediate_oops.push(r->oop_addr()); 150 } 151 } 152 153 // oops_count() returns the number of oops in the oop table plus one 154 if (immediate_oops.is_empty() && nm->oops_count() == 1) { 155 // No oops found, return empty entry 156 return ZNMethodTableEntry(); 157 } 158 159 if (immediate_oops.is_empty()) { 160 // No immediate oops found, return entry without immediate oops 161 return ZNMethodTableEntry(nm, non_immediate_oops); 162 } 163 164 // Return entry with immediate oops 165 return ZNMethodTableEntry(ZNMethodWithImmediateOops::create(nm, immediate_oops), non_immediate_oops); 166 } 167 168 void ZNMethodTable::destroy_entry(ZNMethodTableEntry entry) { 169 if (entry.immediate_oops()) { 170 ZNMethodWithImmediateOops::destroy(entry.method_with_immediate_oops()); 171 } 172 } 173 174 nmethod* ZNMethodTable::method(ZNMethodTableEntry entry) { 175 return entry.immediate_oops() ? entry.method_with_immediate_oops()->method() : entry.method(); 176 } 177 178 size_t ZNMethodTable::first_index(const nmethod* nm, size_t size) { 179 assert(is_power_of_2(size), "Invalid size"); 180 const size_t mask = size - 1; 181 const size_t hash = ZHash::address_to_uint32((uintptr_t)nm); 182 return hash & mask; 183 } 184 185 size_t ZNMethodTable::next_index(size_t prev_index, size_t size) { 186 assert(is_power_of_2(size), "Invalid size"); 187 const size_t mask = size - 1; 188 return (prev_index + 1) & mask; 189 } 190 191 bool ZNMethodTable::register_entry(ZNMethodTableEntry* table, size_t size, ZNMethodTableEntry entry) { 192 const nmethod* const nm = method(entry); 193 size_t index = first_index(nm, size); 194 195 for (;;) { 196 const ZNMethodTableEntry table_entry = table[index]; 197 198 if (!table_entry.registered() && !table_entry.unregistered()) { 199 // Insert new entry 200 table[index] = entry; 201 return true; 202 } 203 204 if (table_entry.registered() && method(table_entry) == nm) { 205 // Replace existing entry 206 destroy_entry(table_entry); 207 table[index] = entry; 208 return false; 209 } 210 211 index = next_index(index, size); 212 } 213 } 214 215 bool ZNMethodTable::unregister_entry(ZNMethodTableEntry* table, size_t size, const nmethod* nm) { 216 if (size == 0) { 217 // Table is empty 218 return false; 219 } 220 221 size_t index = first_index(nm, size); 222 223 for (;;) { 224 const ZNMethodTableEntry table_entry = table[index]; 225 226 if (!table_entry.registered() && !table_entry.unregistered()) { 227 // Entry not found 228 return false; 229 } 230 231 if (table_entry.registered() && method(table_entry) == nm) { 232 // Remove entry 233 destroy_entry(table_entry); 234 table[index] = ZNMethodTableEntry(true /* unregistered */); 235 return true; 236 } 237 238 index = next_index(index, size); 239 } 240 } 241 242 void ZNMethodTable::rebuild(size_t new_size) { 243 assert(is_power_of_2(new_size), "Invalid size"); 244 245 log_debug(gc, nmethod)("Rebuilding NMethod Table: " 246 SIZE_FORMAT "->" SIZE_FORMAT " entries, " 247 SIZE_FORMAT "(%.0lf%%->%.0lf%%) registered, " 248 SIZE_FORMAT "(%.0lf%%->%.0lf%%) unregistered", 249 _size, new_size, 250 _nregistered, percent_of(_nregistered, _size), percent_of(_nregistered, new_size), 251 _nunregistered, percent_of(_nunregistered, _size), 0.0); 252 253 // Allocate new table 254 ZNMethodTableEntry* const new_table = new ZNMethodTableEntry[new_size]; 255 256 // Transfer all registered entries 257 for (size_t i = 0; i < _size; i++) { 258 const ZNMethodTableEntry entry = _table[i]; 259 if (entry.registered()) { 260 register_entry(new_table, new_size, entry); 261 } 262 } 263 264 // Delete old table 265 delete [] _table; 266 267 // Install new table 268 _table = new_table; 269 _size = new_size; 270 _nunregistered = 0; 271 } 272 273 void ZNMethodTable::rebuild_if_needed() { 274 // The hash table uses linear probing. To avoid wasting memory while 275 // at the same time maintaining good hash collision behavior we want 276 // to keep the table occupancy between 30% and 70%. The table always 277 // grows/shrinks by doubling/halving its size. Pruning of unregistered 278 // entries is done by rebuilding the table with or without resizing it. 279 const size_t min_size = 1024; 280 const size_t shrink_threshold = _size * 0.30; 281 const size_t prune_threshold = _size * 0.65; 282 const size_t grow_threshold = _size * 0.70; 283 284 if (_size == 0) { 285 // Initialize table 286 rebuild(min_size); 287 } else if (_nregistered < shrink_threshold && _size > min_size) { 288 // Shrink table 289 rebuild(_size / 2); 290 } else if (_nregistered + _nunregistered > grow_threshold) { 291 // Prune or grow table 292 if (_nregistered < prune_threshold) { 293 // Prune table 294 rebuild(_size); 295 } else { 296 // Grow table 297 rebuild(_size * 2); 298 } 299 } 300 } 301 302 void ZNMethodTable::log_register(const nmethod* nm, ZNMethodTableEntry entry) { 303 LogTarget(Trace, gc, nmethod) log; 304 if (!log.is_enabled()) { 305 return; 306 } 307 308 log.print("Register NMethod: %s.%s (" PTR_FORMAT "), " 309 "Compiler: %s, Oops: %d, ImmediateOops: " SIZE_FORMAT ", NonImmediateOops: %s", 310 nm->method()->method_holder()->external_name(), 311 nm->method()->name()->as_C_string(), 312 p2i(nm), 313 nm->compiler_name(), 314 nm->oops_count() - 1, 315 entry.immediate_oops() ? entry.method_with_immediate_oops()->immediate_oops_count() : 0, 316 BOOL_TO_STR(entry.non_immediate_oops())); 317 318 LogTarget(Trace, gc, nmethod, oops) log_oops; 319 if (!log_oops.is_enabled()) { 320 return; 321 } 322 323 // Print nmethod oops table 324 oop* const begin = nm->oops_begin(); 325 oop* const end = nm->oops_end(); 326 for (oop* p = begin; p < end; p++) { 327 log_oops.print(" Oop[" SIZE_FORMAT "] " PTR_FORMAT " (%s)", 328 (p - begin), p2i(*p), (*p)->klass()->external_name()); 329 } 330 331 if (entry.immediate_oops()) { 332 // Print nmethod immediate oops 333 const ZNMethodWithImmediateOops* const nmi = entry.method_with_immediate_oops(); 334 oop** const begin = nmi->immediate_oops_begin(); 335 oop** const end = nmi->immediate_oops_end(); 336 for (oop** p = begin; p < end; p++) { 337 log_oops.print(" ImmediateOop[" SIZE_FORMAT "] " PTR_FORMAT " @ " PTR_FORMAT " (%s)", 338 (p - begin), p2i(**p), p2i(*p), (**p)->klass()->external_name()); 339 } 340 } 341 } 342 343 void ZNMethodTable::log_unregister(const nmethod* nm) { 344 LogTarget(Debug, gc, nmethod) log; 345 if (!log.is_enabled()) { 346 return; 347 } 348 349 log.print("Unregister NMethod: %s.%s (" PTR_FORMAT ")", 350 nm->method()->method_holder()->external_name(), 351 nm->method()->name()->as_C_string(), 352 p2i(nm)); 353 } 354 355 size_t ZNMethodTable::registered_nmethods() { 356 return _nregistered; 357 } 358 359 size_t ZNMethodTable::unregistered_nmethods() { 360 return _nunregistered; 361 } 362 363 void ZNMethodTable::register_nmethod(nmethod* nm) { 364 ResourceMark rm; 365 366 // Create entry 367 const ZNMethodTableEntry entry = create_entry(nm); 368 369 log_register(nm, entry); 370 371 if (!entry.registered()) { 372 // Method doesn't have any oops, ignore it 373 return; 374 } 375 376 // Grow/Shrink/Prune table if needed 377 rebuild_if_needed(); 378 379 // Insert new entry 380 if (register_entry(_table, _size, entry)) { 381 // New entry registered. When register_entry() instead returns 382 // false the nmethod was already in the table so we do not want 383 // to increase number of registered entries in that case. 384 _nregistered++; 385 } 386 } 387 388 void ZNMethodTable::unregister_nmethod(nmethod* nm) { 389 ResourceMark rm; 390 391 log_unregister(nm); 392 393 // Remove entry 394 if (unregister_entry(_table, _size, nm)) { 395 // Entry was unregistered. When unregister_entry() instead returns 396 // false the nmethod was not in the table (because it didn't have 397 // any oops) so we do not want to decrease the number of registered 398 // entries in that case. 399 _nregistered--; 400 _nunregistered++; 401 } 402 } 403 404 void ZNMethodTable::gc_prologue() { 405 _claimed = 0; 406 } 407 408 void ZNMethodTable::gc_epilogue() { 409 assert(_claimed >= _size, "Failed to claim all table entries"); 410 } 411 412 void ZNMethodTable::entry_oops_do(ZNMethodTableEntry entry, OopClosure* cl) { 413 nmethod* const nm = method(entry); 414 if (!nm->is_alive()) { 415 // No need to visit oops 416 return; 417 } 418 419 // Process oops table 420 oop* const begin = nm->oops_begin(); 421 oop* const end = nm->oops_end(); 422 for (oop* p = begin; p < end; p++) { 423 if (*p != Universe::non_oop_word()) { 424 cl->do_oop(p); 425 } 426 } 427 428 if (entry.immediate_oops()) { 429 // Process immediate oops 430 const ZNMethodWithImmediateOops* const nmi = entry.method_with_immediate_oops(); 431 oop** const begin = nmi->immediate_oops_begin_safe(); 432 oop** const end = nmi->immediate_oops_end(); 433 for (oop** p = begin; p < end; p++) { 434 cl->do_oop(*p); 435 } 436 } 437 438 if (entry.non_immediate_oops()) { 439 // Process non-immediate oops 440 nm->fix_oop_relocations(); 441 } 442 } 443 444 void ZNMethodTable::oops_do(OopClosure* cl) { 445 for (;;) { 446 // Claim table partition 447 const size_t partition_size = DEFAULT_CACHE_LINE_SIZE / sizeof(ZNMethodTableEntry); 448 const size_t partition_start = MIN2(Atomic::add(partition_size, &_claimed) - partition_size, _size); 449 const size_t partition_end = MIN2(partition_start + partition_size, _size); 450 if (partition_start == partition_end) { 451 // End of table 452 break; 453 } 454 455 // Process table partition 456 for (size_t i = partition_start; i < partition_end; i++) { 457 const ZNMethodTableEntry entry = _table[i]; 458 if (entry.registered()) { 459 entry_oops_do(entry, cl); 460 } 461 } 462 } 463 }