aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm/gc_implementation
diff options
context:
space:
mode:
authortonyp <none@none>2009-03-18 11:37:48 -0400
committertonyp <none@none>2009-03-18 11:37:48 -0400
commiteab35a70c0518262702a7971676dbc7057bc62c8 (patch)
tree17bc7b28437141bc8051ccb233101ff6687af3f1 /src/share/vm/gc_implementation
parent2121c16b3b2303930b47ec4dfe63f5ab83af270e (diff)
parent272378d9f536bfd9d0ec1dae906045340848caf3 (diff)
downloadjdk8u_hotspot-eab35a70c0518262702a7971676dbc7057bc62c8.tar.gz
Merge
Diffstat (limited to 'src/share/vm/gc_implementation')
-rw-r--r--src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp11
-rw-r--r--src/share/vm/gc_implementation/g1/concurrentMark.cpp11
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp145
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp27
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp1
-rw-r--r--src/share/vm/gc_implementation/g1/g1RemSet.cpp26
-rw-r--r--src/share/vm/gc_implementation/g1/g1_globals.hpp10
-rw-r--r--src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp12
8 files changed, 182 insertions, 61 deletions
diff --git a/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp b/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp
index 2eb2bc0ca..6f12a3962 100644
--- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp
+++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp
@@ -145,14 +145,9 @@ void ConcurrentG1Refine::set_pya_restart() {
if (G1RSBarrierUseQueue) {
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
dcqs.abandon_logs();
- if (_cg1rThread->do_traversal()) {
- _pya = PYA_restart;
- } else {
- _cg1rThread->set_do_traversal(true);
- // Reset the post-yield actions.
- _pya = PYA_continue;
- _last_pya = PYA_continue;
- }
+ // Reset the post-yield actions.
+ _pya = PYA_continue;
+ _last_pya = PYA_continue;
} else {
_pya = PYA_restart;
}
diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/src/share/vm/gc_implementation/g1/concurrentMark.cpp
index 5b01157e9..3bc288dd0 100644
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp
@@ -1232,7 +1232,16 @@ public:
if (!_final && _regions_done == 0)
_start_vtime_sec = os::elapsedVTime();
- if (hr->continuesHumongous()) return false;
+ if (hr->continuesHumongous()) {
+ HeapRegion* hum_start = hr->humongous_start_region();
+ // If the head region of the humongous region has been determined
+ // to be alive, then all the tail regions should be marked
+ // such as well.
+ if (_region_bm->at(hum_start->hrs_index())) {
+ _region_bm->par_at_put(hr->hrs_index(), 1);
+ }
+ return false;
+ }
HeapWord* nextTop = hr->next_top_at_mark_start();
HeapWord* start = hr->top_at_conc_mark_count();
diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
index ecacfa6c7..d20e8e151 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
@@ -786,6 +786,12 @@ void G1CollectedHeap::abandon_cur_alloc_region() {
}
}
+void G1CollectedHeap::abandon_gc_alloc_regions() {
+ // first, make sure that the GC alloc region list is empty (it should!)
+ assert(_gc_alloc_region_list == NULL, "invariant");
+ release_gc_alloc_regions(true /* totally */);
+}
+
class PostMCRemSetClearClosure: public HeapRegionClosure {
ModRefBarrierSet* _mr_bs;
public:
@@ -914,6 +920,7 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
// Make sure we'll choose a new allocation region afterwards.
abandon_cur_alloc_region();
+ abandon_gc_alloc_regions();
assert(_cur_alloc_region == NULL, "Invariant.");
g1_rem_set()->as_HRInto_G1RemSet()->cleanupHRRS();
tear_down_region_lists();
@@ -954,6 +961,7 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
gclog_or_tty->print(" VerifyAfterGC:");
+ prepare_for_verify();
Universe::verify(false);
}
NOT_PRODUCT(ref_processor()->verify_no_references_recorded());
@@ -1306,7 +1314,7 @@ void G1CollectedHeap::shrink_helper(size_t shrink_bytes)
}
void G1CollectedHeap::shrink(size_t shrink_bytes) {
- release_gc_alloc_regions();
+ release_gc_alloc_regions(true /* totally */);
tear_down_region_lists(); // We will rebuild them in a moment.
shrink_helper(shrink_bytes);
rebuild_region_lists();
@@ -1345,8 +1353,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
_gc_time_stamp(0),
_surviving_young_words(NULL),
_in_cset_fast_test(NULL),
- _in_cset_fast_test_base(NULL)
-{
+ _in_cset_fast_test_base(NULL) {
_g1h = this; // To catch bugs.
if (_process_strong_tasks == NULL || !_process_strong_tasks->valid()) {
vm_exit_during_initialization("Failed necessary allocation.");
@@ -1371,9 +1378,19 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
}
for (int ap = 0; ap < GCAllocPurposeCount; ++ap) {
- _gc_alloc_regions[ap] = NULL;
- _gc_alloc_region_counts[ap] = 0;
+ _gc_alloc_regions[ap] = NULL;
+ _gc_alloc_region_counts[ap] = 0;
+ _retained_gc_alloc_regions[ap] = NULL;
+ // by default, we do not retain a GC alloc region for each ap;
+ // we'll override this, when appropriate, below
+ _retain_gc_alloc_region[ap] = false;
}
+
+ // We will try to remember the last half-full tenured region we
+ // allocated to at the end of a collection so that we can re-use it
+ // during the next collection.
+ _retain_gc_alloc_region[GCAllocForTenured] = true;
+
guarantee(_task_queues != NULL, "task_queues allocation failure.");
}
@@ -2119,15 +2136,7 @@ public:
bool doHeapRegion(HeapRegion* r) {
guarantee(_par || r->claim_value() == HeapRegion::InitialClaimValue,
"Should be unclaimed at verify points.");
- if (r->isHumongous()) {
- if (r->startsHumongous()) {
- // Verify the single H object.
- oop(r->bottom())->verify();
- size_t word_sz = oop(r->bottom())->size();
- guarantee(r->top() == r->bottom() + word_sz,
- "Only one object in a humongous region");
- }
- } else {
+ if (!r->continuesHumongous()) {
VerifyObjsInRegionClosure not_dead_yet_cl(r);
r->verify(_allow_dirty);
r->object_iterate(&not_dead_yet_cl);
@@ -2179,6 +2188,7 @@ public:
_g1h(g1h), _allow_dirty(allow_dirty) { }
void work(int worker_i) {
+ HandleMark hm;
VerifyRegionClosure blk(_allow_dirty, true);
_g1h->heap_region_par_iterate_chunked(&blk, worker_i,
HeapRegion::ParVerifyClaimValue);
@@ -2644,7 +2654,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) {
popular_region->set_popular_pending(false);
}
- release_gc_alloc_regions();
+ release_gc_alloc_regions(false /* totally */);
cleanup_surviving_young_words();
@@ -2697,6 +2707,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) {
if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
gclog_or_tty->print(" VerifyAfterGC:");
+ prepare_for_verify();
Universe::verify(false);
}
@@ -2735,6 +2746,10 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) {
void G1CollectedHeap::set_gc_alloc_region(int purpose, HeapRegion* r) {
assert(purpose >= 0 && purpose < GCAllocPurposeCount, "invalid purpose");
+ // make sure we don't call set_gc_alloc_region() multiple times on
+ // the same region
+ assert(r == NULL || !r->is_gc_alloc_region(),
+ "shouldn't already be a GC alloc region");
HeapWord* original_top = NULL;
if (r != NULL)
original_top = r->top();
@@ -2824,6 +2839,12 @@ void G1CollectedHeap::forget_alloc_region_list() {
while (_gc_alloc_region_list != NULL) {
HeapRegion* r = _gc_alloc_region_list;
assert(r->is_gc_alloc_region(), "Invariant.");
+ // We need HeapRegion::oops_on_card_seq_iterate_careful() to work on
+ // newly allocated data in order to be able to apply deferred updates
+ // before the GC is done for verification purposes (i.e to allow
+ // G1HRRSFlushLogBuffersOnVerify). It's safe thing to do after the
+ // collection.
+ r->ContiguousSpace::set_saved_mark();
_gc_alloc_region_list = r->next_gc_alloc_region();
r->set_next_gc_alloc_region(NULL);
r->set_is_gc_alloc_region(false);
@@ -2851,23 +2872,55 @@ bool G1CollectedHeap::check_gc_alloc_regions() {
}
void G1CollectedHeap::get_gc_alloc_regions() {
+ // First, let's check that the GC alloc region list is empty (it should)
+ assert(_gc_alloc_region_list == NULL, "invariant");
+
for (int ap = 0; ap < GCAllocPurposeCount; ++ap) {
+ assert(_gc_alloc_regions[ap] == NULL, "invariant");
+
// Create new GC alloc regions.
- HeapRegion* alloc_region = _gc_alloc_regions[ap];
- // Clear this alloc region, so that in case it turns out to be
- // unacceptable, we end up with no allocation region, rather than a bad
- // one.
- _gc_alloc_regions[ap] = NULL;
- if (alloc_region == NULL || alloc_region->in_collection_set()) {
- // Can't re-use old one. Allocate a new one.
+ HeapRegion* alloc_region = _retained_gc_alloc_regions[ap];
+ _retained_gc_alloc_regions[ap] = NULL;
+
+ if (alloc_region != NULL) {
+ assert(_retain_gc_alloc_region[ap], "only way to retain a GC region");
+
+ // let's make sure that the GC alloc region is not tagged as such
+ // outside a GC operation
+ assert(!alloc_region->is_gc_alloc_region(), "sanity");
+
+ if (alloc_region->in_collection_set() ||
+ alloc_region->top() == alloc_region->end() ||
+ alloc_region->top() == alloc_region->bottom()) {
+ // we will discard the current GC alloc region if it's in the
+ // collection set (it can happen!), if it's already full (no
+ // point in using it), or if it's empty (this means that it
+ // was emptied during a cleanup and it should be on the free
+ // list now).
+
+ alloc_region = NULL;
+ }
+ }
+
+ if (alloc_region == NULL) {
+ // we will get a new GC alloc region
alloc_region = newAllocRegionWithExpansion(ap, 0);
}
+
if (alloc_region != NULL) {
+ assert(_gc_alloc_regions[ap] == NULL, "pre-condition");
set_gc_alloc_region(ap, alloc_region);
}
+
+ assert(_gc_alloc_regions[ap] == NULL ||
+ _gc_alloc_regions[ap]->is_gc_alloc_region(),
+ "the GC alloc region should be tagged as such");
+ assert(_gc_alloc_regions[ap] == NULL ||
+ _gc_alloc_regions[ap] == _gc_alloc_region_list,
+ "the GC alloc region should be the same as the GC alloc list head");
}
// Set alternative regions for allocation purposes that have reached
- // thier limit.
+ // their limit.
for (int ap = 0; ap < GCAllocPurposeCount; ++ap) {
GCAllocPurpose alt_purpose = g1_policy()->alternative_purpose(ap);
if (_gc_alloc_regions[ap] == NULL && alt_purpose != ap) {
@@ -2877,28 +2930,56 @@ void G1CollectedHeap::get_gc_alloc_regions() {
assert(check_gc_alloc_regions(), "alloc regions messed up");
}
-void G1CollectedHeap::release_gc_alloc_regions() {
+void G1CollectedHeap::release_gc_alloc_regions(bool totally) {
// We keep a separate list of all regions that have been alloc regions in
- // the current collection pause. Forget that now.
+ // the current collection pause. Forget that now. This method will
+ // untag the GC alloc regions and tear down the GC alloc region
+ // list. It's desirable that no regions are tagged as GC alloc
+ // outside GCs.
forget_alloc_region_list();
// The current alloc regions contain objs that have survived
// collection. Make them no longer GC alloc regions.
for (int ap = 0; ap < GCAllocPurposeCount; ++ap) {
HeapRegion* r = _gc_alloc_regions[ap];
- if (r != NULL && r->is_empty()) {
- {
+ _retained_gc_alloc_regions[ap] = NULL;
+
+ if (r != NULL) {
+ // we retain nothing on _gc_alloc_regions between GCs
+ set_gc_alloc_region(ap, NULL);
+ _gc_alloc_region_counts[ap] = 0;
+
+ if (r->is_empty()) {
+ // we didn't actually allocate anything in it; let's just put
+ // it on the free list
MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag);
r->set_zero_fill_complete();
put_free_region_on_list_locked(r);
+ } else if (_retain_gc_alloc_region[ap] && !totally) {
+ // retain it so that we can use it at the beginning of the next GC
+ _retained_gc_alloc_regions[ap] = r;
}
}
- // set_gc_alloc_region will also NULLify all aliases to the region
- set_gc_alloc_region(ap, NULL);
- _gc_alloc_region_counts[ap] = 0;
}
}
+#ifndef PRODUCT
+// Useful for debugging
+
+void G1CollectedHeap::print_gc_alloc_regions() {
+ gclog_or_tty->print_cr("GC alloc regions");
+ for (int ap = 0; ap < GCAllocPurposeCount; ++ap) {
+ HeapRegion* r = _gc_alloc_regions[ap];
+ if (r == NULL) {
+ gclog_or_tty->print_cr(" %2d : "PTR_FORMAT, ap, NULL);
+ } else {
+ gclog_or_tty->print_cr(" %2d : "PTR_FORMAT" "SIZE_FORMAT,
+ ap, r->bottom(), r->used());
+ }
+ }
+}
+#endif // PRODUCT
+
void G1CollectedHeap::init_for_evac_failure(OopsInHeapRegionClosure* cl) {
_drain_in_progress = false;
set_evac_failure_closure(cl);
@@ -3658,7 +3739,9 @@ protected:
CardTableModRefBS* ctbs() { return _ct_bs; }
void immediate_rs_update(HeapRegion* from, oop* p, int tid) {
- _g1_rem->par_write_ref(from, p, tid);
+ if (!from->is_survivor()) {
+ _g1_rem->par_write_ref(from, p, tid);
+ }
}
void deferred_rs_update(HeapRegion* from, oop* p, int tid) {
diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
index 4ac3cf220..e67e4d4ca 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
@@ -172,7 +172,6 @@ private:
NumAPIs = HeapRegion::MaxAge
};
-
// The one and only G1CollectedHeap, so static functions can find it.
static G1CollectedHeap* _g1h;
@@ -217,11 +216,20 @@ private:
// Postcondition: cur_alloc_region == NULL.
void abandon_cur_alloc_region();
+ void abandon_gc_alloc_regions();
// The to-space memory regions into which objects are being copied during
// a GC.
HeapRegion* _gc_alloc_regions[GCAllocPurposeCount];
size_t _gc_alloc_region_counts[GCAllocPurposeCount];
+ // These are the regions, one per GCAllocPurpose, that are half-full
+ // at the end of a collection and that we want to reuse during the
+ // next collection.
+ HeapRegion* _retained_gc_alloc_regions[GCAllocPurposeCount];
+ // This specifies whether we will keep the last half-full region at
+ // the end of a collection so that it can be reused during the next
+ // collection (this is specified per GCAllocPurpose)
+ bool _retain_gc_alloc_region[GCAllocPurposeCount];
// A list of the regions that have been set to be alloc regions in the
// current collection.
@@ -589,8 +597,21 @@ protected:
// Ensure that the relevant gc_alloc regions are set.
void get_gc_alloc_regions();
- // We're done with GC alloc regions; release them, as appropriate.
- void release_gc_alloc_regions();
+ // We're done with GC alloc regions. We are going to tear down the
+ // gc alloc list and remove the gc alloc tag from all the regions on
+ // that list. However, we will also retain the last (i.e., the one
+ // that is half-full) GC alloc region, per GCAllocPurpose, for
+ // possible reuse during the next collection, provided
+ // _retain_gc_alloc_region[] indicates that it should be the
+ // case. Said regions are kept in the _retained_gc_alloc_regions[]
+ // array. If the parameter totally is set, we will not retain any
+ // regions, irrespective of what _retain_gc_alloc_region[]
+ // indicates.
+ void release_gc_alloc_regions(bool totally);
+#ifndef PRODUCT
+ // Useful for debugging.
+ void print_gc_alloc_regions();
+#endif // !PRODUCT
// ("Weak") Reference processing support
ReferenceProcessor* _ref_processor;
diff --git a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp
index 5de297a4e..d66e382f9 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp
@@ -1087,6 +1087,7 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec,
assert(_g1->used_regions() == _g1->recalculate_used_regions(),
"sanity");
+ assert(_g1->used() == _g1->recalculate_used(), "sanity");
double s_w_t_ms = (start_time_sec - _stop_world_start) * 1000.0;
_all_stop_world_times_ms->add(s_w_t_ms);
diff --git a/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/src/share/vm/gc_implementation/g1/g1RemSet.cpp
index aff031a73..3c5a4a5b1 100644
--- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp
+++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp
@@ -502,14 +502,17 @@ HRInto_G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
}
if (ParallelGCThreads > 0) {
- // This is a temporary change to serialize the update and scanning
- // of remembered sets. There are some race conditions when this is
- // done in parallel and they are causing failures. When we resolve
- // said race conditions, we'll revert back to parallel remembered
- // set updating and scanning. See CRs 6677707 and 6677708.
- if (worker_i == 0) {
+ // The two flags below were introduced temporarily to serialize
+ // the updating and scanning of remembered sets. There are some
+ // race conditions when these two operations are done in parallel
+ // and they are causing failures. When we resolve said race
+ // conditions, we'll revert back to parallel remembered set
+ // updating and scanning. See CRs 6677707 and 6677708.
+ if (G1EnableParallelRSetUpdating || (worker_i == 0)) {
updateRS(worker_i);
scanNewRefsRS(oc, worker_i);
+ }
+ if (G1EnableParallelRSetScanning || (worker_i == 0)) {
scanRS(oc, worker_i);
}
} else {
@@ -716,8 +719,7 @@ public:
bool doHeapRegion(HeapRegion* r) {
if (!r->in_collection_set() &&
!r->continuesHumongous() &&
- !r->is_young() &&
- !r->is_survivor()) {
+ !r->is_young()) {
_update_rs_oop_cl.set_from(r);
UpdateRSObjectClosure update_rs_obj_cl(&_update_rs_oop_cl);
@@ -854,7 +856,7 @@ void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) {
// before all the cards on the region are dirtied. This is unlikely,
// and it doesn't happen often, but it can happen. So, the extra
// check below filters out those cards.
- if (r->is_young() || r->is_survivor()) {
+ if (r->is_young()) {
return;
}
// While we are processing RSet buffers during the collection, we
@@ -1025,7 +1027,9 @@ void HRInto_G1RemSet::print_summary_info() {
}
}
void HRInto_G1RemSet::prepare_for_verify() {
- if (G1HRRSFlushLogBuffersOnVerify && VerifyBeforeGC && !_g1->full_collection()) {
+ if (G1HRRSFlushLogBuffersOnVerify &&
+ (VerifyBeforeGC || VerifyAfterGC)
+ && !_g1->full_collection()) {
cleanupHRRS();
_g1->set_refine_cte_cl_concurrency(false);
if (SafepointSynchronize::is_at_safepoint()) {
@@ -1036,5 +1040,7 @@ void HRInto_G1RemSet::prepare_for_verify() {
_cg1r->set_use_cache(false);
updateRS(0);
_cg1r->set_use_cache(cg1r_use_cache);
+
+ assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed");
}
}
diff --git a/src/share/vm/gc_implementation/g1/g1_globals.hpp b/src/share/vm/gc_implementation/g1/g1_globals.hpp
index 98d512c9e..2b7a984a3 100644
--- a/src/share/vm/gc_implementation/g1/g1_globals.hpp
+++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp
@@ -295,6 +295,14 @@
\
product(uintx, G1FixedSurvivorSpaceSize, 0, \
"If non-0 is the size of the G1 survivor space, " \
- "otherwise SurvivorRatio is used to determine the size")
+ "otherwise SurvivorRatio is used to determine the size") \
+ \
+ experimental(bool, G1EnableParallelRSetUpdating, false, \
+ "Enables the parallelization of remembered set updating " \
+ "during evacuation pauses") \
+ \
+ experimental(bool, G1EnableParallelRSetScanning, false, \
+ "Enables the parallelization of remembered set scanning " \
+ "during evacuation pauses")
G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG)
diff --git a/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp b/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp
index 89331a81b..dddb3bb7d 100644
--- a/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp
+++ b/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp
@@ -63,9 +63,8 @@ public:
// return NULL.
HeapWord* allocate(size_t word_sz) {
HeapWord* res = _top;
- HeapWord* new_top = _top + word_sz;
- if (new_top <= _end) {
- _top = new_top;
+ if (pointer_delta(_end, _top) >= word_sz) {
+ _top = _top + word_sz;
return res;
} else {
return NULL;
@@ -75,10 +74,9 @@ public:
// Undo the last allocation in the buffer, which is required to be of the
// "obj" of the given "word_sz".
void undo_allocation(HeapWord* obj, size_t word_sz) {
- assert(_top - word_sz >= _bottom
- && _top - word_sz == obj,
- "Bad undo_allocation");
- _top = _top - word_sz;
+ assert(pointer_delta(_top, _bottom) >= word_sz, "Bad undo");
+ assert(pointer_delta(_top, obj) == word_sz, "Bad undo");
+ _top = obj;
}
// The total (word) size of the buffer, including both allocated and