Path: blob/master/src/hotspot/share/gc/z/zForwarding.cpp
40961 views
/*1* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223#include "precompiled.hpp"24#include "gc/z/zAddress.inline.hpp"25#include "gc/z/zForwarding.inline.hpp"26#include "gc/z/zStat.hpp"27#include "gc/z/zUtils.inline.hpp"28#include "utilities/align.hpp"2930//31// Reference count states:32//33// * If the reference count is zero, it will never change again.34//35// * If the reference count is positive, it can be both retained36// (increased) and released (decreased).37//38// * If the reference count is negative, is can only be released39// (increased). A negative reference count means that one or more40// threads are waiting for one or more other threads to release41// their references.42//43// The reference lock is used for waiting until the reference44// count has become zero (released) or negative one (claimed).45//4647static const ZStatCriticalPhase ZCriticalPhaseRelocationStall("Relocation Stall");4849bool ZForwarding::retain_page() {50for (;;) {51const int32_t ref_count = Atomic::load_acquire(&_ref_count);5253if (ref_count == 0) {54// Released55return false;56}5758if (ref_count < 0) {59// Claimed60const bool success = wait_page_released();61assert(success, "Should always succeed");62return false;63}6465if (Atomic::cmpxchg(&_ref_count, ref_count, ref_count + 1) == ref_count) {66// Retained67return true;68}69}70}7172ZPage* ZForwarding::claim_page() {73for (;;) {74const int32_t ref_count = Atomic::load(&_ref_count);75assert(ref_count > 0, "Invalid state");7677// Invert reference count78if (Atomic::cmpxchg(&_ref_count, ref_count, -ref_count) != ref_count) {79continue;80}8182// If the previous reference count was 1, then we just changed it to -1,83// and we have now claimed the page. Otherwise we wait until it is claimed.84if (ref_count != 1) {85ZLocker<ZConditionLock> locker(&_ref_lock);86while (Atomic::load_acquire(&_ref_count) != -1) {87_ref_lock.wait();88}89}9091return _page;92}93}9495void ZForwarding::release_page() {96for (;;) {97const int32_t ref_count = Atomic::load(&_ref_count);98assert(ref_count != 0, "Invalid state");99100if (ref_count > 0) {101// Decrement reference count102if (Atomic::cmpxchg(&_ref_count, ref_count, ref_count - 1) != ref_count) {103continue;104}105106// If the previous reference count was 1, then we just decremented107// it to 0 and we should signal that the page is now released.108if (ref_count == 1) {109// Notify released110ZLocker<ZConditionLock> locker(&_ref_lock);111_ref_lock.notify_all();112}113} else {114// Increment reference count115if (Atomic::cmpxchg(&_ref_count, ref_count, ref_count + 1) != ref_count) {116continue;117}118119// If the previous reference count was -2 or -1, then we just incremented it120// to -1 or 0, and we should signal the that page is now claimed or released.121if (ref_count == -2 || ref_count == -1) {122// Notify claimed or released123ZLocker<ZConditionLock> locker(&_ref_lock);124_ref_lock.notify_all();125}126}127128return;129}130}131132bool ZForwarding::wait_page_released() const {133if (Atomic::load_acquire(&_ref_count) != 0) {134ZStatTimer timer(ZCriticalPhaseRelocationStall);135ZLocker<ZConditionLock> locker(&_ref_lock);136while (Atomic::load_acquire(&_ref_count) != 0) {137if (_ref_abort) {138return false;139}140141_ref_lock.wait();142}143}144145return true;146}147148ZPage* ZForwarding::detach_page() {149// Wait until released150if (Atomic::load_acquire(&_ref_count) != 0) {151ZLocker<ZConditionLock> locker(&_ref_lock);152while (Atomic::load_acquire(&_ref_count) != 0) {153_ref_lock.wait();154}155}156157// Detach and return page158ZPage* const page = _page;159_page = NULL;160return page;161}162163void ZForwarding::abort_page() {164ZLocker<ZConditionLock> locker(&_ref_lock);165assert(Atomic::load(&_ref_count) > 0, "Invalid state");166assert(!_ref_abort, "Invalid state");167_ref_abort = true;168_ref_lock.notify_all();169}170171void ZForwarding::verify() const {172guarantee(_ref_count != 0, "Invalid reference count");173guarantee(_page != NULL, "Invalid page");174175uint32_t live_objects = 0;176size_t live_bytes = 0;177178for (ZForwardingCursor i = 0; i < _entries.length(); i++) {179const ZForwardingEntry entry = at(&i);180if (!entry.populated()) {181// Skip empty entries182continue;183}184185// Check from index186guarantee(entry.from_index() < _page->object_max_count(), "Invalid from index");187188// Check for duplicates189for (ZForwardingCursor j = i + 1; j < _entries.length(); j++) {190const ZForwardingEntry other = at(&j);191if (!other.populated()) {192// Skip empty entries193continue;194}195196guarantee(entry.from_index() != other.from_index(), "Duplicate from");197guarantee(entry.to_offset() != other.to_offset(), "Duplicate to");198}199200const uintptr_t to_addr = ZAddress::good(entry.to_offset());201const size_t size = ZUtils::object_size(to_addr);202const size_t aligned_size = align_up(size, _page->object_alignment());203live_bytes += aligned_size;204live_objects++;205}206207// Verify number of live objects and bytes208_page->verify_live(live_objects, live_bytes);209}210211212