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_implementation/shenandoah/brooksPointer.hpp" 27 #include "gc_implementation/shenandoah/shenandoahAsserts.hpp" 28 #include "gc_implementation/shenandoah/shenandoahHeap.hpp" 29 #include "gc_implementation/shenandoah/shenandoahHeap.inline.hpp" 30 #include "memory/resourceArea.hpp" 31 32 33 void ShenandoahAsserts::print_obj(ShenandoahMessageBuffer& msg, oop obj) { 34 ShenandoahHeap* heap = ShenandoahHeap::heap(); 35 ShenandoahHeapRegion *r = heap->heap_region_containing(obj); 36 37 ResourceMark rm; 38 stringStream ss; 39 r->print_on(&ss); 40 41 msg.append(" " PTR_FORMAT " - klass " PTR_FORMAT " %s\n", p2i(obj), p2i(obj->klass()), obj->klass()->external_name()); 42 msg.append(" %3s allocated after complete mark start\n", heap->allocated_after_complete_mark_start((HeapWord *) obj) ? "" : "not"); 43 msg.append(" %3s allocated after next mark start\n", heap->allocated_after_next_mark_start((HeapWord *) obj) ? "" : "not"); 44 msg.append(" %3s marked complete\n", heap->is_marked_complete(obj) ? "" : "not"); 45 msg.append(" %3s marked next\n", heap->is_marked_next(obj) ? "" : "not"); 46 msg.append(" %3s in collection set\n", heap->in_collection_set(obj) ? "" : "not"); 47 msg.append(" region: %s", ss.as_string()); 48 } 49 50 void ShenandoahAsserts::print_non_obj(ShenandoahMessageBuffer& msg, void* loc) { 51 ShenandoahHeap* heap = ShenandoahHeap::heap(); 52 if (heap->is_in(loc)) { 53 msg.append(" inside Java heap\n"); 54 ShenandoahHeapRegion *r = heap->heap_region_containing(loc); 55 stringStream ss; 56 r->print_on(&ss); 57 58 msg.append(" %3s in collection set\n", heap->in_collection_set(loc) ? "" : "not"); 59 msg.append(" region: %s", ss.as_string()); 60 } else { 61 msg.append(" outside of Java heap\n"); 62 stringStream ss; 63 os::print_location(&ss, (intptr_t) loc, false); 64 msg.append(" %s", ss.as_string()); 65 } 66 } 67 68 void ShenandoahAsserts::print_obj_safe(ShenandoahMessageBuffer& msg, void* loc) { 69 ShenandoahHeap* heap = ShenandoahHeap::heap(); 70 msg.append(" " PTR_FORMAT " - safe print, no details\n", p2i(loc)); 71 if (heap->is_in(loc)) { 72 ShenandoahHeapRegion* r = heap->heap_region_containing(loc); 73 if (r != NULL) { 74 stringStream ss; 75 r->print_on(&ss); 76 msg.append(" region: %s", ss.as_string()); 77 } 78 } 79 } 80 81 void ShenandoahAsserts::print_failure(SafeLevel level, oop obj, void* interior_loc, oop loc, 82 const char* phase, const char* label, 83 const char* file, int line) { 84 ShenandoahHeap* heap = ShenandoahHeap::heap(); 85 ResourceMark rm; 86 87 bool loc_in_heap = (loc != NULL && heap->is_in(loc)); 88 bool interior_loc_in_heap = (interior_loc != NULL && heap->is_in(interior_loc)); 89 90 ShenandoahMessageBuffer msg("%s; %s\n\n", phase, label); 91 92 msg.append("Referenced from:\n"); 93 if (interior_loc != NULL) { 94 msg.append(" interior location: " PTR_FORMAT "\n", p2i(interior_loc)); 95 if (loc_in_heap) { 96 print_obj(msg, loc); 97 } else { 98 print_non_obj(msg, interior_loc); 99 } 100 } else { 101 msg.append(" no interior location recorded (probably a plain heap scan, or detached oop)\n"); 102 } 103 msg.append("\n"); 104 105 msg.append("Object:\n"); 106 if (level >= _safe_oop) { 107 print_obj(msg, obj); 108 } else { 109 print_obj_safe(msg, obj); 110 } 111 msg.append("\n"); 112 113 if (level >= _safe_oop) { 114 oop fwd = (oop) BrooksPointer::get_raw_unchecked(obj); 115 msg.append("Forwardee:\n"); 116 if (!oopDesc::unsafe_equals(obj, fwd)) { 117 if (level >= _safe_oop_fwd) { 118 print_obj(msg, fwd); 119 } else { 120 print_obj_safe(msg, fwd); 121 } 122 } else { 123 msg.append(" (the object itself)"); 124 } 125 msg.append("\n"); 126 } 127 128 if (level >= _safe_oop_fwd) { 129 oop fwd = (oop) BrooksPointer::get_raw_unchecked(obj); 130 oop fwd2 = (oop) BrooksPointer::get_raw_unchecked(fwd); 131 if (!oopDesc::unsafe_equals(fwd, fwd2)) { 132 msg.append("Second forwardee:\n"); 133 print_obj_safe(msg, fwd2); 134 msg.append("\n"); 135 } 136 } 137 138 report_vm_error(file, line, msg.buffer()); 139 } 140 141 void ShenandoahAsserts::assert_in_heap(void* interior_loc, oop obj, const char *file, int line) { 142 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 143 144 if (!heap->is_in(obj)) { 145 print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_in_heap failed", 146 "oop must point to a heap address", 147 file, line); 148 } 149 } 150 151 void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* file, int line) { 152 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 153 154 // Step 1. Check that both obj and its fwdptr are in heap. 155 // After this step, it is safe to call heap_region_containing(). 156 if (!heap->is_in(obj)) { 157 print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_correct failed", 158 "oop must point to a heap address", 159 file, line); 160 } 161 162 oop fwd = oop(BrooksPointer::get_raw_unchecked(obj)); 163 164 if (!heap->is_in(fwd)) { 165 print_failure(_safe_oop, obj, interior_loc, NULL, "Shenandoah assert_correct failed", 166 "Forwardee must point to a heap address", 167 file, line); 168 } 169 170 bool is_forwarded = !oopDesc::unsafe_equals(obj, fwd); 171 172 // When Full GC moves the objects, we cannot trust fwdptrs. If we got here, it means something 173 // tries fwdptr manipulation when Full GC is running. The only exception is using the fwdptr 174 // that still points to the object itself. 175 176 if (is_forwarded && heap->is_full_gc_move_in_progress()) { 177 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_correct failed", 178 "Non-trivial forwarding pointer during Full GC moves, probable bug.", 179 file, line); 180 } 181 182 // Step 2. Check that forwardee points to correct region. 183 if (is_forwarded && 184 (heap->heap_region_index_containing(fwd) == 185 heap->heap_region_index_containing(obj))) { 186 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_correct failed", 187 "Forwardee should be self, or another region", 188 file, line); 189 } 190 191 // Step 3. Check for multiple forwardings 192 if (is_forwarded) { 193 oop fwd2 = oop(BrooksPointer::get_raw_unchecked(fwd)); 194 if (!oopDesc::unsafe_equals(fwd, fwd2)) { 195 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_correct failed", 196 "Multiple forwardings", 197 file, line); 198 } 199 } 200 } 201 202 void ShenandoahAsserts::assert_in_correct_region(void* interior_loc, oop obj, const char* file, int line) { 203 assert_correct(interior_loc, obj, file, line); 204 205 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 206 ShenandoahHeapRegion* r = heap->heap_region_containing(obj); 207 if (!r->is_active()) { 208 print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_in_correct_region failed", 209 "Object must reside in active region", 210 file, line); 211 } 212 213 size_t alloc_size = obj->size() + BrooksPointer::word_size(); 214 if (alloc_size > ShenandoahHeapRegion::humongous_threshold_words()) { 215 size_t idx = r->region_number(); 216 size_t num_regions = ShenandoahHeapRegion::required_regions(alloc_size * HeapWordSize); 217 for (size_t i = idx; i < idx + num_regions; i++) { 218 ShenandoahHeapRegion* chain_reg = heap->get_region(i); 219 if (i == idx && !chain_reg->is_humongous_start()) { 220 print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_in_correct_region failed", 221 "Object must reside in humongous start", 222 file, line); 223 } 224 if (i != idx && !chain_reg->is_humongous_continuation()) { 225 print_failure(_safe_oop, obj, interior_loc, NULL, "Shenandoah assert_in_correct_region failed", 226 "Humongous continuation should be of proper size", 227 file, line); 228 } 229 } 230 } 231 } 232 233 void ShenandoahAsserts::assert_forwarded(void* interior_loc, oop obj, const char* file, int line) { 234 assert_correct(interior_loc, obj, file, line); 235 oop fwd = oop(BrooksPointer::get_raw_unchecked(obj)); 236 237 if (oopDesc::unsafe_equals(obj, fwd)) { 238 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_forwarded failed", 239 "Object should be forwarded", 240 file, line); 241 } 242 } 243 244 void ShenandoahAsserts::assert_not_forwarded(void* interior_loc, oop obj, const char* file, int line) { 245 assert_correct(interior_loc, obj, file, line); 246 oop fwd = oop(BrooksPointer::get_raw_unchecked(obj)); 247 248 if (!oopDesc::unsafe_equals(obj, fwd)) { 249 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_not_forwarded failed", 250 "Object should not be forwarded", 251 file, line); 252 } 253 } 254 255 void ShenandoahAsserts::assert_marked_complete(void* interior_loc, oop obj, const char* file, int line) { 256 assert_correct(interior_loc, obj, file, line); 257 258 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 259 if (!heap->is_marked_complete(obj)) { 260 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_marked_complete failed", 261 "Object should be marked (complete)", 262 file, line); 263 } 264 } 265 266 void ShenandoahAsserts::assert_marked_next(void* interior_loc, oop obj, const char* file, int line) { 267 assert_correct(interior_loc, obj, file, line); 268 269 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 270 if (!heap->is_marked_next(obj)) { 271 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_marked_next failed", 272 "Object should be marked (next)", 273 file, line); 274 } 275 } 276 277 void ShenandoahAsserts::assert_not_in_cset(void* interior_loc, oop obj, const char* file, int line) { 278 assert_correct(interior_loc, obj, file, line); 279 280 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 281 if (heap->in_collection_set(obj)) { 282 print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_not_in_cset failed", 283 "Object should not be in collection set", 284 file, line); 285 } 286 } 287 288 void ShenandoahAsserts::assert_not_in_cset_loc(void* interior_loc, const char* file, int line) { 289 ShenandoahHeap* heap = ShenandoahHeap::heap_no_check(); 290 if (heap->in_collection_set(interior_loc)) { 291 print_failure(_safe_unknown, NULL, interior_loc, NULL, "Shenandoah assert_not_in_cset_loc failed", 292 "Interior location should not be in collection set", 293 file, line); 294 } 295 } 296 297 void ShenandoahAsserts::print_rp_failure(const char *label, BoolObjectClosure* actual, BoolObjectClosure* expected, 298 const char *file, int line) { 299 ShenandoahHeap* heap = ShenandoahHeap::heap(); 300 ShenandoahMessageBuffer msg("%s\n", label); 301 msg.append(" Actual: " PTR_FORMAT "\n", p2i(actual)); 302 msg.append(" Expected: " PTR_FORMAT "\n", p2i(expected)); 303 msg.append(" SH->_is_alive: " PTR_FORMAT "\n", p2i(&heap->_is_alive)); 304 msg.append(" SH->_forwarded_is_alive: " PTR_FORMAT "\n", p2i(&heap->_forwarded_is_alive)); 305 report_vm_error(file, line, msg.buffer()); 306 } 307 308 void ShenandoahAsserts::assert_rp_isalive_not_installed(const char *file, int line) { 309 ShenandoahHeap* heap = ShenandoahHeap::heap(); 310 ReferenceProcessor* rp = heap->ref_processor(); 311 if (rp->is_alive_non_header() != NULL) { 312 print_rp_failure("Shenandoah assert_rp_isalive_not_installed failed", rp->is_alive_non_header(), NULL, 313 file, line); 314 } 315 } 316 317 void ShenandoahAsserts::assert_rp_isalive_installed(const char *file, int line) { 318 ShenandoahHeap* heap = ShenandoahHeap::heap(); 319 ReferenceProcessor* rp = heap->ref_processor(); 320 if (rp->is_alive_non_header() != heap->is_alive_closure()) { 321 print_rp_failure("Shenandoah assert_rp_isalive_installed failed", rp->is_alive_non_header(), heap->is_alive_closure(), 322 file, line); 323 } 324 }