1 /* 2 * Copyright (c) 2017, 2025, 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 "classfile/classLoaderData.hpp" 25 #include "classfile/classLoaderDataGraph.hpp" 26 #include "gc/shared/barrierSet.hpp" 27 #include "gc/shared/barrierSetNMethod.hpp" 28 #include "gc/shared/gc_globals.hpp" 29 #include "gc/shared/taskqueue.inline.hpp" 30 #include "gc/z/zAddress.inline.hpp" 31 #include "gc/z/zCollectedHeap.hpp" 32 #include "gc/z/zGenerationId.hpp" 33 #include "gc/z/zGlobals.hpp" 34 #include "gc/z/zGranuleMap.inline.hpp" 35 #include "gc/z/zHeap.inline.hpp" 36 #include "gc/z/zHeapIterator.hpp" 37 #include "gc/z/zLock.inline.hpp" 38 #include "gc/z/zNMethod.hpp" 39 #include "memory/iterator.inline.hpp" 40 #include "utilities/bitMap.inline.hpp" 41 42 class ZHeapIteratorBitMap : public CHeapObj<mtGC> { 43 private: 44 CHeapBitMap _bitmap; 45 46 public: 47 ZHeapIteratorBitMap(size_t size_in_bits) 48 : _bitmap(size_in_bits, mtGC) {} 49 50 bool try_set_bit(size_t index) { 51 return _bitmap.par_set_bit(index); 52 } 53 }; 54 55 class ZHeapIteratorContext { 56 private: 57 ObjectClosure* const _object_cl; 58 OopFieldClosure* const _field_cl; 59 const uint _worker_id; 60 ZHeapIteratorQueue* const _queue; 61 ZHeapIteratorArrayChunkQueue* const _array_chunk_queue; 62 63 public: 64 ZHeapIteratorContext(ObjectClosure* object_cl, 65 OopFieldClosure* field_cl, 66 uint worker_id, 67 ZHeapIteratorQueue* queue, 68 ZHeapIteratorArrayChunkQueue* array_chunk_queue) 69 : _object_cl(object_cl), 70 _field_cl(field_cl), 71 _worker_id(worker_id), 72 _queue(queue), 73 _array_chunk_queue(array_chunk_queue) {} 74 75 uint worker_id() const { 76 return _worker_id; 77 } 78 79 void visit_field(oop base, oop* p) const { 80 if (_field_cl != nullptr) { 81 _field_cl->do_field(base, p); 82 } 83 } 84 85 void visit_object(oop obj) const { 86 _object_cl->do_object(obj); 87 } 88 89 void push(oop obj) const { 90 _queue->push(obj); 91 } 92 93 void push_array_chunk(const ObjArrayTask& array_chunk) const { 94 _array_chunk_queue->push(array_chunk); 95 } 96 97 bool pop(oop& obj) const { 98 return _queue->pop_overflow(obj) || _queue->pop_local(obj); 99 } 100 101 bool pop_array_chunk(ObjArrayTask& array_chunk) const { 102 return _array_chunk_queue->pop_overflow(array_chunk) || _array_chunk_queue->pop_local(array_chunk); 103 } 104 105 bool is_drained() const { 106 return _queue->is_empty() && _array_chunk_queue->is_empty(); 107 } 108 }; 109 110 template <bool Weak> 111 class ZHeapIteratorColoredRootOopClosure : public OopClosure { 112 private: 113 ZHeapIterator* const _iter; 114 const ZHeapIteratorContext& _context; 115 116 oop load_oop(oop* p) { 117 if (Weak) { 118 return NativeAccess<AS_NO_KEEPALIVE | ON_PHANTOM_OOP_REF>::oop_load(p); 119 } 120 121 return NativeAccess<AS_NO_KEEPALIVE>::oop_load(p); 122 } 123 124 public: 125 ZHeapIteratorColoredRootOopClosure(ZHeapIterator* iter, 126 const ZHeapIteratorContext& context) 127 : _iter(iter), 128 _context(context) {} 129 130 virtual void do_oop(oop* p) { 131 _context.visit_field(nullptr, p); 132 const oop obj = load_oop(p); 133 _iter->mark_visit_and_push(_context, obj); 134 } 135 136 virtual void do_oop(narrowOop* p) { 137 ShouldNotReachHere(); 138 } 139 }; 140 141 class ZHeapIteratorUncoloredRootOopClosure : public OopClosure { 142 private: 143 ZHeapIterator* const _iter; 144 const ZHeapIteratorContext& _context; 145 146 oop load_oop(oop* p) { 147 const oop o = Atomic::load(p); 148 check_is_valid_zaddress(o); 149 return RawAccess<>::oop_load(p); 150 } 151 152 public: 153 ZHeapIteratorUncoloredRootOopClosure(ZHeapIterator* iter, 154 const ZHeapIteratorContext& context) 155 : _iter(iter), 156 _context(context) {} 157 158 virtual void do_oop(oop* p) { 159 _context.visit_field(nullptr, p); 160 const oop obj = load_oop(p); 161 _iter->mark_visit_and_push(_context, obj); 162 } 163 164 virtual void do_oop(narrowOop* p) { 165 ShouldNotReachHere(); 166 } 167 }; 168 169 class ZHeapIteratorCLDOopClosure : public OopClosure { 170 private: 171 ZHeapIterator* const _iter; 172 const ZHeapIteratorContext& _context; 173 174 oop load_oop(oop* p) { 175 assert(!ZCollectedHeap::heap()->is_in(p), "Should not be in heap"); 176 return NativeAccess<AS_NO_KEEPALIVE>::oop_load(p); 177 } 178 179 public: 180 ZHeapIteratorCLDOopClosure(ZHeapIterator* iter, 181 const ZHeapIteratorContext& context) 182 : _iter(iter), 183 _context(context) {} 184 185 virtual void do_oop(oop* p) { 186 const oop obj = load_oop(p); 187 _iter->mark_visit_and_push(_context, obj); 188 } 189 190 virtual void do_oop(narrowOop* p) { 191 ShouldNotReachHere(); 192 } 193 }; 194 195 template <bool VisitReferents> 196 class ZHeapIteratorOopClosure : public OopIterateClosure { 197 private: 198 ZHeapIterator* const _iter; 199 const ZHeapIteratorContext& _context; 200 const oop _base; 201 202 oop load_oop(oop* p) { 203 assert(ZCollectedHeap::heap()->is_in(p), "Should be in heap"); 204 205 if (VisitReferents) { 206 return HeapAccess<AS_NO_KEEPALIVE | ON_UNKNOWN_OOP_REF>::oop_load_at(_base, (ptrdiff_t)_base->field_offset(p)); 207 } 208 209 return HeapAccess<AS_NO_KEEPALIVE>::oop_load(p); 210 } 211 212 public: 213 ZHeapIteratorOopClosure(ZHeapIterator* iter, 214 const ZHeapIteratorContext& context, 215 oop base) 216 : OopIterateClosure(), 217 _iter(iter), 218 _context(context), 219 _base(base) {} 220 221 virtual ReferenceIterationMode reference_iteration_mode() { 222 return VisitReferents ? DO_FIELDS : DO_FIELDS_EXCEPT_REFERENT; 223 } 224 225 virtual void do_oop(oop* p) { 226 _context.visit_field(_base, p); 227 const oop obj = load_oop(p); 228 _iter->mark_visit_and_push(_context, obj); 229 } 230 231 virtual void do_oop(narrowOop* p) { 232 ShouldNotReachHere(); 233 } 234 235 virtual bool do_metadata() { 236 return true; 237 } 238 239 virtual void do_klass(Klass* k) { 240 ClassLoaderData* const cld = k->class_loader_data(); 241 ZHeapIteratorOopClosure::do_cld(cld); 242 } 243 244 virtual void do_cld(ClassLoaderData* cld) { 245 ZHeapIteratorCLDOopClosure cl(_iter, _context); 246 cld->oops_do(&cl, ClassLoaderData::_claim_other); 247 } 248 249 // Don't follow loom stack metadata; it's already followed in other ways through CLDs 250 virtual void do_nmethod(nmethod* nm) {} 251 virtual void do_method(Method* m) {} 252 }; 253 254 ZHeapIterator::ZHeapIterator(uint nworkers, 255 bool visit_weaks, 256 bool for_verify) 257 : _visit_weaks(visit_weaks), 258 _for_verify(for_verify), 259 _bitmaps(ZAddressOffsetMax), 260 _bitmaps_lock(), 261 _queues(nworkers), 262 _array_chunk_queues(nworkers), 263 _roots_colored(ZGenerationIdOptional::none), 264 _roots_uncolored(ZGenerationIdOptional::none), 265 _roots_weak_colored(ZGenerationIdOptional::none), 266 _terminator(nworkers, &_queues) { 267 268 // Create queues 269 for (uint i = 0; i < _queues.size(); i++) { 270 ZHeapIteratorQueue* const queue = new ZHeapIteratorQueue(); 271 _queues.register_queue(i, queue); 272 } 273 274 // Create array chunk queues 275 for (uint i = 0; i < _array_chunk_queues.size(); i++) { 276 ZHeapIteratorArrayChunkQueue* const array_chunk_queue = new ZHeapIteratorArrayChunkQueue(); 277 _array_chunk_queues.register_queue(i, array_chunk_queue); 278 } 279 } 280 281 ZHeapIterator::~ZHeapIterator() { 282 // Destroy bitmaps 283 ZHeapIteratorBitMapsIterator iter(&_bitmaps); 284 for (ZHeapIteratorBitMap* bitmap; iter.next(&bitmap);) { 285 delete bitmap; 286 } 287 288 // Destroy array chunk queues 289 for (uint i = 0; i < _array_chunk_queues.size(); i++) { 290 delete _array_chunk_queues.queue(i); 291 } 292 293 // Destroy queues 294 for (uint i = 0; i < _queues.size(); i++) { 295 delete _queues.queue(i); 296 } 297 298 // Clear claimed CLD bits 299 ClassLoaderDataGraph::clear_claimed_marks(ClassLoaderData::_claim_other); 300 } 301 302 static size_t object_index_max() { 303 return ZGranuleSize >> ZObjectAlignmentSmallShift; 304 } 305 306 static size_t object_index(oop obj) { 307 const zaddress addr = to_zaddress(obj); 308 const zoffset offset = ZAddress::offset(addr); 309 const uintptr_t mask = ZGranuleSize - 1; 310 return (untype(offset) & mask) >> ZObjectAlignmentSmallShift; 311 } 312 313 ZHeapIteratorBitMap* ZHeapIterator::object_bitmap(oop obj) { 314 const zoffset offset = ZAddress::offset(to_zaddress(obj)); 315 ZHeapIteratorBitMap* bitmap = _bitmaps.get_acquire(offset); 316 if (bitmap == nullptr) { 317 ZLocker<ZLock> locker(&_bitmaps_lock); 318 bitmap = _bitmaps.get(offset); 319 if (bitmap == nullptr) { 320 // Install new bitmap 321 bitmap = new ZHeapIteratorBitMap(object_index_max()); 322 _bitmaps.release_put(offset, bitmap); 323 } 324 } 325 326 return bitmap; 327 } 328 329 bool ZHeapIterator::should_visit_object_at_mark() const { 330 // Verify wants to visit objects as soon as they are found. 331 return _for_verify; 332 } 333 334 bool ZHeapIterator::should_visit_object_at_follow() const { 335 // Non-verify code needs to be careful and visit the objects 336 // during the follow stage, where we've completed the root 337 // iteration. This prevents lock-ordering problems between 338 // the root iterator and the visit closures. 339 return !_for_verify; 340 } 341 342 bool ZHeapIterator::mark_object(oop obj) { 343 if (obj == nullptr) { 344 return false; 345 } 346 347 ZHeapIteratorBitMap* const bitmap = object_bitmap(obj); 348 const size_t index = object_index(obj); 349 return bitmap->try_set_bit(index); 350 } 351 352 typedef ClaimingCLDToOopClosure<ClassLoaderData::_claim_other> ZHeapIteratorCLDClosure; 353 354 class ZHeapIteratorNMethodClosure : public NMethodClosure { 355 private: 356 OopClosure* const _cl; 357 BarrierSetNMethod* const _bs_nm; 358 359 public: 360 ZHeapIteratorNMethodClosure(OopClosure* cl) 361 : _cl(cl), 362 _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {} 363 364 virtual void do_nmethod(nmethod* nm) { 365 // If ClassUnloading is turned off, all nmethods are considered strong, 366 // not only those on the call stacks. The heap iteration might happen 367 // before the concurrent processign of the code cache, make sure that 368 // all nmethods have been processed before visiting the oops. 369 _bs_nm->nmethod_entry_barrier(nm); 370 371 ZNMethod::nmethod_oops_do(nm, _cl); 372 } 373 }; 374 375 class ZHeapIteratorThreadClosure : public ThreadClosure { 376 private: 377 OopClosure* const _cl; 378 NMethodClosure* const _nm_cl; 379 380 public: 381 ZHeapIteratorThreadClosure(OopClosure* cl, NMethodClosure* nm_cl) 382 : _cl(cl), 383 _nm_cl(nm_cl) {} 384 385 void do_thread(Thread* thread) { 386 thread->oops_do(_cl, _nm_cl); 387 } 388 }; 389 390 void ZHeapIterator::push_strong_roots(const ZHeapIteratorContext& context) { 391 { 392 ZHeapIteratorColoredRootOopClosure<false /* Weak */> cl(this, context); 393 ZHeapIteratorCLDClosure cld_cl(&cl); 394 395 _roots_colored.apply(&cl, 396 &cld_cl); 397 } 398 399 { 400 ZHeapIteratorUncoloredRootOopClosure cl(this, context); 401 ZHeapIteratorNMethodClosure nm_cl(&cl); 402 ZHeapIteratorThreadClosure thread_cl(&cl, &nm_cl); 403 _roots_uncolored.apply(&thread_cl, 404 &nm_cl); 405 } 406 } 407 408 void ZHeapIterator::push_weak_roots(const ZHeapIteratorContext& context) { 409 ZHeapIteratorColoredRootOopClosure<true /* Weak */> cl(this, context); 410 _roots_weak_colored.apply(&cl); 411 } 412 413 template <bool VisitWeaks> 414 void ZHeapIterator::push_roots(const ZHeapIteratorContext& context) { 415 push_strong_roots(context); 416 if (VisitWeaks) { 417 push_weak_roots(context); 418 } 419 } 420 421 void ZHeapIterator::mark_visit_and_push(const ZHeapIteratorContext& context, oop obj) { 422 if (mark_object(obj)) { 423 if (should_visit_object_at_mark()) { 424 context.visit_object(obj); 425 } 426 context.push(obj); 427 } 428 } 429 430 template <bool VisitReferents> 431 void ZHeapIterator::follow_object(const ZHeapIteratorContext& context, oop obj) { 432 ZHeapIteratorOopClosure<VisitReferents> cl(this, context, obj); 433 ZIterator::oop_iterate(obj, &cl); 434 } 435 436 void ZHeapIterator::follow_array(const ZHeapIteratorContext& context, oop obj) { 437 // Follow klass 438 ZHeapIteratorOopClosure<false /* VisitReferents */> cl(this, context, obj); 439 cl.do_klass(obj->klass()); 440 441 // Push array chunk 442 context.push_array_chunk(ObjArrayTask(obj, 0 /* index */)); 443 } 444 445 void ZHeapIterator::follow_array_chunk(const ZHeapIteratorContext& context, const ObjArrayTask& array) { 446 const objArrayOop obj = objArrayOop(array.obj()); 447 const int length = obj->length(); 448 const int start = array.index(); 449 const int stride = MIN2<int>(length - start, (int)ObjArrayMarkingStride); 450 const int end = start + stride; 451 452 // Push remaining array chunk first 453 if (end < length) { 454 context.push_array_chunk(ObjArrayTask(obj, end)); 455 } 456 457 // Follow array chunk 458 ZHeapIteratorOopClosure<false /* VisitReferents */> cl(this, context, obj); 459 ZIterator::oop_iterate_range(obj, &cl, start, end); 460 } 461 462 template <bool VisitWeaks> 463 void ZHeapIterator::follow(const ZHeapIteratorContext& context, oop obj) { 464 // Follow 465 if (obj->is_objArray()) { 466 follow_array(context, obj); 467 } else { 468 follow_object<VisitWeaks>(context, obj); 469 } 470 } 471 472 template <bool VisitWeaks> 473 void ZHeapIterator::visit_and_follow(const ZHeapIteratorContext& context, oop obj) { 474 if (should_visit_object_at_follow()) { 475 context.visit_object(obj); 476 } 477 478 follow<VisitWeaks>(context, obj); 479 } 480 481 template <bool VisitWeaks> 482 void ZHeapIterator::drain(const ZHeapIteratorContext& context) { 483 ObjArrayTask array; 484 oop obj; 485 486 do { 487 while (context.pop(obj)) { 488 visit_and_follow<VisitWeaks>(context, obj); 489 } 490 491 if (context.pop_array_chunk(array)) { 492 follow_array_chunk(context, array); 493 } 494 } while (!context.is_drained()); 495 } 496 497 template <bool VisitWeaks> 498 void ZHeapIterator::steal(const ZHeapIteratorContext& context) { 499 ObjArrayTask array; 500 oop obj; 501 502 if (steal_array_chunk(context, array)) { 503 follow_array_chunk(context, array); 504 } else if (steal(context, obj)) { 505 visit_and_follow<VisitWeaks>(context, obj); 506 } 507 } 508 509 bool ZHeapIterator::steal(const ZHeapIteratorContext& context, oop& obj) { 510 return _queues.steal(context.worker_id(), obj); 511 } 512 513 bool ZHeapIterator::steal_array_chunk(const ZHeapIteratorContext& context, ObjArrayTask& array) { 514 return _array_chunk_queues.steal(context.worker_id(), array); 515 } 516 517 template <bool VisitWeaks> 518 void ZHeapIterator::drain_and_steal(const ZHeapIteratorContext& context) { 519 do { 520 drain<VisitWeaks>(context); 521 steal<VisitWeaks>(context); 522 } while (!context.is_drained() || !_terminator.offer_termination()); 523 } 524 525 template <bool VisitWeaks> 526 void ZHeapIterator::object_iterate_inner(const ZHeapIteratorContext& context) { 527 push_roots<VisitWeaks>(context); 528 drain_and_steal<VisitWeaks>(context); 529 } 530 531 void ZHeapIterator::object_iterate(ObjectClosure* object_cl, uint worker_id) { 532 object_and_field_iterate(object_cl, nullptr /* field_cl */, worker_id); 533 } 534 535 void ZHeapIterator::object_and_field_iterate(ObjectClosure* object_cl, OopFieldClosure* field_cl, uint worker_id) { 536 const ZHeapIteratorContext context(object_cl, 537 field_cl, 538 worker_id, 539 _queues.queue(worker_id), 540 _array_chunk_queues.queue(worker_id)); 541 542 if (_visit_weaks) { 543 object_iterate_inner<true /* VisitWeaks */>(context); 544 } else { 545 object_iterate_inner<false /* VisitWeaks */>(context); 546 } 547 }