1 /* 2 * Copyright (c) 2018, Red Hat, Inc. and/or its affiliates. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 * 22 */ 23 24 #include "precompiled.hpp" 25 26 #include "gc/shenandoah/brooksPointer.hpp" 27 #include "gc/shenandoah/shenandoahConnectionMatrix.hpp" 28 #include "gc/shenandoah/shenandoahAsserts.hpp" 29 #include "gc/shenandoah/shenandoahHeap.hpp" 30 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 31 #include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp" 32 #include "gc/shenandoah/shenandoahTraversalGC.hpp" 33 #include "memory/resourceArea.hpp" 34 35 void ShenandoahAsserts::print_obj(ShenandoahMessageBuffer& msg, oop obj) { 36 ShenandoahHeap* heap = ShenandoahHeap::heap(); 37 ShenandoahHeapRegion *r = heap->heap_region_containing(obj); 38 39 ResourceMark rm; 40 stringStream ss; 41 r->print_on(&ss); 42 43 msg.append(" " PTR_FORMAT " - klass " PTR_FORMAT " %s\n", p2i(obj), p2i(obj->klass()), obj->klass()->external_name()); 44 msg.append(" %3s allocated after complete mark start\n", heap->allocated_after_complete_mark_start((HeapWord *) obj) ? "" : "not"); 45 msg.append(" %3s allocated after next mark start\n", heap->allocated_after_next_mark_start((HeapWord *) obj) ? "" : "not"); 46 msg.append(" %3s marked complete\n", heap->is_marked_complete(obj) ? "" : "not"); 47 msg.append(" %3s marked next\n", heap->is_marked_next(obj) ? "" : "not"); 48 msg.append(" %3s in collection set\n", heap->in_collection_set(obj) ? "" : "not"); 49 if (heap->traversal_gc() != NULL) { 50 msg.append(" %3s in root set\n", heap->traversal_gc()->root_regions()->is_in((HeapWord*) obj) ? "" : "not"); 51 msg.append(" %3s in traversal set\n", heap->traversal_gc()->traversal_set()->is_in((HeapWord*) obj) ? "" : "not"); 52 } 53 msg.append(" region: %s", ss.as_string()); 54 } 55 56 void ShenandoahAsserts::print_non_obj(ShenandoahMessageBuffer& msg, void* loc) { 57 ShenandoahHeap* heap = ShenandoahHeap::heap(); 58 if (heap->is_in(loc)) { 59 msg.append(" inside Java heap\n"); 60 ShenandoahHeapRegion *r = heap->heap_region_containing(loc); 61 stringStream ss; 62 r->print_on(&ss); 63 64 msg.append(" %3s in collection set\n", heap->in_collection_set(loc) ? "" : "not"); 65 msg.append(" region: %s", ss.as_string()); 66 } else { 67 msg.append(" outside of Java heap\n"); 68 stringStream ss; 69 os::print_location(&ss, (intptr_t) loc, false); 70 msg.append(" %s", ss.as_string()); 71 } 72 } 73 74 void ShenandoahAsserts::print_obj_safe(ShenandoahMessageBuffer& msg, void* loc) { 75 ShenandoahHeap* heap = ShenandoahHeap::heap(); 76 msg.append(" " PTR_FORMAT " - safe print, no details\n", p2i(loc)); 77 if (heap->is_in(loc)) { 78 ShenandoahHeapRegion* r = heap->heap_region_containing(loc); 79 if (r != NULL) { 80 stringStream ss; 81 r->print_on(&ss); 82 msg.append(" region: %s", ss.as_string()); 83 } 84 } 85 } 86 87 void ShenandoahAsserts::print_failure(SafeLevel level, oop obj, void* interior_loc, oop loc, 88 const char* phase, const char* label, 89 const char* file, int line) { 90 ShenandoahHeap* heap = ShenandoahHeap::heap(); 91 ResourceMark rm; 92 93 bool loc_in_heap = (loc != NULL && heap->is_in(loc)); 94 bool interior_loc_in_heap = (interior_loc != NULL && heap->is_in(interior_loc)); 95 96 ShenandoahMessageBuffer msg("%s; %s\n\n", phase, label); 97 98 msg.append("Referenced from:\n"); 99 if (interior_loc != NULL) { 100 msg.append(" interior location: " PTR_FORMAT "\n", p2i(interior_loc)); 101 if (loc_in_heap) { 102 print_obj(msg, loc); 103 } else { 104 print_non_obj(msg, interior_loc); 105 } 106 } else { 107 msg.append(" no interior location recorded (probably a plain heap scan, or detached oop)\n"); 108 } 109 msg.append("\n"); 110 111 msg.append("Object:\n"); 112 if (level >= _safe_oop) { 113 print_obj(msg, obj); 114 } else { 115 print_obj_safe(msg, obj); 116 } 117 msg.append("\n"); 118 119 if (level >= _safe_oop) { 120 oop fwd = (oop) BrooksPointer::get_raw_unchecked(obj); 121 msg.append("Forwardee:\n"); 122 if (!oopDesc::unsafe_equals(obj, fwd)) { 123 if (level >= _safe_oop_fwd) { 124 print_obj(msg, fwd); 125 } else { 126 print_obj_safe(msg, fwd); 127 } 128 } else { 129 msg.append(" (the object itself)"); 130 } 131 msg.append("\n"); 132 } 133 134 if (level >= _safe_oop_fwd) { 135 oop fwd = (oop) BrooksPointer::get_raw_unchecked(obj); 136 oop fwd2 = (oop) BrooksPointer::get_raw_unchecked(fwd); 137 if (!oopDesc::unsafe_equals(fwd, fwd2)) { 138 msg.append("Second forwardee:\n"); 139 print_obj_safe(msg, fwd2); 140 msg.append("\n"); 141 } 142 } 143 144 if (loc_in_heap && UseShenandoahMatrix && (level == _safe_all)) { 145 msg.append("Matrix connections:\n"); 146 147 oop fwd_to = (oop) BrooksPointer::get_raw_unchecked(obj); 148 oop fwd_from = (oop) BrooksPointer::get_raw_unchecked(loc); 149 150 size_t from_idx = heap->heap_region_index_containing(loc); 151 size_t to_idx = heap->heap_region_index_containing(obj); 152 size_t fwd_from_idx = heap->heap_region_index_containing(fwd_from); 153 size_t fwd_to_idx = heap->heap_region_index_containing(fwd_to); 154 155 ShenandoahConnectionMatrix* matrix = heap->connection_matrix(); 156 msg.append(" %35s %3s connected\n", 157 "reference and object", 158 matrix->is_connected(from_idx, to_idx) ? "" : "not"); 159 msg.append(" %35s %3s connected\n", 160 "fwd(reference) and object", 161 matrix->is_connected(fwd_from_idx, to_idx) ? "" : "not"); 162 msg.append(" %35s %3s connected\n", 163 "reference and fwd(object)", 164 matrix->is_connected(from_idx, fwd_to_idx) ? "" : "not"); 165 msg.append(" %35s %3s connected\n", 166 "fwd(reference) and fwd(object)", 167 matrix->is_connected(fwd_from_idx, fwd_to_idx) ? "" : "not"); 168 169 if (interior_loc_in_heap) { 170 size_t from_interior_idx = heap->heap_region_index_containing(interior_loc); 171 msg.append(" %35s %3s connected\n", 172 "interior-reference and object", 173 matrix->is_connected(from_interior_idx, to_idx) ? "" : "not"); 174 msg.append(" %35s %3s connected\n", 175 "interior-reference and fwd(object)", 176 matrix->is_connected(from_interior_idx, fwd_to_idx) ? "" : "not"); 177 } 178 } 179 180 report_vm_error(file, line, msg.buffer()); 181 } 182 183 void ShenandoahAsserts::assert_in_heap(void* interior_loc, oop obj, const char *file, int line) { 184 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 185 186 if (!heap->is_in(obj)) { 187 print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_in_heap failed", 188 "oop must point to a heap address", 189 file, line); 190 } 191 } 192 193 void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* file, int line) { 194 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 195 196 // Step 1. Check that both obj and its fwdptr are in heap. 197 // After this step, it is safe to call heap_region_containing(). 198 if (!heap->is_in(obj)) { 199 print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_correct failed", 200 "oop must point to a heap address", 201 file, line); 202 } 203 204 oop fwd = oop(BrooksPointer::get_raw_unchecked(obj)); 205 206 if (!heap->is_in(fwd)) { 207 print_failure(_safe_oop, obj, interior_loc, NULL, "Shenandoah assert_correct failed", 208 "Forwardee must point to a heap address", 209 file, line); 210 } 211 212 bool is_forwarded = !oopDesc::unsafe_equals(obj, fwd); 213 214 // When Full GC moves the objects, we cannot trust fwdptrs. If we got here, it means something 215 // tries fwdptr manipulation when Full GC is running. The only exception is using the fwdptr 216 // that still points to the object itself. 217 218 if (is_forwarded && heap->is_full_gc_move_in_progress()) { 219 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_correct failed", 220 "Non-trivial forwarding pointer during Full GC moves, probable bug.", 221 file, line); 222 } 223 224 // Step 2. Check that forwardee points to correct region. 225 if (is_forwarded && 226 (heap->heap_region_index_containing(fwd) == 227 heap->heap_region_index_containing(obj))) { 228 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_correct failed", 229 "Forwardee should be self, or another region", 230 file, line); 231 } 232 233 // Step 3. Check for multiple forwardings 234 if (is_forwarded) { 235 oop fwd2 = oop(BrooksPointer::get_raw_unchecked(fwd)); 236 if (!oopDesc::unsafe_equals(fwd, fwd2)) { 237 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_correct failed", 238 "Multiple forwardings", 239 file, line); 240 } 241 } 242 } 243 244 void ShenandoahAsserts::assert_in_correct_region(void* interior_loc, oop obj, const char* file, int line) { 245 assert_correct(interior_loc, obj, file, line); 246 247 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 248 ShenandoahHeapRegion* r = heap->heap_region_containing(obj); 249 if (!r->is_active()) { 250 print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_in_correct_region failed", 251 "Object must reside in active region", 252 file, line); 253 } 254 255 size_t alloc_size = obj->size() + BrooksPointer::word_size(); 256 if (alloc_size > ShenandoahHeapRegion::humongous_threshold_words()) { 257 size_t idx = r->region_number(); 258 size_t num_regions = ShenandoahHeapRegion::required_regions(alloc_size * HeapWordSize); 259 for (size_t i = idx; i < idx + num_regions; i++) { 260 ShenandoahHeapRegion* chain_reg = heap->get_region(i); 261 if (i == idx && !chain_reg->is_humongous_start()) { 262 print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_in_correct_region failed", 263 "Object must reside in humongous start", 264 file, line); 265 } 266 if (i != idx && !chain_reg->is_humongous_continuation()) { 267 print_failure(_safe_oop, obj, interior_loc, NULL, "Shenandoah assert_in_correct_region failed", 268 "Humongous continuation should be of proper size", 269 file, line); 270 } 271 } 272 } 273 } 274 275 void ShenandoahAsserts::assert_forwarded(void* interior_loc, oop obj, const char* file, int line) { 276 assert_correct(interior_loc, obj, file, line); 277 oop fwd = oop(BrooksPointer::get_raw_unchecked(obj)); 278 279 if (oopDesc::unsafe_equals(obj, fwd)) { 280 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_forwarded failed", 281 "Object should be forwarded", 282 file, line); 283 } 284 } 285 286 void ShenandoahAsserts::assert_not_forwarded(void* interior_loc, oop obj, const char* file, int line) { 287 assert_correct(interior_loc, obj, file, line); 288 oop fwd = oop(BrooksPointer::get_raw_unchecked(obj)); 289 290 if (!oopDesc::unsafe_equals(obj, fwd)) { 291 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_not_forwarded failed", 292 "Object should not be forwarded", 293 file, line); 294 } 295 } 296 297 void ShenandoahAsserts::assert_marked_complete(void* interior_loc, oop obj, const char* file, int line) { 298 assert_correct(interior_loc, obj, file, line); 299 300 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 301 if (!heap->is_marked_complete(obj)) { 302 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_marked_complete failed", 303 "Object should be marked (complete)", 304 file, line); 305 } 306 } 307 308 void ShenandoahAsserts::assert_marked_next(void* interior_loc, oop obj, const char* file, int line) { 309 assert_correct(interior_loc, obj, file, line); 310 311 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 312 if (!heap->is_marked_next(obj)) { 313 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_marked_next failed", 314 "Object should be marked (next)", 315 file, line); 316 } 317 } 318 319 void ShenandoahAsserts::assert_not_in_cset(void* interior_loc, oop obj, const char* file, int line) { 320 assert_correct(interior_loc, obj, file, line); 321 322 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 323 if (heap->in_collection_set(obj)) { 324 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_not_in_cset failed", 325 "Object should not be in collection set", 326 file, line); 327 } 328 } 329 330 void ShenandoahAsserts::assert_not_in_cset_loc(void* interior_loc, const char* file, int line) { 331 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 332 if (heap->in_collection_set(interior_loc)) { 333 print_failure(_safe_unknown, NULL, interior_loc, NULL, "Shenandoah assert_not_in_cset_loc failed", 334 "Interior location should not be in collection set", 335 file, line); 336 } 337 } 338 339 void ShenandoahAsserts::print_rp_failure(const char *label, BoolObjectClosure* actual, BoolObjectClosure* expected, 340 const char *file, int line) { 341 ShenandoahHeap* heap = ShenandoahHeap::heap(); 342 ShenandoahMessageBuffer msg("%s\n", label); 343 msg.append(" Actual: " PTR_FORMAT "\n", p2i(actual)); 344 msg.append(" Expected: " PTR_FORMAT "\n", p2i(expected)); 345 msg.append(" SH->_is_alive: " PTR_FORMAT "\n", p2i(&heap->_is_alive)); 346 msg.append(" SH->_forwarded_is_alive: " PTR_FORMAT "\n", p2i(&heap->_forwarded_is_alive)); 347 report_vm_error(file, line, msg.buffer()); 348 } 349 350 void ShenandoahAsserts::assert_rp_isalive_not_installed(const char *file, int line) { 351 ShenandoahHeap* heap = ShenandoahHeap::heap(); 352 ReferenceProcessor* rp = heap->ref_processor(); 353 if (rp->is_alive_non_header() != NULL) { 354 print_rp_failure("Shenandoah assert_rp_isalive_not_installed failed", rp->is_alive_non_header(), NULL, 355 file, line); 356 } 357 } 358 359 void ShenandoahAsserts::assert_rp_isalive_installed(const char *file, int line) { 360 ShenandoahHeap* heap = ShenandoahHeap::heap(); 361 ReferenceProcessor* rp = heap->ref_processor(); 362 if (rp->is_alive_non_header() != heap->is_alive_closure()) { 363 print_rp_failure("Shenandoah assert_rp_isalive_installed failed", rp->is_alive_non_header(), heap->is_alive_closure(), 364 file, line); 365 } 366 }