< prev index next >

src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp

Print this page
*** 1,7 ***
  /*
!  * Copyright (c) 2018, 2020, Red Hat, Inc. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.
--- 1,7 ---
  /*
!  * Copyright (c) 2018, 2025, Red Hat, Inc. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.

*** 27,11 ***
--- 27,14 ---
  #include "gc/shenandoah/shenandoahForwarding.hpp"
  #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  #include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp"
  #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
  #include "gc/shenandoah/shenandoahUtils.hpp"
+ #include "oops/oop.inline.hpp"
  #include "memory/resourceArea.hpp"
+ #include "runtime/os.hpp"
+ #include "utilities/vmError.hpp"
  
  void print_raw_memory(ShenandoahMessageBuffer &msg, void* loc) {
    // Be extra safe. Only access data that is guaranteed to be safe:
    // should be in heap, in known committed region, within that region.
  

*** 55,28 ***
    ShenandoahHeap* heap = ShenandoahHeap::heap();
    ShenandoahHeapRegion *r = heap->heap_region_containing(obj);
  
    ResourceMark rm;
    stringStream ss;
!   r->print_on(&ss);
- 
-   stringStream mw_ss;
-   obj->mark().print_on(&mw_ss);
  
    ShenandoahMarkingContext* const ctx = heap->marking_context();
  
!   msg.append("  " PTR_FORMAT " - klass " PTR_FORMAT " %s\n", p2i(obj), p2i(obj->klass()), obj->klass()->external_name());
!   msg.append("    %3s allocated after mark start\n", ctx->allocated_after_mark_start(obj) ? "" : "not");
!   msg.append("    %3s after update watermark\n",     cast_from_oop<HeapWord*>(obj) >= r->get_update_watermark() ? "" : "not");
!   msg.append("    %3s marked strong\n",              ctx->is_marked_strong(obj) ? "" : "not");
!   msg.append("    %3s marked weak\n",                ctx->is_marked_weak(obj) ? "" : "not");
!   msg.append("    %3s in collection set\n",          heap->in_collection_set(obj) ? "" : "not");
!   if (heap->mode()->is_generational() && !obj->is_forwarded()) {
!     msg.append("  age: %d\n", obj->age());
!   }
!   msg.append("  mark:%s\n", mw_ss.freeze());
!   msg.append("  region: %s", ss.freeze());
  }
  
  void ShenandoahAsserts::print_non_obj(ShenandoahMessageBuffer& msg, void* loc) {
    ShenandoahHeap* heap = ShenandoahHeap::heap();
    if (heap->is_in_reserved(loc)) {
--- 58,46 ---
    ShenandoahHeap* heap = ShenandoahHeap::heap();
    ShenandoahHeapRegion *r = heap->heap_region_containing(obj);
  
    ResourceMark rm;
    stringStream ss;
!   StreamIndentor si(&ss);
  
    ShenandoahMarkingContext* const ctx = heap->marking_context();
  
!   narrowKlass nk = 0;
!   const Klass* obj_klass = nullptr;
!   const bool klass_valid = extract_klass_safely(obj, nk, obj_klass);
!   const char* klass_text = "(invalid)";
!   if (klass_valid && os::is_readable_pointer(obj_klass) && Metaspace::contains(obj_klass)) {
!     klass_text = obj_klass->external_name();
!   }
!   ss.print_cr(PTR_FORMAT " - nk %u klass " PTR_FORMAT " %s\n", p2i(obj), nk, p2i(obj_klass), klass_text);
!   {
!     StreamIndentor si(&ss);
!     ss.print_cr("%3s allocated after mark start", ctx->allocated_after_mark_start(obj) ? "" : "not");
+     ss.print_cr("%3s after update watermark",     cast_from_oop<HeapWord*>(obj) >= r->get_update_watermark() ? "" : "not");
+     ss.print_cr("%3s marked strong",              ctx->is_marked_strong(obj) ? "" : "not");
+     ss.print_cr("%3s marked weak",                ctx->is_marked_weak(obj) ? "" : "not");
+     ss.print_cr("%3s in collection set",          heap->in_collection_set(obj) ? "" : "not");
+     if (heap->mode()->is_generational() && !obj->is_forwarded()) {
+       ss.print_cr("age: %d", obj->age());
+     }
+     ss.print_raw("mark: ");
+     obj->mark().print_on(&ss);
+     ss.cr();
+     ss.print_raw("region: ");
+     r->print_on(&ss);
+     ss.cr();
+     if (obj_klass == vmClasses::Class_klass()) {
+       msg.append("  mirrored klass:       " PTR_FORMAT "\n", p2i(obj->metadata_field(java_lang_Class::klass_offset())));
+       msg.append("  mirrored array klass: " PTR_FORMAT "\n", p2i(obj->metadata_field(java_lang_Class::array_klass_offset())));
+     }
+   }
+   const_address loc = cast_from_oop<const_address>(obj);
+   os::print_hex_dump(&ss, loc, loc + 64, 4, true, 32, loc);
+   msg.append("%s", ss.base());
  }
  
  void ShenandoahAsserts::print_non_obj(ShenandoahMessageBuffer& msg, void* loc) {
    ShenandoahHeap* heap = ShenandoahHeap::heap();
    if (heap->is_in_reserved(loc)) {

*** 113,18 ***
                                         const char* phase, const char* label,
                                         const char* file, int line) {
    ShenandoahHeap* heap = ShenandoahHeap::heap();
    ResourceMark rm;
  
    bool loc_in_heap = (loc != nullptr && heap->is_in_reserved(loc));
  
    ShenandoahMessageBuffer msg("%s; %s\n\n", phase, label);
  
    msg.append("Referenced from:\n");
    if (interior_loc != nullptr) {
      msg.append("  interior location: " PTR_FORMAT "\n", p2i(interior_loc));
!     if (loc_in_heap) {
        print_obj(msg, loc);
      } else {
        print_non_obj(msg, interior_loc);
      }
    } else {
--- 134,22 ---
                                         const char* phase, const char* label,
                                         const char* file, int line) {
    ShenandoahHeap* heap = ShenandoahHeap::heap();
    ResourceMark rm;
  
+   if (!os::is_readable_pointer(obj)) {
+     level = _safe_unknown;
+   }
+ 
    bool loc_in_heap = (loc != nullptr && heap->is_in_reserved(loc));
  
    ShenandoahMessageBuffer msg("%s; %s\n\n", phase, label);
  
    msg.append("Referenced from:\n");
    if (interior_loc != nullptr) {
      msg.append("  interior location: " PTR_FORMAT "\n", p2i(interior_loc));
!     if (loc_in_heap && os::is_readable_pointer(loc)) {
        print_obj(msg, loc);
      } else {
        print_non_obj(msg, interior_loc);
      }
    } else {

*** 142,11 ***
  
    if (level >= _safe_oop) {
      oop fwd = ShenandoahForwarding::get_forwardee_raw_unchecked(obj);
      msg.append("Forwardee:\n");
      if (obj != fwd) {
!       if (level >= _safe_oop_fwd) {
          print_obj(msg, fwd);
        } else {
          print_obj_safe(msg, fwd);
        }
      } else {
--- 167,11 ---
  
    if (level >= _safe_oop) {
      oop fwd = ShenandoahForwarding::get_forwardee_raw_unchecked(obj);
      msg.append("Forwardee:\n");
      if (obj != fwd) {
!       if (level >= _safe_oop_fwd && os::is_readable_pointer(fwd)) {
          print_obj(msg, fwd);
        } else {
          print_obj_safe(msg, fwd);
        }
      } else {

*** 197,21 ***
      print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
                    "oop must be in heap bounds",
                    file, line);
    }
  
!   Klass* obj_klass = ShenandoahForwarding::klass(obj);
-   if (obj_klass == nullptr) {
      print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
!                   "Object klass pointer should not be null",
!                   file,line);
-   }
- 
-   if (!Metaspace::contains(obj_klass)) {
-     print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
-                   "Object klass pointer must go to metaspace",
-                   file,line);
    }
  
    if (!heap->is_in(obj)) {
      print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
                    "Object should be in active region area",
--- 222,14 ---
      print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
                    "oop must be in heap bounds",
                    file, line);
    }
  
!   if (!os::is_readable_pointer(obj)) {
      print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
!                   "oop within heap bounds but at unreadable location",
!                   file, line);
    }
  
    if (!heap->is_in(obj)) {
      print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
                    "Object should be in active region area",

*** 235,13 ***
        print_failure(_safe_oop, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
                      "Forwardee must be in heap bounds",
                      file, line);
      }
  
!     if (obj_klass != ShenandoahForwarding::klass(fwd)) {
        print_failure(_safe_oop, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
!                     "Forwardee klass disagrees with object class",
                      file, line);
      }
  
      // Step 3. Check that forwardee points to correct region
      if (!heap->is_in(fwd)) {
--- 253,13 ---
        print_failure(_safe_oop, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
                      "Forwardee must be in heap bounds",
                      file, line);
      }
  
!     if (!os::is_readable_pointer(fwd)) {
        print_failure(_safe_oop, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
!                     "Forwardee within heap bounds but at unreadable location",
                      file, line);
      }
  
      // Step 3. Check that forwardee points to correct region
      if (!heap->is_in(fwd)) {

*** 263,25 ***
                      "Multiple forwardings",
                      file, line);
      }
    }
  
    // Do additional checks for special objects: their fields can hold metadata as well.
!   // We want to check class loading/unloading did not corrupt them.
  
    if (Universe::is_fully_initialized() && (obj_klass == vmClasses::Class_klass())) {
!     Metadata* klass = obj->metadata_field(java_lang_Class::klass_offset());
      if (klass != nullptr && !Metaspace::contains(klass)) {
        print_failure(_safe_all, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
!                     "Instance class mirror should point to Metaspace",
                      file, line);
      }
  
!     Metadata* array_klass = obj->metadata_field(java_lang_Class::array_klass_offset());
      if (array_klass != nullptr && !Metaspace::contains(array_klass)) {
        print_failure(_safe_all, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
!                     "Array class mirror should point to Metaspace",
                      file, line);
      }
    }
  }
  
--- 281,53 ---
                      "Multiple forwardings",
                      file, line);
      }
    }
  
+   const Klass* obj_klass = nullptr;
+   narrowKlass nk = 0;
+   if (!extract_klass_safely(obj, nk, obj_klass)) {
+     print_failure(_safe_oop, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
+                   "Object klass pointer invalid",
+                   file,line);
+   }
+ 
+   if (obj_klass == nullptr) {
+     print_failure(_safe_oop, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
+                   "Object klass pointer should not be null",
+                   file,line);
+   }
+ 
+   if (!Metaspace::contains(obj_klass)) {
+     print_failure(_safe_oop, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
+                   "Object klass pointer must go to metaspace",
+                   file,line);
+   }
+ 
+   if (!UseCompactObjectHeaders && obj_klass != fwd->klass_or_null()) {
+     print_failure(_safe_oop, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
+                   "Forwardee klass disagrees with object class",
+                   file, line);
+   }
+ 
    // Do additional checks for special objects: their fields can hold metadata as well.
!   // We want to check class loading/unloading did not corrupt them. We can only reasonably
+   // trust the forwarded objects, as the from-space object can have the klasses effectively
+   // dead.
  
    if (Universe::is_fully_initialized() && (obj_klass == vmClasses::Class_klass())) {
!     const Metadata* klass = fwd->metadata_field(java_lang_Class::klass_offset());
      if (klass != nullptr && !Metaspace::contains(klass)) {
        print_failure(_safe_all, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
!                     "Mirrored instance class should point to Metaspace",
                      file, line);
      }
  
!     const Metadata* array_klass = fwd->metadata_field(java_lang_Class::array_klass_offset());
      if (array_klass != nullptr && !Metaspace::contains(array_klass)) {
        print_failure(_safe_all, obj, interior_loc, nullptr, "Shenandoah assert_correct failed",
!                     "Mirrored array class should point to Metaspace",
                      file, line);
      }
    }
  }
  

*** 509,5 ***
--- 555,36 ---
    }
  
    ShenandoahMessageBuffer msg("Active(%d) & GC(%d) Generations aren't reconciled", agen->type(), ggen->type());
    report_vm_error(file, line, msg.buffer());
  }
+ 
+ bool ShenandoahAsserts::extract_klass_safely(oop obj, narrowKlass& nk, const Klass*& k) {
+   nk = 0;
+   k = nullptr;
+ 
+   if (!os::is_readable_pointer(obj)) {
+     return false;
+   }
+   if (UseCompressedClassPointers) {
+     if (UseCompactObjectHeaders) { // look in forwardee
+       markWord mark = obj->mark();
+       if (mark.is_marked()) {
+         oop fwd = cast_to_oop(mark.clear_lock_bits().to_pointer());
+         if (!os::is_readable_pointer(fwd)) {
+           return false;
+         }
+         mark = fwd->mark();
+       }
+       nk = mark.narrow_klass();
+     } else {
+       nk = obj->narrow_klass();
+     }
+     if (!CompressedKlassPointers::is_valid_narrow_klass_id(nk)) {
+       return false;
+     }
+     k = CompressedKlassPointers::decode_not_null_without_asserts(nk);
+   } else {
+     k = obj->klass();
+   }
+   return k != nullptr;
+ }
< prev index next >