8260267: ZGC: Reduce mark stack usage

Co-authored-by: Wang Chao <wchao@openjdk.org>
Co-authored-by: Hui Shi <hshi@openjdk.org>
Reviewed-by: sjohanss, ayang
This commit is contained in:
Per Liden 2021-05-20 11:32:48 +00:00
parent f979523a69
commit aba2265682
20 changed files with 255 additions and 104 deletions

@ -26,6 +26,7 @@
#include "gc/z/zBarrier.inline.hpp"
#include "gc/z/zHeap.inline.hpp"
#include "gc/z/zOop.inline.hpp"
#include "gc/z/zThread.inline.hpp"
#include "memory/iterator.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/safepoint.hpp"
@ -64,7 +65,7 @@ bool ZBarrier::should_mark_through(uintptr_t addr) {
return true;
}
template <bool follow, bool finalizable, bool publish>
template <bool gc_thread, bool follow, bool finalizable, bool publish>
uintptr_t ZBarrier::mark(uintptr_t addr) {
uintptr_t good_addr;
@ -81,7 +82,7 @@ uintptr_t ZBarrier::mark(uintptr_t addr) {
// Mark
if (should_mark_through<finalizable>(addr)) {
ZHeap::heap()->mark_object<follow, finalizable, publish>(good_addr);
ZHeap::heap()->mark_object<gc_thread, follow, finalizable, publish>(good_addr);
}
if (finalizable) {
@ -111,11 +112,11 @@ uintptr_t ZBarrier::relocate(uintptr_t addr) {
}
uintptr_t ZBarrier::relocate_or_mark(uintptr_t addr) {
return during_relocate() ? relocate(addr) : mark<Follow, Strong, Publish>(addr);
return during_relocate() ? relocate(addr) : mark<AnyThread, Follow, Strong, Publish>(addr);
}
uintptr_t ZBarrier::relocate_or_mark_no_follow(uintptr_t addr) {
return during_relocate() ? relocate(addr) : mark<DontFollow, Strong, Publish>(addr);
return during_relocate() ? relocate(addr) : mark<AnyThread, DontFollow, Strong, Publish>(addr);
}
uintptr_t ZBarrier::relocate_or_remap(uintptr_t addr) {
@ -169,6 +170,13 @@ uintptr_t ZBarrier::weak_load_barrier_on_phantom_oop_slow_path(uintptr_t addr) {
//
// Keep alive barrier
//
uintptr_t ZBarrier::keep_alive_barrier_on_oop_slow_path(uintptr_t addr) {
assert(during_mark(), "Invalid phase");
// Mark
return mark<AnyThread, Follow, Strong, Overflow>(addr);
}
uintptr_t ZBarrier::keep_alive_barrier_on_weak_oop_slow_path(uintptr_t addr) {
const uintptr_t good_addr = weak_load_barrier_on_oop_slow_path(addr);
assert(ZHeap::heap()->is_object_strongly_live(good_addr), "Should be live");
@ -186,16 +194,18 @@ uintptr_t ZBarrier::keep_alive_barrier_on_phantom_oop_slow_path(uintptr_t addr)
//
uintptr_t ZBarrier::mark_barrier_on_oop_slow_path(uintptr_t addr) {
assert(during_mark(), "Invalid phase");
assert(ZThread::is_worker(), "Invalid thread");
// Mark
return mark<Follow, Strong, Overflow>(addr);
return mark<GCThread, Follow, Strong, Overflow>(addr);
}
uintptr_t ZBarrier::mark_barrier_on_finalizable_oop_slow_path(uintptr_t addr) {
assert(during_mark(), "Invalid phase");
assert(ZThread::is_worker(), "Invalid thread");
// Mark
return mark<Follow, Finalizable, Overflow>(addr);
return mark<GCThread, Follow, Finalizable, Overflow>(addr);
}
//

@ -33,6 +33,9 @@ typedef uintptr_t (*ZBarrierSlowPath)(uintptr_t);
class ZBarrier : public AllStatic {
private:
static const bool GCThread = true;
static const bool AnyThread = false;
static const bool Follow = true;
static const bool DontFollow = false;
@ -55,7 +58,7 @@ private:
static bool during_mark();
static bool during_relocate();
template <bool finalizable> static bool should_mark_through(uintptr_t addr);
template <bool follow, bool finalizable, bool publish> static uintptr_t mark(uintptr_t addr);
template <bool gc_thread, bool follow, bool finalizable, bool publish> static uintptr_t mark(uintptr_t addr);
static uintptr_t remap(uintptr_t addr);
static uintptr_t relocate(uintptr_t addr);
static uintptr_t relocate_or_mark(uintptr_t addr);
@ -69,6 +72,7 @@ private:
static uintptr_t weak_load_barrier_on_weak_oop_slow_path(uintptr_t addr);
static uintptr_t weak_load_barrier_on_phantom_oop_slow_path(uintptr_t addr);
static uintptr_t keep_alive_barrier_on_oop_slow_path(uintptr_t addr);
static uintptr_t keep_alive_barrier_on_weak_oop_slow_path(uintptr_t addr);
static uintptr_t keep_alive_barrier_on_phantom_oop_slow_path(uintptr_t addr);
@ -104,10 +108,10 @@ public:
static bool is_alive_barrier_on_phantom_oop(oop o);
// Keep alive barrier
static void keep_alive_barrier_on_oop(oop o);
static void keep_alive_barrier_on_weak_oop_field(volatile oop* p);
static void keep_alive_barrier_on_phantom_oop_field(volatile oop* p);
static void keep_alive_barrier_on_phantom_root_oop_field(oop* p);
static void keep_alive_barrier_on_oop(oop o);
// Mark barrier
static void mark_barrier_on_oop_field(volatile oop* p, bool finalizable);

@ -364,7 +364,7 @@ inline void ZBarrier::keep_alive_barrier_on_oop(oop o) {
assert(ZAddress::is_good(addr), "Invalid address");
if (during_mark()) {
mark_barrier_on_oop_slow_path(addr);
keep_alive_barrier_on_oop_slow_path(addr);
}
}

@ -44,6 +44,7 @@ static const ZStatPhaseCycle ZPhaseCycle("Garbage Collection Cycle");
static const ZStatPhasePause ZPhasePauseMarkStart("Pause Mark Start");
static const ZStatPhaseConcurrent ZPhaseConcurrentMark("Concurrent Mark");
static const ZStatPhaseConcurrent ZPhaseConcurrentMarkContinue("Concurrent Mark Continue");
static const ZStatPhaseConcurrent ZPhaseConcurrentMarkFree("Concurrent Mark Free");
static const ZStatPhasePause ZPhasePauseMarkEnd("Pause Mark End");
static const ZStatPhaseConcurrent ZPhaseConcurrentProcessNonStrongReferences("Concurrent Process Non-Strong References");
static const ZStatPhaseConcurrent ZPhaseConcurrentResetRelocationSet("Concurrent Reset Relocation Set");
@ -322,6 +323,11 @@ void ZDriver::concurrent_mark_continue() {
ZHeap::heap()->mark(false /* initial */);
}
void ZDriver::concurrent_mark_free() {
ZStatTimer timer(ZPhaseConcurrentMarkFree);
ZHeap::heap()->mark_free();
}
void ZDriver::concurrent_process_non_strong_references() {
ZStatTimer timer(ZPhaseConcurrentProcessNonStrongReferences);
ZBreakpoint::at_after_reference_processing_started();
@ -426,22 +432,25 @@ void ZDriver::gc(GCCause::Cause cause) {
concurrent(mark_continue);
}
// Phase 4: Concurrent Process Non-Strong References
// Phase 4: Concurrent Mark Free
concurrent(mark_free);
// Phase 5: Concurrent Process Non-Strong References
concurrent(process_non_strong_references);
// Phase 5: Concurrent Reset Relocation Set
// Phase 6: Concurrent Reset Relocation Set
concurrent(reset_relocation_set);
// Phase 6: Pause Verify
// Phase 7: Pause Verify
pause_verify();
// Phase 7: Concurrent Select Relocation Set
// Phase 8: Concurrent Select Relocation Set
concurrent(select_relocation_set);
// Phase 8: Pause Relocate Start
// Phase 9: Pause Relocate Start
pause_relocate_start();
// Phase 9: Concurrent Relocate
// Phase 10: Concurrent Relocate
concurrent(relocate);
}

@ -41,6 +41,7 @@ private:
void concurrent_mark();
bool pause_mark_end();
void concurrent_mark_continue();
void concurrent_mark_free();
void concurrent_process_non_strong_references();
void concurrent_reset_relocation_set();
void pause_verify();

@ -284,6 +284,10 @@ bool ZHeap::mark_end() {
return true;
}
void ZHeap::mark_free() {
_mark.free();
}
void ZHeap::keep_alive(oop obj) {
ZBarrier::keep_alive_barrier_on_oop(obj);
}

@ -122,11 +122,12 @@ public:
// Marking
bool is_object_live(uintptr_t addr) const;
bool is_object_strongly_live(uintptr_t addr) const;
template <bool follow, bool finalizable, bool publish> void mark_object(uintptr_t addr);
template <bool gc_thread, bool follow, bool finalizable, bool publish> void mark_object(uintptr_t addr);
void mark_start();
void mark(bool initial);
void mark_flush_and_free(Thread* thread);
bool mark_end();
void mark_free();
void keep_alive(oop obj);
// Relocation set

@ -57,10 +57,10 @@ inline bool ZHeap::is_object_strongly_live(uintptr_t addr) const {
return page->is_object_strongly_live(addr);
}
template <bool follow, bool finalizable, bool publish>
template <bool gc_thread, bool follow, bool finalizable, bool publish>
inline void ZHeap::mark_object(uintptr_t addr) {
assert(ZGlobalPhase == ZPhaseMark, "Mark not allowed");
_mark.mark_object<follow, finalizable, publish>(addr);
_mark.mark_object<gc_thread, follow, finalizable, publish>(addr);
}
inline uintptr_t ZHeap::alloc_tlab(size_t size) {

@ -278,28 +278,6 @@ void ZMark::follow_object(oop obj, bool finalizable) {
}
}
bool ZMark::try_mark_object(ZMarkCache* cache, uintptr_t addr, bool finalizable) {
ZPage* const page = _page_table->get(addr);
if (page->is_allocating()) {
// Newly allocated objects are implicitly marked
return false;
}
// Try mark object
bool inc_live = false;
const bool success = page->mark_object(addr, finalizable, inc_live);
if (inc_live) {
// Update live objects/bytes for page. We use the aligned object
// size since that is the actual number of bytes used on the page
// and alignment paddings can never be reclaimed.
const size_t size = ZUtils::object_size(addr);
const size_t aligned_size = align_up(size, page->object_alignment());
cache->inc_live(page, aligned_size);
}
return success;
}
void ZMark::mark_and_follow(ZMarkCache* cache, ZMarkStackEntry entry) {
// Decode flags
const bool finalizable = entry.finalizable();
@ -310,24 +288,38 @@ void ZMark::mark_and_follow(ZMarkCache* cache, ZMarkStackEntry entry) {
return;
}
// Decode object address and follow flag
// Decode object address and additional flags
const uintptr_t addr = entry.object_address();
const bool mark = entry.mark();
bool inc_live = entry.inc_live();
const bool follow = entry.follow();
if (!try_mark_object(cache, addr, finalizable)) {
ZPage* const page = _page_table->get(addr);
assert(page->is_relocatable(), "Invalid page state");
// Mark
if (mark && !page->mark_object(addr, finalizable, inc_live)) {
// Already marked
return;
}
if (is_array(addr)) {
// Decode follow flag
const bool follow = entry.follow();
// Increment live
if (inc_live) {
// Update live objects/bytes for page. We use the aligned object
// size since that is the actual number of bytes used on the page
// and alignment paddings can never be reclaimed.
const size_t size = ZUtils::object_size(addr);
const size_t aligned_size = align_up(size, page->object_alignment());
cache->inc_live(page, aligned_size);
}
// The follow flag is currently only relevant for object arrays
if (follow) {
// Follow
if (follow) {
if (is_array(addr)) {
follow_array_object(objArrayOop(ZOop::from_address(addr)), finalizable);
} else {
follow_object(ZOop::from_address(addr), finalizable);
}
} else {
follow_object(ZOop::from_address(addr), finalizable);
}
}
@ -776,6 +768,14 @@ bool ZMark::end() {
return true;
}
void ZMark::free() {
// Free any unused mark stack space
_allocator.free();
// Update statistics
ZStatMark::set_at_mark_free(_allocator.size());
}
void ZMark::flush_and_free() {
Thread* const thread = Thread::current();
flush_and_free(thread);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -64,7 +64,6 @@ private:
void follow_partial_array(ZMarkStackEntry entry, bool finalizable);
void follow_array_object(objArrayOop obj, bool finalizable);
void follow_object(oop obj, bool finalizable);
bool try_mark_object(ZMarkCache* cache, uintptr_t addr, bool finalizable);
void mark_and_follow(ZMarkCache* cache, ZMarkStackEntry entry);
template <typename T> bool drain(ZMarkStripe* stripe,
@ -101,11 +100,12 @@ public:
bool is_initialized() const;
template <bool follow, bool finalizable, bool publish> void mark_object(uintptr_t addr);
template <bool gc_thread, bool follow, bool finalizable, bool publish> void mark_object(uintptr_t addr);
void start();
void mark(bool initial);
bool end();
void free();
void flush_and_free();
bool flush_and_free(Thread* thread);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,17 +27,52 @@
#include "gc/z/zAddress.inline.hpp"
#include "gc/z/zMark.hpp"
#include "gc/z/zMarkStack.inline.hpp"
#include "gc/z/zPage.inline.hpp"
#include "gc/z/zPageTable.inline.hpp"
#include "gc/z/zThreadLocalData.hpp"
#include "runtime/thread.hpp"
#include "utilities/debug.hpp"
template <bool follow, bool finalizable, bool publish>
// Marking before pushing helps reduce mark stack memory usage. However,
// we only mark before pushing in GC threads to avoid burdening Java threads
// with writing to, and potentially first having to clear, mark bitmaps.
//
// It's also worth noting that while marking an object can be done at any
// time in the marking phase, following an object can only be done after
// root processing has called ClassLoaderDataGraph::clear_claimed_marks(),
// since it otherwise would interact badly with claiming of CLDs.
template <bool gc_thread, bool follow, bool finalizable, bool publish>
inline void ZMark::mark_object(uintptr_t addr) {
assert(ZAddress::is_marked(addr), "Should be marked");
ZPage* const page = _page_table->get(addr);
if (page->is_allocating()) {
// Already implicitly marked
return;
}
const bool mark_before_push = gc_thread;
bool inc_live = false;
if (mark_before_push) {
// Try mark object
if (!page->mark_object(addr, finalizable, inc_live)) {
// Already marked
return;
}
} else {
// Don't push if already marked
if (page->is_object_marked<finalizable>(addr)) {
// Already marked
return;
}
}
// Push
ZMarkThreadLocalStacks* const stacks = ZThreadLocalData::stacks(Thread::current());
ZMarkStripe* const stripe = _stripes.stripe_for_addr(addr);
ZMarkStackEntry entry(addr, follow, finalizable);
ZMarkStackEntry entry(addr, !mark_before_push, inc_live, follow, finalizable);
stacks->push(&_allocator, &_stripes, stripe, entry, publish);
}

@ -64,6 +64,8 @@ public:
void push(T* stack);
T* pop();
void clear();
};
using ZMarkStack = ZStack<ZMarkStackEntry, ZMarkStackSlots>;

@ -156,6 +156,11 @@ inline T* ZStackList<T>::pop() {
}
}
template <typename T>
inline void ZStackList<T>::clear() {
_head = encode_versioned_pointer(NULL, 0);
}
inline bool ZMarkStripe::is_empty() const {
return _published.is_empty() && _overflowed.is_empty();
}

@ -54,12 +54,63 @@ ZMarkStackSpace::ZMarkStackSpace() :
// Register mark stack space start
ZMarkStackSpaceStart = _start;
// Prime space
_end += expand_space();
}
bool ZMarkStackSpace::is_initialized() const {
return _start != 0;
}
size_t ZMarkStackSpace::size() const {
return _end - _start;
}
size_t ZMarkStackSpace::used() const {
return _top - _start;
}
size_t ZMarkStackSpace::expand_space() {
const size_t expand_size = ZMarkStackSpaceExpandSize;
const size_t old_size = size();
const size_t new_size = old_size + expand_size;
if (new_size > ZMarkStackSpaceLimit) {
// Expansion limit reached. This is a fatal error since we
// currently can't recover from running out of mark stack space.
fatal("Mark stack space exhausted. Use -XX:ZMarkStackSpaceLimit=<size> to increase the "
"maximum number of bytes allocated for mark stacks. Current limit is " SIZE_FORMAT "M.",
ZMarkStackSpaceLimit / M);
}
log_debug(gc, marking)("Expanding mark stack space: " SIZE_FORMAT "M->" SIZE_FORMAT "M",
old_size / M, new_size / M);
// Expand
os::commit_memory_or_exit((char*)_end, expand_size, false /* executable */, "Mark stack space");
return expand_size;
}
size_t ZMarkStackSpace::shrink_space() {
// Shrink to what is currently used
const size_t old_size = size();
const size_t new_size = align_up(used(), ZMarkStackSpaceExpandSize);
const size_t shrink_size = old_size - new_size;
if (shrink_size > 0) {
// Shrink
log_debug(gc, marking)("Shrinking mark stack space: " SIZE_FORMAT "M->" SIZE_FORMAT "M",
old_size / M, new_size / M);
const uintptr_t shrink_start = _end - shrink_size;
os::uncommit_memory((char*)shrink_start, shrink_size, false /* executable */);
}
return shrink_size;
}
uintptr_t ZMarkStackSpace::alloc_space(size_t size) {
uintptr_t top = Atomic::load(&_top);
@ -91,23 +142,8 @@ uintptr_t ZMarkStackSpace::expand_and_alloc_space(size_t size) {
return addr;
}
// Check expansion limit
const size_t expand_size = ZMarkStackSpaceExpandSize;
const size_t old_size = _end - _start;
const size_t new_size = old_size + expand_size;
if (new_size > ZMarkStackSpaceLimit) {
// Expansion limit reached. This is a fatal error since we
// currently can't recover from running out of mark stack space.
fatal("Mark stack space exhausted. Use -XX:ZMarkStackSpaceLimit=<size> to increase the "
"maximum number of bytes allocated for mark stacks. Current limit is " SIZE_FORMAT "M.",
ZMarkStackSpaceLimit / M);
}
log_debug(gc, marking)("Expanding mark stack space: " SIZE_FORMAT "M->" SIZE_FORMAT "M",
old_size / M, new_size / M);
// Expand
os::commit_memory_or_exit((char*)_end, expand_size, false /* executable */, "Mark stack space");
const size_t expand_size = expand_space();
// Increment top before end to make sure another
// thread can't steal out newly expanded space.
@ -118,6 +154,8 @@ uintptr_t ZMarkStackSpace::expand_and_alloc_space(size_t size) {
}
uintptr_t ZMarkStackSpace::alloc(size_t size) {
assert(size <= ZMarkStackSpaceExpandSize, "Invalid size");
const uintptr_t addr = alloc_space(size);
if (addr != 0) {
return addr;
@ -126,26 +164,21 @@ uintptr_t ZMarkStackSpace::alloc(size_t size) {
return expand_and_alloc_space(size);
}
void ZMarkStackSpace::free() {
_end -= shrink_space();
_top = _start;
}
ZMarkStackAllocator::ZMarkStackAllocator() :
_freelist(),
_space() {
// Prime free list to avoid an immediate space
// expansion when marking starts.
if (_space.is_initialized()) {
prime_freelist();
}
}
_space() {}
bool ZMarkStackAllocator::is_initialized() const {
return _space.is_initialized();
}
void ZMarkStackAllocator::prime_freelist() {
for (size_t size = 0; size < ZMarkStackSpaceExpandSize; size += ZMarkStackMagazineSize) {
const uintptr_t addr = _space.alloc(ZMarkStackMagazineSize);
ZMarkStackMagazine* const magazine = create_magazine_from_space(addr, ZMarkStackMagazineSize);
free_magazine(magazine);
}
size_t ZMarkStackAllocator::size() const {
return _space.size();
}
ZMarkStackMagazine* ZMarkStackAllocator::create_magazine_from_space(uintptr_t addr, size_t size) {
@ -181,3 +214,8 @@ ZMarkStackMagazine* ZMarkStackAllocator::alloc_magazine() {
void ZMarkStackAllocator::free_magazine(ZMarkStackMagazine* magazine) {
_freelist.push(magazine);
}
void ZMarkStackAllocator::free() {
_freelist.clear();
_space.free();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,7 +35,10 @@ private:
volatile uintptr_t _top;
volatile uintptr_t _end;
void expand();
size_t used() const;
size_t expand_space();
size_t shrink_space();
uintptr_t alloc_space(size_t size);
uintptr_t expand_and_alloc_space(size_t size);
@ -45,7 +48,10 @@ public:
bool is_initialized() const;
size_t size() const;
uintptr_t alloc(size_t size);
void free();
};
class ZMarkStackAllocator {
@ -53,7 +59,6 @@ private:
ZCACHE_ALIGNED ZMarkStackMagazineList _freelist;
ZCACHE_ALIGNED ZMarkStackSpace _space;
void prime_freelist();
ZMarkStackMagazine* create_magazine_from_space(uintptr_t addr, size_t size);
public:
@ -61,8 +66,12 @@ public:
bool is_initialized() const;
size_t size() const;
ZMarkStackMagazine* alloc_magazine();
void free_magazine(ZMarkStackMagazine* magazine);
void free();
};
#endif // SHARE_GC_Z_ZMARKSTACKALLOCATOR_HPP

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,18 +35,22 @@
// ------------
//
// 6
// 3 3 2 1 0
// +--------------------------------------------------------------------+-+-+-+
// |11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111|1|1|1|
// +--------------------------------------------------------------------+-+-+-+
// | | | |
// | 2-2 Follow Flag (1-bit) * | |
// | | |
// | 1-1 Partial Array Flag (1-bit) * |
// | |
// | 0-0 Final Flag (1-bit) *
// 3 5 4 3 2 1 0
// +------------------------------------------------------------------+-+-+-+-+-+
// |11111111 11111111 11111111 11111111 11111111 11111111 11111111 111|1|1|1|1|1|
// +------------------------------------------------------------------+-+-+-+-+-+
// | | | | | |
// | 4-4 Mark Flag (1-bit) * | | | |
// | | | | |
// | 3-3 Increment Live Flag (1-bit) * | | |
// | | | |
// | 2-2 Follow Flag (1-bit) * | |
// | | |
// | 1-1 Partial Array Flag (1-bit) * |
// | |
// | 0-0 Final Flag (1-bit) *
// |
// * 63-3 Object Address (61-bits)
// * 63-5 Object Address (59-bits)
//
//
// Partial array entry
@ -72,7 +76,9 @@ private:
typedef ZBitField<uint64_t, bool, 0, 1> field_finalizable;
typedef ZBitField<uint64_t, bool, 1, 1> field_partial_array;
typedef ZBitField<uint64_t, bool, 2, 1> field_follow;
typedef ZBitField<uint64_t, uintptr_t, 3, 61> field_object_address;
typedef ZBitField<uint64_t, bool, 3, 1> field_inc_live;
typedef ZBitField<uint64_t, bool, 4, 1> field_mark;
typedef ZBitField<uint64_t, uintptr_t, 5, 59> field_object_address;
typedef ZBitField<uint64_t, size_t, 2, 30> field_partial_array_length;
typedef ZBitField<uint64_t, size_t, 32, 32> field_partial_array_offset;
@ -86,8 +92,10 @@ public:
// what _entry is initialized to.
}
ZMarkStackEntry(uintptr_t object_address, bool follow, bool finalizable) :
ZMarkStackEntry(uintptr_t object_address, bool mark, bool inc_live, bool follow, bool finalizable) :
_entry(field_object_address::encode(object_address) |
field_mark::encode(mark) |
field_inc_live::encode(inc_live) |
field_follow::encode(follow) |
field_partial_array::encode(false) |
field_finalizable::encode(finalizable)) {}
@ -118,6 +126,14 @@ public:
return field_follow::decode(_entry);
}
bool inc_live() const {
return field_inc_live::decode(_entry);
}
bool mark() const {
return field_mark::decode(_entry);
}
uintptr_t object_address() const {
return field_object_address::decode(_entry);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -92,6 +92,7 @@ public:
bool is_in(uintptr_t addr) const;
bool is_marked() const;
template <bool finalizable> bool is_object_marked(uintptr_t addr) const;
bool is_object_live(uintptr_t addr) const;
bool is_object_strongly_live(uintptr_t addr) const;
bool mark_object(uintptr_t addr, bool finalizable, bool& inc_live);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -171,15 +171,22 @@ inline bool ZPage::is_marked() const {
}
inline bool ZPage::is_object_marked(uintptr_t addr) const {
assert(is_relocatable(), "Invalid page state");
const size_t index = ((ZAddress::offset(addr) - start()) >> object_alignment_shift()) * 2;
return _livemap.get(index);
}
inline bool ZPage::is_object_strongly_marked(uintptr_t addr) const {
assert(is_relocatable(), "Invalid page state");
const size_t index = ((ZAddress::offset(addr) - start()) >> object_alignment_shift()) * 2;
return _livemap.get(index + 1);
}
template <bool finalizable>
inline bool ZPage::is_object_marked(uintptr_t addr) const {
return finalizable ? is_object_marked(addr) : is_object_strongly_marked(addr);
}
inline bool ZPage::is_object_live(uintptr_t addr) const {
return is_allocating() || is_object_marked(addr);
}

@ -1125,6 +1125,7 @@ size_t ZStatMark::_nproactiveflush;
size_t ZStatMark::_nterminateflush;
size_t ZStatMark::_ntrycomplete;
size_t ZStatMark::_ncontinue;
size_t ZStatMark::_mark_stack_usage;
void ZStatMark::set_at_mark_start(size_t nstripes) {
_nstripes = nstripes;
@ -1140,6 +1141,10 @@ void ZStatMark::set_at_mark_end(size_t nproactiveflush,
_ncontinue = ncontinue;
}
void ZStatMark::set_at_mark_free(size_t mark_stack_usage) {
_mark_stack_usage = mark_stack_usage;
}
void ZStatMark::print() {
log_info(gc, marking)("Mark: "
SIZE_FORMAT " stripe(s), "
@ -1152,6 +1157,8 @@ void ZStatMark::print() {
_nterminateflush,
_ntrycomplete,
_ncontinue);
log_info(gc, marking)("Mark Stack Usage: " SIZE_FORMAT "M", _mark_stack_usage / M);
}
//

@ -407,6 +407,7 @@ private:
static size_t _nterminateflush;
static size_t _ntrycomplete;
static size_t _ncontinue;
static size_t _mark_stack_usage;
public:
static void set_at_mark_start(size_t nstripes);
@ -414,6 +415,7 @@ public:
size_t nterminateflush,
size_t ntrycomplete,
size_t ncontinue);
static void set_at_mark_free(size_t mark_stack_usage);
static void print();
};