diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index b906ae2ca0b96..c6bcbd18a1683 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -465,11 +465,17 @@ void ShenandoahBarrierSetC2::post_barrier(GraphKit* kit, } if (ReduceInitialCardMarks && obj == kit->just_allocated_object(kit->control())) { - // We can skip marks on a freshly-allocated object in Eden. - // Keep this code in sync with new_deferred_store_barrier() in runtime.cpp. - // That routine informs GC to take appropriate compensating steps, - // upon a slow-path allocation, so as to make this card-mark - // elision safe. + // We use card marks to track old to young references in Generational Shenandoah; + // see flag ShenandoahCardBarrier above. + // Objects are always allocated in the young generation and initialized + // before they are promoted. There's always a safepoint (e.g. at final mark) + // before an object is promoted from young to old. Promotion entails dirtying of + // the cards backing promoted objects, so they will be guaranteed to be scanned + // at the next remembered set scan of the old generation. + // Thus, we can safely skip card-marking of initializing stores on a + // freshly-allocated object. If any of the assumptions above change in + // the future, this code will need to be re-examined; see check in + // ShenandoahCardBarrier::on_slowpath_allocation_exit(). return; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp index 38e363664dc3a..62067bccb1ed7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp @@ -88,6 +88,14 @@ bool ShenandoahBarrierSet::need_keep_alive_barrier(DecoratorSet decorators, Basi return (on_weak_ref || unknown) && keep_alive; } +void ShenandoahBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) { +#if COMPILER2_OR_JVMCI + assert(!ReduceInitialCardMarks || !ShenandoahCardBarrier || ShenandoahGenerationalHeap::heap()->is_in_young(new_obj), + "Error: losing card mark on initialzing store to old gen"); +#endif // COMPILER2_OR_JVMCI + assert(thread->deferred_card_mark().is_empty(), "We don't use this"); +} + void ShenandoahBarrierSet::on_thread_create(Thread* thread) { // Create thread local data ShenandoahThreadLocalData::create(thread); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp index 8d1dc92761a59..0d38cc757f44a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp @@ -77,17 +77,21 @@ class ShenandoahBarrierSet: public BarrierSet { return (decorators & IN_NATIVE) != 0; } - void print_on(outputStream* st) const; + void print_on(outputStream* st) const override; template inline void arraycopy_barrier(T* src, T* dst, size_t count); inline void clone_barrier(oop src); void clone_barrier_runtime(oop src); - virtual void on_thread_create(Thread* thread); - virtual void on_thread_destroy(Thread* thread); - virtual void on_thread_attach(Thread* thread); - virtual void on_thread_detach(Thread* thread); + // Support for optimizing compilers to call the barrier set on slow path allocations + // that did not enter a TLAB. Used for e.g. ReduceInitialCardMarks to take any + // compensating actions to restore card-marks that might otherwise be incorrectly elided. + void on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) override; + void on_thread_create(Thread* thread) override; + void on_thread_destroy(Thread* thread) override; + void on_thread_attach(Thread* thread) override; + void on_thread_detach(Thread* thread) override; static inline oop resolve_forwarded_not_null(oop p); static inline oop resolve_forwarded_not_null_mutator(oop p);