Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/gc/z/zForwarding.cpp
40961 views
1
/*
2
* Copyright (c) 2015, 2020, 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
#include "precompiled.hpp"
25
#include "gc/z/zAddress.inline.hpp"
26
#include "gc/z/zForwarding.inline.hpp"
27
#include "gc/z/zStat.hpp"
28
#include "gc/z/zUtils.inline.hpp"
29
#include "utilities/align.hpp"
30
31
//
32
// Reference count states:
33
//
34
// * If the reference count is zero, it will never change again.
35
//
36
// * If the reference count is positive, it can be both retained
37
// (increased) and released (decreased).
38
//
39
// * If the reference count is negative, is can only be released
40
// (increased). A negative reference count means that one or more
41
// threads are waiting for one or more other threads to release
42
// their references.
43
//
44
// The reference lock is used for waiting until the reference
45
// count has become zero (released) or negative one (claimed).
46
//
47
48
static const ZStatCriticalPhase ZCriticalPhaseRelocationStall("Relocation Stall");
49
50
bool ZForwarding::retain_page() {
51
for (;;) {
52
const int32_t ref_count = Atomic::load_acquire(&_ref_count);
53
54
if (ref_count == 0) {
55
// Released
56
return false;
57
}
58
59
if (ref_count < 0) {
60
// Claimed
61
const bool success = wait_page_released();
62
assert(success, "Should always succeed");
63
return false;
64
}
65
66
if (Atomic::cmpxchg(&_ref_count, ref_count, ref_count + 1) == ref_count) {
67
// Retained
68
return true;
69
}
70
}
71
}
72
73
ZPage* ZForwarding::claim_page() {
74
for (;;) {
75
const int32_t ref_count = Atomic::load(&_ref_count);
76
assert(ref_count > 0, "Invalid state");
77
78
// Invert reference count
79
if (Atomic::cmpxchg(&_ref_count, ref_count, -ref_count) != ref_count) {
80
continue;
81
}
82
83
// If the previous reference count was 1, then we just changed it to -1,
84
// and we have now claimed the page. Otherwise we wait until it is claimed.
85
if (ref_count != 1) {
86
ZLocker<ZConditionLock> locker(&_ref_lock);
87
while (Atomic::load_acquire(&_ref_count) != -1) {
88
_ref_lock.wait();
89
}
90
}
91
92
return _page;
93
}
94
}
95
96
void ZForwarding::release_page() {
97
for (;;) {
98
const int32_t ref_count = Atomic::load(&_ref_count);
99
assert(ref_count != 0, "Invalid state");
100
101
if (ref_count > 0) {
102
// Decrement reference count
103
if (Atomic::cmpxchg(&_ref_count, ref_count, ref_count - 1) != ref_count) {
104
continue;
105
}
106
107
// If the previous reference count was 1, then we just decremented
108
// it to 0 and we should signal that the page is now released.
109
if (ref_count == 1) {
110
// Notify released
111
ZLocker<ZConditionLock> locker(&_ref_lock);
112
_ref_lock.notify_all();
113
}
114
} else {
115
// Increment reference count
116
if (Atomic::cmpxchg(&_ref_count, ref_count, ref_count + 1) != ref_count) {
117
continue;
118
}
119
120
// If the previous reference count was -2 or -1, then we just incremented it
121
// to -1 or 0, and we should signal the that page is now claimed or released.
122
if (ref_count == -2 || ref_count == -1) {
123
// Notify claimed or released
124
ZLocker<ZConditionLock> locker(&_ref_lock);
125
_ref_lock.notify_all();
126
}
127
}
128
129
return;
130
}
131
}
132
133
bool ZForwarding::wait_page_released() const {
134
if (Atomic::load_acquire(&_ref_count) != 0) {
135
ZStatTimer timer(ZCriticalPhaseRelocationStall);
136
ZLocker<ZConditionLock> locker(&_ref_lock);
137
while (Atomic::load_acquire(&_ref_count) != 0) {
138
if (_ref_abort) {
139
return false;
140
}
141
142
_ref_lock.wait();
143
}
144
}
145
146
return true;
147
}
148
149
ZPage* ZForwarding::detach_page() {
150
// Wait until released
151
if (Atomic::load_acquire(&_ref_count) != 0) {
152
ZLocker<ZConditionLock> locker(&_ref_lock);
153
while (Atomic::load_acquire(&_ref_count) != 0) {
154
_ref_lock.wait();
155
}
156
}
157
158
// Detach and return page
159
ZPage* const page = _page;
160
_page = NULL;
161
return page;
162
}
163
164
void ZForwarding::abort_page() {
165
ZLocker<ZConditionLock> locker(&_ref_lock);
166
assert(Atomic::load(&_ref_count) > 0, "Invalid state");
167
assert(!_ref_abort, "Invalid state");
168
_ref_abort = true;
169
_ref_lock.notify_all();
170
}
171
172
void ZForwarding::verify() const {
173
guarantee(_ref_count != 0, "Invalid reference count");
174
guarantee(_page != NULL, "Invalid page");
175
176
uint32_t live_objects = 0;
177
size_t live_bytes = 0;
178
179
for (ZForwardingCursor i = 0; i < _entries.length(); i++) {
180
const ZForwardingEntry entry = at(&i);
181
if (!entry.populated()) {
182
// Skip empty entries
183
continue;
184
}
185
186
// Check from index
187
guarantee(entry.from_index() < _page->object_max_count(), "Invalid from index");
188
189
// Check for duplicates
190
for (ZForwardingCursor j = i + 1; j < _entries.length(); j++) {
191
const ZForwardingEntry other = at(&j);
192
if (!other.populated()) {
193
// Skip empty entries
194
continue;
195
}
196
197
guarantee(entry.from_index() != other.from_index(), "Duplicate from");
198
guarantee(entry.to_offset() != other.to_offset(), "Duplicate to");
199
}
200
201
const uintptr_t to_addr = ZAddress::good(entry.to_offset());
202
const size_t size = ZUtils::object_size(to_addr);
203
const size_t aligned_size = align_up(size, _page->object_alignment());
204
live_bytes += aligned_size;
205
live_objects++;
206
}
207
208
// Verify number of live objects and bytes
209
_page->verify_live(live_objects, live_bytes);
210
}
211
212