1/*
2 * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 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 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 *
22 */
23
24#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHSHAREDVARIABLES_HPP
25#define SHARE_GC_SHENANDOAH_SHENANDOAHSHAREDVARIABLES_HPP
26
27#include "memory/allocation.hpp"
28#include "runtime/orderAccess.hpp"
29
30typedef jbyte ShenandoahSharedValue;
31
32// Needed for cooperation with generated code.
33STATIC_ASSERT(sizeof(ShenandoahSharedValue) == 1);
34
35typedef struct ShenandoahSharedFlag {
36 enum {
37 UNSET = 0,
38 SET = 1
39 };
40
41 DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile ShenandoahSharedValue));
42 volatile ShenandoahSharedValue value;
43 DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
44
45 ShenandoahSharedFlag() {
46 unset();
47 }
48
49 void set() {
50 OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)SET);
51 }
52
53 void unset() {
54 OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)UNSET);
55 }
56
57 bool is_set() const {
58 return OrderAccess::load_acquire(&value) == SET;
59 }
60
61 bool is_unset() const {
62 return OrderAccess::load_acquire(&value) == UNSET;
63 }
64
65 void set_cond(bool val) {
66 if (val) {
67 set();
68 } else {
69 unset();
70 }
71 }
72
73 bool try_set() {
74 if (is_set()) {
75 return false;
76 }
77 ShenandoahSharedValue old = Atomic::cmpxchg((ShenandoahSharedValue)SET, &value, (ShenandoahSharedValue)UNSET);
78 return old == UNSET; // success
79 }
80
81 bool try_unset() {
82 if (!is_set()) {
83 return false;
84 }
85 ShenandoahSharedValue old = Atomic::cmpxchg((ShenandoahSharedValue)UNSET, &value, (ShenandoahSharedValue)SET);
86 return old == SET; // success
87 }
88
89 volatile ShenandoahSharedValue* addr_of() {
90 return &value;
91 }
92
93private:
94 volatile ShenandoahSharedValue* operator&() {
95 fatal("Use addr_of() instead");
96 return NULL;
97 }
98
99 bool operator==(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
100 bool operator!=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
101 bool operator> (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
102 bool operator>=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
103 bool operator< (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
104 bool operator<=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
105
106} ShenandoahSharedFlag;
107
108typedef struct ShenandoahSharedBitmap {
109 DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile ShenandoahSharedValue));
110 volatile ShenandoahSharedValue value;
111 DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
112
113 ShenandoahSharedBitmap() {
114 clear();
115 }
116
117 void set(uint mask) {
118 assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
119 ShenandoahSharedValue mask_val = (ShenandoahSharedValue) mask;
120 while (true) {
121 ShenandoahSharedValue ov = OrderAccess::load_acquire(&value);
122 if ((ov & mask_val) != 0) {
123 // already set
124 return;
125 }
126
127 ShenandoahSharedValue nv = ov | mask_val;
128 if (Atomic::cmpxchg(nv, &value, ov) == ov) {
129 // successfully set
130 return;
131 }
132 }
133 }
134
135 void unset(uint mask) {
136 assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
137 ShenandoahSharedValue mask_val = (ShenandoahSharedValue) mask;
138 while (true) {
139 ShenandoahSharedValue ov = OrderAccess::load_acquire(&value);
140 if ((ov & mask_val) == 0) {
141 // already unset
142 return;
143 }
144
145 ShenandoahSharedValue nv = ov & ~mask_val;
146 if (Atomic::cmpxchg(nv, &value, ov) == ov) {
147 // successfully unset
148 return;
149 }
150 }
151 }
152
153 void clear() {
154 OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)0);
155 }
156
157 bool is_set(uint mask) const {
158 return !is_unset(mask);
159 }
160
161 bool is_unset(uint mask) const {
162 assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
163 return (OrderAccess::load_acquire(&value) & (ShenandoahSharedValue) mask) == 0;
164 }
165
166 bool is_clear() const {
167 return (OrderAccess::load_acquire(&value)) == 0;
168 }
169
170 void set_cond(uint mask, bool val) {
171 if (val) {
172 set(mask);
173 } else {
174 unset(mask);
175 }
176 }
177
178 volatile ShenandoahSharedValue* addr_of() {
179 return &value;
180 }
181
182 ShenandoahSharedValue raw_value() const {
183 return value;
184 }
185
186private:
187 volatile ShenandoahSharedValue* operator&() {
188 fatal("Use addr_of() instead");
189 return NULL;
190 }
191
192 bool operator==(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
193 bool operator!=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
194 bool operator> (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
195 bool operator>=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
196 bool operator< (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
197 bool operator<=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
198
199} ShenandoahSharedBitmap;
200
201template<class T>
202struct ShenandoahSharedEnumFlag {
203 DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile ShenandoahSharedValue));
204 volatile ShenandoahSharedValue value;
205 DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
206
207 ShenandoahSharedEnumFlag() {
208 value = 0;
209 }
210
211 void set(T v) {
212 assert (v >= 0, "sanity");
213 assert (v < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
214 OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)v);
215 }
216
217 T get() const {
218 return (T)OrderAccess::load_acquire(&value);
219 }
220
221 T cmpxchg(T new_value, T expected) {
222 assert (new_value >= 0, "sanity");
223 assert (new_value < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
224 return (T)Atomic::cmpxchg((ShenandoahSharedValue)new_value, &value, (ShenandoahSharedValue)expected);
225 }
226
227 volatile ShenandoahSharedValue* addr_of() {
228 return &value;
229 }
230
231private:
232 volatile T* operator&() {
233 fatal("Use addr_of() instead");
234 return NULL;
235 }
236
237 bool operator==(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
238 bool operator!=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
239 bool operator> (ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
240 bool operator>=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
241 bool operator< (ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
242 bool operator<=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
243
244};
245
246#endif // SHARE_GC_SHENANDOAH_SHENANDOAHSHAREDVARIABLES_HPP
247