src/share/vm/gc_implementation/g1/g1AllocRegion.cpp

Thu, 07 Apr 2011 09:53:20 -0700

author
johnc
date
Thu, 07 Apr 2011 09:53:20 -0700
changeset 2781
e1162778c1c8
parent 2715
abdfc822206f
child 3028
f44782f04dd4
permissions
-rw-r--r--

7009266: G1: assert(obj->is_oop_or_null(true )) failed: Error
Summary: A referent object that is only weakly reachable at the start of concurrent marking but is re-attached to the strongly reachable object graph during marking may not be marked as live. This can cause the reference object to be processed prematurely and leave dangling pointers to the referent object. Implement a read barrier for the java.lang.ref.Reference::referent field by intrinsifying the Reference.get() method, and intercepting accesses though JNI, reflection, and Unsafe, so that when a non-null referent object is read it is also logged in an SATB buffer.
Reviewed-by: kvn, iveresov, never, tonyp, dholmes

tonyp@2715 1 /*
tonyp@2715 2 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
tonyp@2715 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
tonyp@2715 4 *
tonyp@2715 5 * This code is free software; you can redistribute it and/or modify it
tonyp@2715 6 * under the terms of the GNU General Public License version 2 only, as
tonyp@2715 7 * published by the Free Software Foundation.
tonyp@2715 8 *
tonyp@2715 9 * This code is distributed in the hope that it will be useful, but WITHOUT
tonyp@2715 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
tonyp@2715 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
tonyp@2715 12 * version 2 for more details (a copy is included in the LICENSE file that
tonyp@2715 13 * accompanied this code).
tonyp@2715 14 *
tonyp@2715 15 * You should have received a copy of the GNU General Public License version
tonyp@2715 16 * 2 along with this work; if not, write to the Free Software Foundation,
tonyp@2715 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
tonyp@2715 18 *
tonyp@2715 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
tonyp@2715 20 * or visit www.oracle.com if you need additional information or have any
tonyp@2715 21 * questions.
tonyp@2715 22 *
tonyp@2715 23 */
tonyp@2715 24
tonyp@2715 25 #include "precompiled.hpp"
tonyp@2715 26 #include "gc_implementation/g1/g1AllocRegion.inline.hpp"
tonyp@2715 27 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
tonyp@2715 28
tonyp@2715 29 G1CollectedHeap* G1AllocRegion::_g1h = NULL;
tonyp@2715 30 HeapRegion* G1AllocRegion::_dummy_region = NULL;
tonyp@2715 31
tonyp@2715 32 void G1AllocRegion::setup(G1CollectedHeap* g1h, HeapRegion* dummy_region) {
tonyp@2715 33 assert(_dummy_region == NULL, "should be set once");
tonyp@2715 34 assert(dummy_region != NULL, "pre-condition");
tonyp@2715 35 assert(dummy_region->free() == 0, "pre-condition");
tonyp@2715 36
tonyp@2715 37 // Make sure that any allocation attempt on this region will fail
tonyp@2715 38 // and will not trigger any asserts.
tonyp@2715 39 assert(allocate(dummy_region, 1, false) == NULL, "should fail");
tonyp@2715 40 assert(par_allocate(dummy_region, 1, false) == NULL, "should fail");
tonyp@2715 41 assert(allocate(dummy_region, 1, true) == NULL, "should fail");
tonyp@2715 42 assert(par_allocate(dummy_region, 1, true) == NULL, "should fail");
tonyp@2715 43
tonyp@2715 44 _g1h = g1h;
tonyp@2715 45 _dummy_region = dummy_region;
tonyp@2715 46 }
tonyp@2715 47
tonyp@2715 48 void G1AllocRegion::fill_up_remaining_space(HeapRegion* alloc_region,
tonyp@2715 49 bool bot_updates) {
tonyp@2715 50 assert(alloc_region != NULL && alloc_region != _dummy_region,
tonyp@2715 51 "pre-condition");
tonyp@2715 52
tonyp@2715 53 // Other threads might still be trying to allocate using a CAS out
tonyp@2715 54 // of the region we are trying to retire, as they can do so without
tonyp@2715 55 // holding the lock. So, we first have to make sure that noone else
tonyp@2715 56 // can allocate out of it by doing a maximal allocation. Even if our
tonyp@2715 57 // CAS attempt fails a few times, we'll succeed sooner or later
tonyp@2715 58 // given that failed CAS attempts mean that the region is getting
tonyp@2715 59 // closed to being full.
tonyp@2715 60 size_t free_word_size = alloc_region->free() / HeapWordSize;
tonyp@2715 61
tonyp@2715 62 // This is the minimum free chunk we can turn into a dummy
tonyp@2715 63 // object. If the free space falls below this, then noone can
tonyp@2715 64 // allocate in this region anyway (all allocation requests will be
tonyp@2715 65 // of a size larger than this) so we won't have to perform the dummy
tonyp@2715 66 // allocation.
tonyp@2715 67 size_t min_word_size_to_fill = CollectedHeap::min_fill_size();
tonyp@2715 68
tonyp@2715 69 while (free_word_size >= min_word_size_to_fill) {
tonyp@2715 70 HeapWord* dummy = par_allocate(alloc_region, free_word_size, bot_updates);
tonyp@2715 71 if (dummy != NULL) {
tonyp@2715 72 // If the allocation was successful we should fill in the space.
tonyp@2715 73 CollectedHeap::fill_with_object(dummy, free_word_size);
tonyp@2715 74 alloc_region->set_pre_dummy_top(dummy);
tonyp@2715 75 break;
tonyp@2715 76 }
tonyp@2715 77
tonyp@2715 78 free_word_size = alloc_region->free() / HeapWordSize;
tonyp@2715 79 // It's also possible that someone else beats us to the
tonyp@2715 80 // allocation and they fill up the region. In that case, we can
tonyp@2715 81 // just get out of the loop.
tonyp@2715 82 }
tonyp@2715 83 assert(alloc_region->free() / HeapWordSize < min_word_size_to_fill,
tonyp@2715 84 "post-condition");
tonyp@2715 85 }
tonyp@2715 86
tonyp@2715 87 void G1AllocRegion::retire(bool fill_up) {
tonyp@2715 88 assert(_alloc_region != NULL, ar_ext_msg(this, "not initialized properly"));
tonyp@2715 89
tonyp@2715 90 trace("retiring");
tonyp@2715 91 HeapRegion* alloc_region = _alloc_region;
tonyp@2715 92 if (alloc_region != _dummy_region) {
tonyp@2715 93 // We never have to check whether the active region is empty or not,
tonyp@2715 94 // and potentially free it if it is, given that it's guaranteed that
tonyp@2715 95 // it will never be empty.
tonyp@2715 96 assert(!alloc_region->is_empty(),
tonyp@2715 97 ar_ext_msg(this, "the alloc region should never be empty"));
tonyp@2715 98
tonyp@2715 99 if (fill_up) {
tonyp@2715 100 fill_up_remaining_space(alloc_region, _bot_updates);
tonyp@2715 101 }
tonyp@2715 102
tonyp@2715 103 assert(alloc_region->used() >= _used_bytes_before,
tonyp@2715 104 ar_ext_msg(this, "invariant"));
tonyp@2715 105 size_t allocated_bytes = alloc_region->used() - _used_bytes_before;
tonyp@2715 106 retire_region(alloc_region, allocated_bytes);
tonyp@2715 107 _used_bytes_before = 0;
tonyp@2715 108 _alloc_region = _dummy_region;
tonyp@2715 109 }
tonyp@2715 110 trace("retired");
tonyp@2715 111 }
tonyp@2715 112
tonyp@2715 113 HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size,
tonyp@2715 114 bool force) {
tonyp@2715 115 assert(_alloc_region == _dummy_region, ar_ext_msg(this, "pre-condition"));
tonyp@2715 116 assert(_used_bytes_before == 0, ar_ext_msg(this, "pre-condition"));
tonyp@2715 117
tonyp@2715 118 trace("attempting region allocation");
tonyp@2715 119 HeapRegion* new_alloc_region = allocate_new_region(word_size, force);
tonyp@2715 120 if (new_alloc_region != NULL) {
tonyp@2715 121 new_alloc_region->reset_pre_dummy_top();
tonyp@2715 122 // Need to do this before the allocation
tonyp@2715 123 _used_bytes_before = new_alloc_region->used();
tonyp@2715 124 HeapWord* result = allocate(new_alloc_region, word_size, _bot_updates);
tonyp@2715 125 assert(result != NULL, ar_ext_msg(this, "the allocation should succeeded"));
tonyp@2715 126
tonyp@2715 127 OrderAccess::storestore();
tonyp@2715 128 // Note that we first perform the allocation and then we store the
tonyp@2715 129 // region in _alloc_region. This is the reason why an active region
tonyp@2715 130 // can never be empty.
tonyp@2715 131 _alloc_region = new_alloc_region;
tonyp@2715 132 trace("region allocation successful");
tonyp@2715 133 return result;
tonyp@2715 134 } else {
tonyp@2715 135 trace("region allocation failed");
tonyp@2715 136 return NULL;
tonyp@2715 137 }
tonyp@2715 138 ShouldNotReachHere();
tonyp@2715 139 }
tonyp@2715 140
tonyp@2715 141 void G1AllocRegion::fill_in_ext_msg(ar_ext_msg* msg, const char* message) {
tonyp@2715 142 msg->append("[%s] %s b: %s r: "PTR_FORMAT" u: "SIZE_FORMAT,
tonyp@2715 143 _name, message, BOOL_TO_STR(_bot_updates),
tonyp@2715 144 _alloc_region, _used_bytes_before);
tonyp@2715 145 }
tonyp@2715 146
tonyp@2715 147 void G1AllocRegion::init() {
tonyp@2715 148 trace("initializing");
tonyp@2715 149 assert(_alloc_region == NULL && _used_bytes_before == 0,
tonyp@2715 150 ar_ext_msg(this, "pre-condition"));
tonyp@2715 151 assert(_dummy_region != NULL, "should have been set");
tonyp@2715 152 _alloc_region = _dummy_region;
tonyp@2715 153 trace("initialized");
tonyp@2715 154 }
tonyp@2715 155
tonyp@2715 156 HeapRegion* G1AllocRegion::release() {
tonyp@2715 157 trace("releasing");
tonyp@2715 158 HeapRegion* alloc_region = _alloc_region;
tonyp@2715 159 retire(false /* fill_up */);
tonyp@2715 160 assert(_alloc_region == _dummy_region, "post-condition of retire()");
tonyp@2715 161 _alloc_region = NULL;
tonyp@2715 162 trace("released");
tonyp@2715 163 return (alloc_region == _dummy_region) ? NULL : alloc_region;
tonyp@2715 164 }
tonyp@2715 165
tonyp@2715 166 #if G1_ALLOC_REGION_TRACING
tonyp@2715 167 void G1AllocRegion::trace(const char* str, size_t word_size, HeapWord* result) {
tonyp@2715 168 // All the calls to trace that set either just the size or the size
tonyp@2715 169 // and the result are considered part of level 2 tracing and are
tonyp@2715 170 // skipped during level 1 tracing.
tonyp@2715 171 if ((word_size == 0 && result == NULL) || (G1_ALLOC_REGION_TRACING > 1)) {
tonyp@2715 172 const size_t buffer_length = 128;
tonyp@2715 173 char hr_buffer[buffer_length];
tonyp@2715 174 char rest_buffer[buffer_length];
tonyp@2715 175
tonyp@2715 176 HeapRegion* alloc_region = _alloc_region;
tonyp@2715 177 if (alloc_region == NULL) {
tonyp@2715 178 jio_snprintf(hr_buffer, buffer_length, "NULL");
tonyp@2715 179 } else if (alloc_region == _dummy_region) {
tonyp@2715 180 jio_snprintf(hr_buffer, buffer_length, "DUMMY");
tonyp@2715 181 } else {
tonyp@2715 182 jio_snprintf(hr_buffer, buffer_length,
tonyp@2715 183 HR_FORMAT, HR_FORMAT_PARAMS(alloc_region));
tonyp@2715 184 }
tonyp@2715 185
tonyp@2715 186 if (G1_ALLOC_REGION_TRACING > 1) {
tonyp@2715 187 if (result != NULL) {
tonyp@2715 188 jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT" "PTR_FORMAT,
tonyp@2715 189 word_size, result);
tonyp@2715 190 } else if (word_size != 0) {
tonyp@2715 191 jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT, word_size);
tonyp@2715 192 } else {
tonyp@2715 193 jio_snprintf(rest_buffer, buffer_length, "");
tonyp@2715 194 }
tonyp@2715 195 } else {
tonyp@2715 196 jio_snprintf(rest_buffer, buffer_length, "");
tonyp@2715 197 }
tonyp@2715 198
tonyp@2715 199 tty->print_cr("[%s] %s : %s %s", _name, hr_buffer, str, rest_buffer);
tonyp@2715 200 }
tonyp@2715 201 }
tonyp@2715 202 #endif // G1_ALLOC_REGION_TRACING
tonyp@2715 203
tonyp@2715 204 G1AllocRegion::G1AllocRegion(const char* name,
tonyp@2715 205 bool bot_updates)
tonyp@2715 206 : _name(name), _bot_updates(bot_updates),
tonyp@2715 207 _alloc_region(NULL), _used_bytes_before(0) { }
tonyp@2715 208

mercurial