1 /*
   2  * Copyright (c) 2018, 2019, Red Hat, Inc. 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 
  25 #include "precompiled.hpp"
  26 
  27 #include "gc/shenandoah/shenandoahAsserts.hpp"
  28 #include "gc/shenandoah/shenandoahForwarding.hpp"
  29 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  30 #include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp"
  31 #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
  32 #include "gc/shenandoah/shenandoahTraversalGC.hpp"
  33 #include "gc/shenandoah/shenandoahUtils.hpp"
  34 #include "memory/resourceArea.hpp"
  35 
  36 void print_raw_memory(ShenandoahMessageBuffer &msg, void* loc) {
  37   // Be extra safe. Only access data that is guaranteed to be safe:
  38   // should be in heap, in known committed region, within that region.
  39 
  40   ShenandoahHeap* heap = ShenandoahHeap::heap();
  41   if (!heap->is_in(loc)) return;
  42 
  43   ShenandoahHeapRegion* r = heap->heap_region_containing(loc);
  44   if (r != NULL && r->is_committed()) {
  45     address start = MAX2((address) r->bottom(), (address) loc - 32);
  46     address end   = MIN2((address) r->end(),    (address) loc + 128);
  47     if (start >= end) return;
  48 
  49     stringStream ss;
  50     os::print_hex_dump(&ss, start, end, 4);
  51     msg.append("\n");
  52     msg.append("Raw heap memory:\n%s", ss.as_string());
  53   }
  54 }
  55 
  56 void ShenandoahAsserts::print_obj(ShenandoahMessageBuffer& msg, oop obj) {
  57   ShenandoahHeap* heap = ShenandoahHeap::heap();
  58   ShenandoahHeapRegion *r = heap->heap_region_containing(obj);
  59 
  60   ResourceMark rm;
  61   stringStream ss;
  62   r->print_on(&ss);
  63 
  64   stringStream mw_ss;
  65   obj->mark().print_on(&mw_ss);
  66 
  67   ShenandoahMarkingContext* const ctx = heap->marking_context();
  68 
  69   msg.append("  " PTR_FORMAT " - klass " PTR_FORMAT " %s\n", p2i(obj), p2i(obj->klass()), obj->klass()->external_name());
  70   msg.append("    %3s allocated after mark start\n", ctx->allocated_after_mark_start((HeapWord *) obj) ? "" : "not");
  71   msg.append("    %3s marked \n",                    ctx->is_marked(obj) ? "" : "not");
  72   msg.append("    %3s in collection set\n",          heap->in_collection_set(obj) ? "" : "not");
  73   if (heap->traversal_gc() != NULL) {
  74     msg.append("    %3s in traversal set\n",         heap->traversal_gc()->traversal_set()->is_in((HeapWord*) obj) ? "" : "not");
  75   }
  76   msg.append("  mark:%s\n", mw_ss.as_string());
  77   msg.append("  region: %s", ss.as_string());
  78 }
  79 
  80 void ShenandoahAsserts::print_non_obj(ShenandoahMessageBuffer& msg, void* loc) {
  81   ShenandoahHeap* heap = ShenandoahHeap::heap();
  82   if (heap->is_in(loc)) {
  83     msg.append("  inside Java heap\n");
  84     ShenandoahHeapRegion *r = heap->heap_region_containing(loc);
  85     stringStream ss;
  86     r->print_on(&ss);
  87 
  88     msg.append("    %3s in collection set\n",    heap->in_collection_set(loc) ? "" : "not");
  89     msg.append("  region: %s", ss.as_string());
  90   } else {
  91     msg.append("  outside of Java heap\n");
  92     stringStream ss;
  93     os::print_location(&ss, (intptr_t) loc, false);
  94     msg.append("  %s", ss.as_string());
  95   }
  96 }
  97 
  98 void ShenandoahAsserts::print_obj_safe(ShenandoahMessageBuffer& msg, void* loc) {
  99   ShenandoahHeap* heap = ShenandoahHeap::heap();
 100   msg.append("  " PTR_FORMAT " - safe print, no details\n", p2i(loc));
 101   if (heap->is_in(loc)) {
 102     ShenandoahHeapRegion* r = heap->heap_region_containing(loc);
 103     if (r != NULL) {
 104       stringStream ss;
 105       r->print_on(&ss);
 106       msg.append("  region: %s", ss.as_string());
 107       print_raw_memory(msg, loc);
 108     }
 109   }
 110 }
 111 
 112 void ShenandoahAsserts::print_failure(SafeLevel level, oop obj, void* interior_loc, oop loc,
 113                                        const char* phase, const char* label,
 114                                        const char* file, int line) {
 115   ShenandoahHeap* heap = ShenandoahHeap::heap();
 116   ResourceMark rm;
 117 
 118   bool loc_in_heap = (loc != NULL && heap->is_in(loc));
 119 
 120   ShenandoahMessageBuffer msg("%s; %s\n\n", phase, label);
 121 
 122   msg.append("Referenced from:\n");
 123   if (interior_loc != NULL) {
 124     msg.append("  interior location: " PTR_FORMAT "\n", p2i(interior_loc));
 125     if (loc_in_heap) {
 126       print_obj(msg, loc);
 127     } else {
 128       print_non_obj(msg, interior_loc);
 129     }
 130   } else {
 131     msg.append("  no interior location recorded (probably a plain heap scan, or detached oop)\n");
 132   }
 133   msg.append("\n");
 134 
 135   msg.append("Object:\n");
 136   if (level >= _safe_oop) {
 137     print_obj(msg, obj);
 138   } else {
 139     print_obj_safe(msg, obj);
 140   }
 141   msg.append("\n");
 142 
 143   if (level >= _safe_oop) {
 144     oop fwd = (oop) ShenandoahForwarding::get_forwardee_raw_unchecked(obj);
 145     msg.append("Forwardee:\n");
 146     if (obj != fwd) {
 147       if (level >= _safe_oop_fwd) {
 148         print_obj(msg, fwd);
 149       } else {
 150         print_obj_safe(msg, fwd);
 151       }
 152     } else {
 153       msg.append("  (the object itself)");
 154     }
 155     msg.append("\n");
 156   }
 157 
 158   if (level >= _safe_oop_fwd) {
 159     oop fwd = (oop) ShenandoahForwarding::get_forwardee_raw_unchecked(obj);
 160     oop fwd2 = (oop) ShenandoahForwarding::get_forwardee_raw_unchecked(fwd);
 161     if (fwd != fwd2) {
 162       msg.append("Second forwardee:\n");
 163       print_obj_safe(msg, fwd2);
 164       msg.append("\n");
 165     }
 166   }
 167 
 168   report_vm_error(file, line, msg.buffer());
 169 }
 170 
 171 void ShenandoahAsserts::assert_in_heap(void* interior_loc, oop obj, const char *file, int line) {
 172   ShenandoahHeap* heap = ShenandoahHeap::heap_no_check();
 173 
 174   if (!heap->is_in(obj)) {
 175     print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_in_heap failed",
 176                   "oop must point to a heap address",
 177                   file, line);
 178   }
 179 }
 180 
 181 void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* file, int line) {
 182   ShenandoahHeap* heap = ShenandoahHeap::heap_no_check();
 183 
 184   // Step 1. Check that obj is correct.
 185   // After this step, it is safe to call heap_region_containing().
 186   if (!heap->is_in(obj)) {
 187     print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_correct failed",
 188                   "oop must point to a heap address",
 189                   file, line);
 190   }
 191 
 192   Klass* obj_klass = obj->klass_or_null();
 193   if (obj_klass == NULL) {
 194     print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_correct failed",
 195                   "Object klass pointer should not be NULL",
 196                   file,line);
 197   }
 198 
 199   if (!Metaspace::contains(obj_klass)) {
 200     print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_correct failed",
 201                   "Object klass pointer must go to metaspace",
 202                   file,line);
 203   }
 204 
 205   oop fwd = oop(ShenandoahForwarding::get_forwardee_raw_unchecked(obj));
 206 
 207   if (obj != fwd) {
 208     // When Full GC moves the objects, we cannot trust fwdptrs. If we got here, it means something
 209     // tries fwdptr manipulation when Full GC is running. The only exception is using the fwdptr
 210     // that still points to the object itself.
 211     if (heap->is_full_gc_move_in_progress()) {
 212       print_failure(_safe_oop, obj, interior_loc, NULL, "Shenandoah assert_correct failed",
 213                     "Non-trivial forwarding pointer during Full GC moves, probable bug.",
 214                     file, line);
 215     }
 216 
 217     // Step 2. Check that forwardee is correct
 218     if (!heap->is_in(fwd)) {
 219       print_failure(_safe_oop, obj, interior_loc, NULL, "Shenandoah assert_correct failed",
 220                     "Forwardee must point to a heap address",
 221                     file, line);
 222     }
 223 
 224     if (obj_klass != fwd->klass()) {
 225       print_failure(_safe_oop, obj, interior_loc, NULL, "Shenandoah assert_correct failed",
 226                     "Forwardee klass disagrees with object class",
 227                     file, line);
 228     }
 229 
 230     // Step 3. Check that forwardee points to correct region
 231     if (heap->heap_region_index_containing(fwd) == heap->heap_region_index_containing(obj)) {
 232       print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_correct failed",
 233                     "Non-trivial forwardee should in another region",
 234                     file, line);
 235     }
 236 
 237     // Step 4. Check for multiple forwardings
 238     oop fwd2 = oop(ShenandoahForwarding::get_forwardee_raw_unchecked(fwd));
 239     if (fwd != fwd2) {
 240       print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_correct failed",
 241                     "Multiple forwardings",
 242                     file, line);
 243     }
 244   }
 245 }
 246 
 247 void ShenandoahAsserts::assert_in_correct_region(void* interior_loc, oop obj, const char* file, int line) {
 248   assert_correct(interior_loc, obj, file, line);
 249 
 250   ShenandoahHeap* heap = ShenandoahHeap::heap_no_check();
 251   ShenandoahHeapRegion* r = heap->heap_region_containing(obj);
 252   if (!r->is_active()) {
 253     print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_in_correct_region failed",
 254                   "Object must reside in active region",
 255                   file, line);
 256   }
 257 
 258   size_t alloc_size = obj->size();
 259   if (alloc_size > ShenandoahHeapRegion::humongous_threshold_words()) {
 260     size_t idx = r->region_number();
 261     size_t num_regions = ShenandoahHeapRegion::required_regions(alloc_size * HeapWordSize);
 262     for (size_t i = idx; i < idx + num_regions; i++) {
 263       ShenandoahHeapRegion* chain_reg = heap->get_region(i);
 264       if (i == idx && !chain_reg->is_humongous_start()) {
 265         print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_in_correct_region failed",
 266                       "Object must reside in humongous start",
 267                       file, line);
 268       }
 269       if (i != idx && !chain_reg->is_humongous_continuation()) {
 270         print_failure(_safe_oop, obj, interior_loc, NULL, "Shenandoah assert_in_correct_region failed",
 271                       "Humongous continuation should be of proper size",
 272                       file, line);
 273       }
 274     }
 275   }
 276 }
 277 
 278 void ShenandoahAsserts::assert_forwarded(void* interior_loc, oop obj, const char* file, int line) {
 279   assert_correct(interior_loc, obj, file, line);
 280   oop fwd = oop(ShenandoahForwarding::get_forwardee_raw_unchecked(obj));
 281 
 282   if (obj == fwd) {
 283     print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_forwarded failed",
 284                   "Object should be forwarded",
 285                   file, line);
 286   }
 287 }
 288 
 289 void ShenandoahAsserts::assert_not_forwarded(void* interior_loc, oop obj, const char* file, int line) {
 290   assert_correct(interior_loc, obj, file, line);
 291   oop fwd = oop(ShenandoahForwarding::get_forwardee_raw_unchecked(obj));
 292 
 293   if (obj != fwd) {
 294     print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_not_forwarded failed",
 295                   "Object should not be forwarded",
 296                   file, line);
 297   }
 298 }
 299 
 300 void ShenandoahAsserts::assert_marked(void *interior_loc, oop obj, const char *file, int line) {
 301   assert_correct(interior_loc, obj, file, line);
 302 
 303   ShenandoahHeap* heap = ShenandoahHeap::heap_no_check();
 304   if (!heap->marking_context()->is_marked(obj)) {
 305     print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_marked failed",
 306                   "Object should be marked",
 307                   file, line);
 308   }
 309 }
 310 
 311 void ShenandoahAsserts::assert_in_cset(void* interior_loc, oop obj, const char* file, int line) {
 312   assert_correct(interior_loc, obj, file, line);
 313 
 314   ShenandoahHeap* heap = ShenandoahHeap::heap_no_check();
 315   if (!heap->in_collection_set(obj)) {
 316     print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_in_cset failed",
 317                   "Object should be in collection set",
 318                   file, line);
 319   }
 320 }
 321 
 322 void ShenandoahAsserts::assert_not_in_cset(void* interior_loc, oop obj, const char* file, int line) {
 323   assert_correct(interior_loc, obj, file, line);
 324 
 325   ShenandoahHeap* heap = ShenandoahHeap::heap_no_check();
 326   if (heap->in_collection_set(obj)) {
 327     print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_not_in_cset failed",
 328                   "Object should not be in collection set",
 329                   file, line);
 330   }
 331 }
 332 
 333 void ShenandoahAsserts::assert_not_in_cset_loc(void* interior_loc, const char* file, int line) {
 334   ShenandoahHeap* heap = ShenandoahHeap::heap_no_check();
 335   if (heap->in_collection_set(interior_loc)) {
 336     print_failure(_safe_unknown, NULL, interior_loc, NULL, "Shenandoah assert_not_in_cset_loc failed",
 337                   "Interior location should not be in collection set",
 338                   file, line);
 339   }
 340 }
 341 
 342 void ShenandoahAsserts::print_rp_failure(const char *label, BoolObjectClosure* actual,
 343                                          const char *file, int line) {
 344   ShenandoahMessageBuffer msg("%s\n", label);
 345   msg.append(" Actual:                  " PTR_FORMAT "\n", p2i(actual));
 346   report_vm_error(file, line, msg.buffer());
 347 }
 348 
 349 void ShenandoahAsserts::assert_rp_isalive_not_installed(const char *file, int line) {
 350   ShenandoahHeap* heap = ShenandoahHeap::heap();
 351   ReferenceProcessor* rp = heap->ref_processor();
 352   if (rp->is_alive_non_header() != NULL) {
 353     print_rp_failure("Shenandoah assert_rp_isalive_not_installed failed", rp->is_alive_non_header(),
 354                      file, line);
 355   }
 356 }
 357 
 358 void ShenandoahAsserts::assert_rp_isalive_installed(const char *file, int line) {
 359   ShenandoahHeap* heap = ShenandoahHeap::heap();
 360   ReferenceProcessor* rp = heap->ref_processor();
 361   if (rp->is_alive_non_header() == NULL) {
 362     print_rp_failure("Shenandoah assert_rp_isalive_installed failed", rp->is_alive_non_header(),
 363                      file, line);
 364   }
 365 }
 366 
 367 void ShenandoahAsserts::assert_locked_or_shenandoah_safepoint(Mutex* lock, const char* file, int line) {
 368   if (ShenandoahSafepoint::is_at_shenandoah_safepoint()) {
 369     return;
 370   }
 371 
 372   if (lock->owned_by_self()) {
 373     return;
 374   }
 375 
 376   ShenandoahMessageBuffer msg("Must ba at a Shenandoah safepoint or held %s lock", lock->name());
 377   report_vm_error(file, line, msg.buffer());
 378 }