heapRegionSet.cpp 15.4 KB
Newer Older
1
/*
2
 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 * 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.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#include "precompiled.hpp"
26
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
27
#include "gc_implementation/g1/heapRegionRemSet.hpp"
28 29
#include "gc_implementation/g1/heapRegionSet.inline.hpp"

30 31
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC

32
uint FreeRegionList::_unrealistically_long_length = 0;
33

T
tonyp 已提交
34
void HeapRegionSetBase::fill_in_ext_msg(hrs_ext_msg* msg, const char* message) {
35 36
  msg->append("[%s] %s ln: %u cy: "SIZE_FORMAT,
              name(), message, length(), total_capacity_bytes());
37 38 39
  fill_in_ext_msg_extra(msg);
}

40 41
#ifndef PRODUCT
void HeapRegionSetBase::verify_region(HeapRegion* hr) {
42 43 44 45 46
  assert(hr->containing_set() == this, err_msg("Inconsistent containing set for %u", hr->hrm_index()));
  assert(!hr->is_young(), err_msg("Adding young region %u", hr->hrm_index())); // currently we don't use these sets for young regions
  assert(hr->isHumongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrm_index(), name()));
  assert(hr->is_empty() == regions_empty(), err_msg("Wrong empty state for region %u and set %s", hr->hrm_index(), name()));
  assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrm_index()));
47
}
48
#endif
49 50 51 52 53 54

void HeapRegionSetBase::verify() {
  // It's important that we also observe the MT safety protocol even
  // for the verification calls. If we do verification without the
  // appropriate locks and the set changes underneath our feet
  // verification might fail and send us on a wild goose chase.
55
  check_mt_safety();
56

57 58
  guarantee(( is_empty() && length() == 0 && total_capacity_bytes() == 0) ||
            (!is_empty() && length() >= 0 && total_capacity_bytes() >= 0),
T
tonyp 已提交
59
            hrs_ext_msg(this, "invariant"));
60 61 62 63
}

void HeapRegionSetBase::verify_start() {
  // See comment in verify() about MT safety and verification.
64
  check_mt_safety();
65
  assert(!_verify_in_progress,
T
tonyp 已提交
66
         hrs_ext_msg(this, "verification should not be in progress"));
67 68 69 70

  // Do the basic verification first before we do the checks over the regions.
  HeapRegionSetBase::verify();

71
  _verify_in_progress = true;
72 73 74 75
}

void HeapRegionSetBase::verify_end() {
  // See comment in verify() about MT safety and verification.
76
  check_mt_safety();
77
  assert(_verify_in_progress,
T
tonyp 已提交
78
         hrs_ext_msg(this, "verification should be in progress"));
79 80 81 82 83 84 85 86 87 88 89

  _verify_in_progress = false;
}

void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) {
  out->cr();
  out->print_cr("Set: %s ("PTR_FORMAT")", name(), this);
  out->print_cr("  Region Assumptions");
  out->print_cr("    humongous         : %s", BOOL_TO_STR(regions_humongous()));
  out->print_cr("    empty             : %s", BOOL_TO_STR(regions_empty()));
  out->print_cr("  Attributes");
90
  out->print_cr("    length            : %14u", length());
91 92 93 94
  out->print_cr("    total capacity    : "SIZE_FORMAT_W(14)" bytes",
                total_capacity_bytes());
}

95
HeapRegionSetBase::HeapRegionSetBase(const char* name, bool humongous, bool empty, HRSMtSafeChecker* mt_safety_checker)
96
  : _name(name), _verify_in_progress(false),
97 98 99
    _is_humongous(humongous), _is_empty(empty), _mt_safety_checker(mt_safety_checker),
    _count()
{ }
100

101 102 103
void FreeRegionList::set_unrealistically_long_length(uint len) {
  guarantee(_unrealistically_long_length == 0, "should only be set once");
  _unrealistically_long_length = len;
104 105
}

106
void FreeRegionList::fill_in_ext_msg_extra(hrs_ext_msg* msg) {
107
  msg->append(" hd: "PTR_FORMAT" tl: "PTR_FORMAT, _head, _tail);
108 109
}

110 111
void FreeRegionList::remove_all() {
  check_mt_safety();
112 113 114 115
  verify_optional();

  HeapRegion* curr = _head;
  while (curr != NULL) {
116
    verify_region(curr);
117 118 119

    HeapRegion* next = curr->next();
    curr->set_next(NULL);
120
    curr->set_prev(NULL);
121 122 123 124 125 126 127 128
    curr->set_containing_set(NULL);
    curr = next;
  }
  clear();

  verify_optional();
}

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
void FreeRegionList::add_ordered(FreeRegionList* from_list) {
  check_mt_safety();
  from_list->check_mt_safety();

  verify_optional();
  from_list->verify_optional();

  if (from_list->is_empty()) {
    return;
  }

  #ifdef ASSERT
  FreeRegionListIterator iter(from_list);
  while (iter.more_available()) {
    HeapRegion* hr = iter.get_next();
    // In set_containing_set() we check that we either set the value
    // from NULL to non-NULL or vice versa to catch bugs. So, we have
    // to NULL it first before setting it to the value.
    hr->set_containing_set(NULL);
    hr->set_containing_set(this);
  }
  #endif // ASSERT

152 153 154 155 156 157 158
  if (is_empty()) {
    assert(length() == 0 && _tail == NULL, hrs_ext_msg(this, "invariant"));
    _head = from_list->_head;
    _tail = from_list->_tail;
  } else {
    HeapRegion* curr_to = _head;
    HeapRegion* curr_from = from_list->_head;
159

160
    while (curr_from != NULL) {
161
      while (curr_to != NULL && curr_to->hrm_index() < curr_from->hrm_index()) {
162 163
        curr_to = curr_to->next();
      }
164

165 166 167 168 169
      if (curr_to == NULL) {
        // The rest of the from list should be added as tail
        _tail->set_next(curr_from);
        curr_from->set_prev(_tail);
        curr_from = NULL;
170
      } else {
171 172 173 174 175 176 177 178 179 180 181 182
        HeapRegion* next_from = curr_from->next();

        curr_from->set_next(curr_to);
        curr_from->set_prev(curr_to->prev());
        if (curr_to->prev() == NULL) {
          _head = curr_from;
        } else {
          curr_to->prev()->set_next(curr_from);
        }
        curr_to->set_prev(curr_from);

        curr_from = next_from;
183 184 185
      }
    }

186
    if (_tail->hrm_index() < from_list->_tail->hrm_index()) {
187 188
      _tail = from_list->_tail;
    }
189 190 191 192 193 194 195 196 197
  }

  _count.increment(from_list->length(), from_list->total_capacity_bytes());
  from_list->clear();

  verify_optional();
  from_list->verify_optional();
}

198
void FreeRegionList::remove_starting_at(HeapRegion* first, uint num_regions) {
199
  check_mt_safety();
200
  assert(num_regions >= 1, hrs_ext_msg(this, "pre-condition"));
T
tonyp 已提交
201
  assert(!is_empty(), hrs_ext_msg(this, "pre-condition"));
202 203

  verify_optional();
204
  DEBUG_ONLY(uint old_length = length();)
205

206
  HeapRegion* curr = first;
207
  uint count = 0;
208
  while (count < num_regions) {
209
    verify_region(curr);
210
    HeapRegion* next = curr->next();
211
    HeapRegion* prev = curr->prev();
212

213 214 215 216
    assert(count < num_regions,
           hrs_err_msg("[%s] should not come across more regions "
                       "pending for removal than num_regions: %u",
                       name(), num_regions));
217

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
    if (prev == NULL) {
      assert(_head == curr, hrs_ext_msg(this, "invariant"));
      _head = next;
    } else {
      assert(_head != curr, hrs_ext_msg(this, "invariant"));
      prev->set_next(next);
    }
    if (next == NULL) {
      assert(_tail == curr, hrs_ext_msg(this, "invariant"));
      _tail = prev;
    } else {
      assert(_tail != curr, hrs_ext_msg(this, "invariant"));
      next->set_prev(prev);
    }
    if (_last = curr) {
      _last = NULL;
    }
235

236 237 238
    curr->set_next(NULL);
    curr->set_prev(NULL);
    remove(curr);
239

240
    count++;
241 242 243
    curr = next;
  }

244 245 246 247
  assert(count == num_regions,
         hrs_err_msg("[%s] count: %u should be == num_regions: %u",
                     name(), count, num_regions));
  assert(length() + num_regions == old_length,
T
tonyp 已提交
248
         hrs_err_msg("[%s] new length should be consistent "
249 250
                     "new length: %u old length: %u num_regions: %u",
                     name(), length(), old_length, num_regions));
251 252 253 254

  verify_optional();
}

255
void FreeRegionList::verify() {
256 257
  // See comment in HeapRegionSetBase::verify() about MT safety and
  // verification.
258
  check_mt_safety();
259 260 261 262

  // This will also do the basic verification too.
  verify_start();

263
  verify_list();
264 265 266 267

  verify_end();
}

268 269
void FreeRegionList::clear() {
  _count = HeapRegionSetCount();
270 271
  _head = NULL;
  _tail = NULL;
272
  _last = NULL;
273 274
}

275
void FreeRegionList::print_on(outputStream* out, bool print_contents) {
276 277 278 279 280 281 282
  HeapRegionSetBase::print_on(out, print_contents);
  out->print_cr("  Linking");
  out->print_cr("    head              : "PTR_FORMAT, _head);
  out->print_cr("    tail              : "PTR_FORMAT, _tail);

  if (print_contents) {
    out->print_cr("  Contents");
283
    FreeRegionListIterator iter(this);
284 285 286 287 288
    while (iter.more_available()) {
      HeapRegion* hr = iter.get_next();
      hr->print_on(out);
    }
  }
289 290

  out->cr();
291
}
292 293

void FreeRegionList::verify_list() {
294
  HeapRegion* curr = _head;
295 296 297 298
  HeapRegion* prev1 = NULL;
  HeapRegion* prev0 = NULL;
  uint count = 0;
  size_t capacity = 0;
299 300 301
  uint last_index = 0;

  guarantee(_head == NULL || _head->prev() == NULL, "_head should not have a prev");
302 303 304 305 306 307 308
  while (curr != NULL) {
    verify_region(curr);

    count++;
    guarantee(count < _unrealistically_long_length,
        hrs_err_msg("[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: "PTR_FORMAT" prev0: "PTR_FORMAT" " "prev1: "PTR_FORMAT" length: %u", name(), count, curr, prev0, prev1, length()));

309 310 311
    if (curr->next() != NULL) {
      guarantee(curr->next()->prev() == curr, "Next or prev pointers messed up");
    }
312 313
    guarantee(curr->hrm_index() == 0 || curr->hrm_index() > last_index, "List should be sorted");
    last_index = curr->hrm_index();
314

315 316 317 318 319 320 321
    capacity += curr->capacity();

    prev1 = prev0;
    prev0 = curr;
    curr = curr->next();
  }

322
  guarantee(_tail == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), _tail->hrm_index(), prev0->hrm_index()));
323
  guarantee(_tail == NULL || _tail->next() == NULL, "_tail should not have a next");
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
  guarantee(length() == count, err_msg("%s count mismatch. Expected %u, actual %u.", name(), length(), count));
  guarantee(total_capacity_bytes() == capacity, err_msg("%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT,
      name(), total_capacity_bytes(), capacity));
}

// Note on the check_mt_safety() methods below:
//
// Verification of the "master" heap region sets / lists that are
// maintained by G1CollectedHeap is always done during a STW pause and
// by the VM thread at the start / end of the pause. The standard
// verification methods all assert check_mt_safety(). This is
// important as it ensures that verification is done without
// concurrent updates taking place at the same time. It follows, that,
// for the "master" heap region sets / lists, the check_mt_safety()
// method should include the VM thread / STW case.

void MasterFreeRegionListMtSafeChecker::check() {
  // Master Free List MT safety protocol:
  // (a) If we're at a safepoint, operations on the master free list
  // should be invoked by either the VM thread (which will serialize
  // them) or by the GC workers while holding the
  // FreeList_lock.
  // (b) If we're not at a safepoint, operations on the master free
  // list should be invoked while holding the Heap_lock.

  if (SafepointSynchronize::is_at_safepoint()) {
    guarantee(Thread::current()->is_VM_thread() ||
              FreeList_lock->owned_by_self(), "master free list MT safety protocol at a safepoint");
  } else {
    guarantee(Heap_lock->owned_by_self(), "master free list MT safety protocol outside a safepoint");
  }
}

void SecondaryFreeRegionListMtSafeChecker::check() {
  // Secondary Free List MT safety protocol:
  // Operations on the secondary free list should always be invoked
  // while holding the SecondaryFreeList_lock.

  guarantee(SecondaryFreeList_lock->owned_by_self(), "secondary free list MT safety protocol");
}

void OldRegionSetMtSafeChecker::check() {
  // Master Old Set MT safety protocol:
  // (a) If we're at a safepoint, operations on the master old set
  // should be invoked:
  // - by the VM thread (which will serialize them), or
  // - by the GC workers while holding the FreeList_lock, if we're
  //   at a safepoint for an evacuation pause (this lock is taken
  //   anyway when an GC alloc region is retired so that a new one
  //   is allocated from the free list), or
  // - by the GC workers while holding the OldSets_lock, if we're at a
  //   safepoint for a cleanup pause.
  // (b) If we're not at a safepoint, operations on the master old set
  // should be invoked while holding the Heap_lock.

  if (SafepointSynchronize::is_at_safepoint()) {
    guarantee(Thread::current()->is_VM_thread()
        || FreeList_lock->owned_by_self() || OldSets_lock->owned_by_self(),
        "master old set MT safety protocol at a safepoint");
  } else {
    guarantee(Heap_lock->owned_by_self(), "master old set MT safety protocol outside a safepoint");
  }
}

void HumongousRegionSetMtSafeChecker::check() {
  // Humongous Set MT safety protocol:
  // (a) If we're at a safepoint, operations on the master humongous
  // set should be invoked by either the VM thread (which will
  // serialize them) or by the GC workers while holding the
  // OldSets_lock.
  // (b) If we're not at a safepoint, operations on the master
  // humongous set should be invoked while holding the Heap_lock.

  if (SafepointSynchronize::is_at_safepoint()) {
    guarantee(Thread::current()->is_VM_thread() ||
              OldSets_lock->owned_by_self(),
              "master humongous set MT safety protocol at a safepoint");
  } else {
    guarantee(Heap_lock->owned_by_self(),
              "master humongous set MT safety protocol outside a safepoint");
  }
}
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443

void FreeRegionList_test() {
  FreeRegionList l("test");

  const uint num_regions_in_test = 5;
  // Create a fake heap. It does not need to be valid, as the HeapRegion constructor
  // does not access it.
  MemRegion heap(NULL, num_regions_in_test * HeapRegion::GrainWords);
  // Allocate a fake BOT because the HeapRegion constructor initializes
  // the BOT.
  size_t bot_size = G1BlockOffsetSharedArray::compute_size(heap.word_size());
  HeapWord* bot_data = NEW_C_HEAP_ARRAY(HeapWord, bot_size, mtGC);
  ReservedSpace bot_rs(G1BlockOffsetSharedArray::compute_size(heap.word_size()));
  G1RegionToSpaceMapper* bot_storage =
    G1RegionToSpaceMapper::create_mapper(bot_rs,
                                         os::vm_page_size(),
                                         HeapRegion::GrainBytes,
                                         G1BlockOffsetSharedArray::N_bytes,
                                         mtGC);
  G1BlockOffsetSharedArray oa(heap, bot_storage);
  bot_storage->commit_regions(0, num_regions_in_test);
  HeapRegion hr0(0, &oa, heap);
  HeapRegion hr1(1, &oa, heap);
  HeapRegion hr2(2, &oa, heap);
  HeapRegion hr3(3, &oa, heap);
  HeapRegion hr4(4, &oa, heap);
  l.add_ordered(&hr1);
  l.add_ordered(&hr0);
  l.add_ordered(&hr3);
  l.add_ordered(&hr4);
  l.add_ordered(&hr2);
  assert(l.length() == num_regions_in_test, "wrong length");
  l.verify_list();

  bot_storage->uncommit_regions(0, num_regions_in_test);
  delete bot_storage;
  FREE_C_HEAP_ARRAY(HeapWord, bot_data, mtGC);
}