1/*
2 * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24#ifndef SHARE_GC_Z_ZFORWARDING_INLINE_HPP
25#define SHARE_GC_Z_ZFORWARDING_INLINE_HPP
26
27#include "gc/z/zAttachedArray.inline.hpp"
28#include "gc/z/zForwarding.hpp"
29#include "gc/z/zGlobals.hpp"
30#include "gc/z/zHash.inline.hpp"
31#include "gc/z/zHeap.hpp"
32#include "gc/z/zVirtualMemory.inline.hpp"
33#include "runtime/atomic.hpp"
34#include "utilities/debug.hpp"
35
36inline uintptr_t ZForwarding::start() const {
37 return _virtual.start();
38}
39
40inline size_t ZForwarding::size() const {
41 return _virtual.size();
42}
43
44inline size_t ZForwarding::object_alignment_shift() const {
45 return _object_alignment_shift;
46}
47
48inline ZPage* ZForwarding::page() const {
49 return _page;
50}
51
52inline bool ZForwarding::is_pinned() const {
53 return Atomic::load(&_pinned);
54}
55
56inline void ZForwarding::set_pinned() {
57 Atomic::store(true, &_pinned);
58}
59
60inline bool ZForwarding::inc_refcount() {
61 uint32_t refcount = Atomic::load(&_refcount);
62
63 while (refcount > 0) {
64 const uint32_t old_refcount = refcount;
65 const uint32_t new_refcount = old_refcount + 1;
66 const uint32_t prev_refcount = Atomic::cmpxchg(new_refcount, &_refcount, old_refcount);
67 if (prev_refcount == old_refcount) {
68 return true;
69 }
70
71 refcount = prev_refcount;
72 }
73
74 return false;
75}
76
77inline bool ZForwarding::dec_refcount() {
78 assert(_refcount > 0, "Invalid state");
79 return Atomic::sub(1u, &_refcount) == 0u;
80}
81
82inline bool ZForwarding::retain_page() {
83 return inc_refcount();
84}
85
86inline void ZForwarding::release_page() {
87 if (dec_refcount()) {
88 ZHeap::heap()->free_page(_page, true /* reclaimed */);
89 _page = NULL;
90 }
91}
92
93inline ZForwardingEntry* ZForwarding::entries() const {
94 return _entries(this);
95}
96
97inline ZForwardingEntry ZForwarding::at(ZForwardingCursor* cursor) const {
98 return Atomic::load(entries() + *cursor);
99}
100
101inline ZForwardingEntry ZForwarding::first(uintptr_t from_index, ZForwardingCursor* cursor) const {
102 const uint32_t mask = _entries.length() - 1;
103 const uint32_t hash = ZHash::uint32_to_uint32((uint32_t)from_index);
104 *cursor = hash & mask;
105 return at(cursor);
106}
107
108inline ZForwardingEntry ZForwarding::next(ZForwardingCursor* cursor) const {
109 const uint32_t mask = _entries.length() - 1;
110 *cursor = (*cursor + 1) & mask;
111 return at(cursor);
112}
113
114inline ZForwardingEntry ZForwarding::find(uintptr_t from_index) const {
115 ZForwardingCursor dummy;
116 return find(from_index, &dummy);
117}
118
119inline ZForwardingEntry ZForwarding::find(uintptr_t from_index, ZForwardingCursor* cursor) const {
120 // Reading entries in the table races with the atomic CAS done for
121 // insertion into the table. This is safe because each entry is at
122 // most updated once (from zero to something else).
123 ZForwardingEntry entry = first(from_index, cursor);
124 while (entry.populated()) {
125 if (entry.from_index() == from_index) {
126 // Match found, return matching entry
127 return entry;
128 }
129
130 entry = next(cursor);
131 }
132
133 // Match not found, return empty entry
134 return entry;
135}
136
137inline uintptr_t ZForwarding::insert(uintptr_t from_index, uintptr_t to_offset, ZForwardingCursor* cursor) {
138 const ZForwardingEntry new_entry(from_index, to_offset);
139 const ZForwardingEntry old_entry; // Empty
140
141 for (;;) {
142 const ZForwardingEntry prev_entry = Atomic::cmpxchg(new_entry, entries() + *cursor, old_entry);
143 if (!prev_entry.populated()) {
144 // Success
145 return to_offset;
146 }
147
148 // Find next empty or matching entry
149 ZForwardingEntry entry = at(cursor);
150 while (entry.populated()) {
151 if (entry.from_index() == from_index) {
152 // Match found, return already inserted address
153 return entry.to_offset();
154 }
155
156 entry = next(cursor);
157 }
158 }
159}
160
161#endif // SHARE_GC_Z_ZFORWARDING_INLINE_HPP
162