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_VM_GC_SHENANDOAH_SHENANDOAHSHAREDFLAG_HPP
25 #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHSHAREDFLAG_HPP
26 
27 #include "memory/allocation.hpp"
28 #include "runtime/orderAccess.hpp"
29 
30 typedef jbyte ShenandoahSharedValue;
31 
32 // Needed for cooperation with generated code.
33 STATIC_ASSERT(sizeof(ShenandoahSharedValue) == 1);
34 
35 typedef 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 
ShenandoahSharedFlagShenandoahSharedFlag45   ShenandoahSharedFlag() {
46     unset();
47   }
48 
setShenandoahSharedFlag49   void set() {
50     OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)SET);
51   }
52 
unsetShenandoahSharedFlag53   void unset() {
54     OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)UNSET);
55   }
56 
is_setShenandoahSharedFlag57   bool is_set() const {
58     return OrderAccess::load_acquire(&value) == SET;
59   }
60 
is_unsetShenandoahSharedFlag61   bool is_unset() const {
62     return OrderAccess::load_acquire(&value) == UNSET;
63   }
64 
set_condShenandoahSharedFlag65   void set_cond(bool val) {
66     if (val) {
67       set();
68     } else {
69       unset();
70     }
71   }
72 
try_setShenandoahSharedFlag73   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 
try_unsetShenandoahSharedFlag81   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 
addr_ofShenandoahSharedFlag89   volatile ShenandoahSharedValue* addr_of() {
90     return &value;
91   }
92 
93 private:
operator &ShenandoahSharedFlag94   volatile ShenandoahSharedValue* operator&() {
95     fatal("Use addr_of() instead");
96     return NULL;
97   }
98 
operator ==ShenandoahSharedFlag99   bool operator==(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
operator !=ShenandoahSharedFlag100   bool operator!=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
operator >ShenandoahSharedFlag101   bool operator> (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
operator >=ShenandoahSharedFlag102   bool operator>=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
operator <ShenandoahSharedFlag103   bool operator< (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
operator <=ShenandoahSharedFlag104   bool operator<=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
105 
106 } ShenandoahSharedFlag;
107 
108 typedef 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 
ShenandoahSharedBitmapShenandoahSharedBitmap113   ShenandoahSharedBitmap() {
114     clear();
115   }
116 
setShenandoahSharedBitmap117   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 
unsetShenandoahSharedBitmap135   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 
clearShenandoahSharedBitmap153   void clear() {
154     OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)0);
155   }
156 
is_setShenandoahSharedBitmap157   bool is_set(uint mask) const {
158     return !is_unset(mask);
159   }
160 
is_unsetShenandoahSharedBitmap161   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 
is_clearShenandoahSharedBitmap166   bool is_clear() const {
167     return (OrderAccess::load_acquire(&value)) == 0;
168   }
169 
set_condShenandoahSharedBitmap170   void set_cond(uint mask, bool val) {
171     if (val) {
172       set(mask);
173     } else {
174       unset(mask);
175     }
176   }
177 
addr_ofShenandoahSharedBitmap178   volatile ShenandoahSharedValue* addr_of() {
179     return &value;
180   }
181 
raw_valueShenandoahSharedBitmap182   ShenandoahSharedValue raw_value() const {
183     return value;
184   }
185 
186 private:
operator &ShenandoahSharedBitmap187   volatile ShenandoahSharedValue* operator&() {
188     fatal("Use addr_of() instead");
189     return NULL;
190   }
191 
operator ==ShenandoahSharedBitmap192   bool operator==(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
operator !=ShenandoahSharedBitmap193   bool operator!=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
operator >ShenandoahSharedBitmap194   bool operator> (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
operator >=ShenandoahSharedBitmap195   bool operator>=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
operator <ShenandoahSharedBitmap196   bool operator< (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
operator <=ShenandoahSharedBitmap197   bool operator<=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
198 
199 } ShenandoahSharedBitmap;
200 
201 template<class T>
202 struct 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 
ShenandoahSharedEnumFlagShenandoahSharedEnumFlag207   ShenandoahSharedEnumFlag() {
208     value = 0;
209   }
210 
setShenandoahSharedEnumFlag211   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 
getShenandoahSharedEnumFlag217   T get() const {
218     return (T)OrderAccess::load_acquire(&value);
219   }
220 
cmpxchgShenandoahSharedEnumFlag221   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 
addr_ofShenandoahSharedEnumFlag227   volatile ShenandoahSharedValue* addr_of() {
228     return &value;
229   }
230 
231 private:
operator &ShenandoahSharedEnumFlag232   volatile T* operator&() {
233     fatal("Use addr_of() instead");
234     return NULL;
235   }
236 
operator ==ShenandoahSharedEnumFlag237   bool operator==(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
operator !=ShenandoahSharedEnumFlag238   bool operator!=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
operator >ShenandoahSharedEnumFlag239   bool operator> (ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
operator >=ShenandoahSharedEnumFlag240   bool operator>=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
operator <ShenandoahSharedEnumFlag241   bool operator< (ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
operator <=ShenandoahSharedEnumFlag242   bool operator<=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
243 
244 };
245 
246 #endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHSHAREDFLAG_HPP
247