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