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 "gc_implementation/shenandoah/shenandoahPadding.hpp"
  28 #include "memory/allocation.hpp"
  29 #include "runtime/orderAccess.hpp"
  30 
  31 typedef jbyte ShenandoahSharedValue;
  32 
  33 typedef struct ShenandoahSharedFlag {
  34   enum {
  35     UNSET = 0,
  36     SET = 1
  37   };
  38 
  39   shenandoah_padding(0);
  40   volatile ShenandoahSharedValue value;
  41   shenandoah_padding(1);
  42 
  43   ShenandoahSharedFlag() {
  44     // Needed for cooperation with generated code.
  45     STATIC_ASSERT(sizeof(ShenandoahSharedValue) == 1);
  46 
  47     unset();
  48   }
  49 
  50   void set() {
  51     OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)SET);
  52   }
  53 
  54   void unset() {
  55     OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)UNSET);
  56   }
  57 
  58   bool is_set() const {
  59     return OrderAccess::load_acquire((volatile ShenandoahSharedValue*) &value) == SET;
  60   }
  61 
  62   bool is_unset() const {
  63     return OrderAccess::load_acquire((volatile ShenandoahSharedValue*) &value) == UNSET;
  64   }
  65 
  66   void set_cond(bool val) {
  67     if (val) {
  68       set();
  69     } else {
  70       unset();
  71     }
  72   }
  73 
  74   bool try_set() {
  75     if (is_set()) {
  76       return false;
  77     }
  78     ShenandoahSharedValue old = Atomic::cmpxchg((ShenandoahSharedValue)SET, &value, (ShenandoahSharedValue)UNSET);
  79     return old == UNSET; // success
  80   }
  81 
  82   bool try_unset() {
  83     if (!is_set()) {
  84       return false;
  85     }
  86     ShenandoahSharedValue old = Atomic::cmpxchg((ShenandoahSharedValue)UNSET, &value, (ShenandoahSharedValue)SET);
  87     return old == SET; // success
  88   }
  89 
  90   volatile ShenandoahSharedValue* addr_of() {
  91     return &value;
  92   }
  93 
  94 private:
  95   volatile ShenandoahSharedValue* operator&() {
  96     fatal("Use addr_of() instead");
  97     return NULL;
  98   }
  99 
 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   bool operator<=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
 106 
 107 } ShenandoahSharedFlag;
 108 
 109 typedef struct ShenandoahSharedBitmap {
 110   shenandoah_padding(0);
 111   volatile ShenandoahSharedValue value;
 112   shenandoah_padding(1);
 113 
 114   ShenandoahSharedBitmap() {
 115     clear();
 116   }
 117 
 118   void set(uint mask) {
 119     assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
 120     ShenandoahSharedValue mask_val = (ShenandoahSharedValue) mask;
 121     while (true) {
 122       ShenandoahSharedValue ov = OrderAccess::load_acquire(&value);
 123       if ((ov & mask_val) != 0) {
 124         // already set
 125         return;
 126       }
 127 
 128       ShenandoahSharedValue nv = ov | mask_val;
 129       if (Atomic::cmpxchg(nv, &value, ov) == ov) {
 130         // successfully set
 131         return;
 132       }
 133     }
 134   }
 135 
 136   void unset(uint mask) {
 137     assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
 138     ShenandoahSharedValue mask_val = (ShenandoahSharedValue) mask;
 139     while (true) {
 140       ShenandoahSharedValue ov = OrderAccess::load_acquire(&value);
 141       if ((ov & mask_val) == 0) {
 142         // already unset
 143         return;
 144       }
 145 
 146       ShenandoahSharedValue nv = ov & ~mask_val;
 147       if (Atomic::cmpxchg(nv, &value, ov) == ov) {
 148         // successfully unset
 149         return;
 150       }
 151     }
 152   }
 153 
 154   void clear() {
 155     OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)0);
 156   }
 157 
 158   bool is_set(uint mask) const {
 159     return !is_unset(mask);
 160   }
 161 
 162   bool is_unset(uint mask) const {
 163     assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
 164     return (OrderAccess::load_acquire((volatile ShenandoahSharedValue*)&value) & (ShenandoahSharedValue) mask) == 0;
 165   }
 166 
 167   bool is_clear() const {
 168     return (OrderAccess::load_acquire((volatile ShenandoahSharedValue*)&value)) == 0;
 169   }
 170 
 171   void set_cond(uint mask, bool val) {
 172     if (val) {
 173       set(mask);
 174     } else {
 175       unset(mask);
 176     }
 177   }
 178 
 179   volatile ShenandoahSharedValue* addr_of() {
 180     return &value;
 181   }
 182 
 183   ShenandoahSharedValue raw_value() {
 184     return value;
 185   }
 186 
 187 private:
 188   volatile ShenandoahSharedValue* operator&() {
 189     fatal("Use addr_of() instead");
 190     return NULL;
 191   }
 192 
 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   bool operator<=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
 199 
 200 } ShenandoahSharedBitmap;
 201 
 202 template<class T>
 203 struct ShenandoahSharedEnumFlag {
 204   shenandoah_padding(0);
 205   volatile ShenandoahSharedValue value;
 206   shenandoah_padding(1);
 207 
 208   ShenandoahSharedEnumFlag() {
 209     value = 0;
 210   }
 211 
 212   void set(T v) {
 213     assert (v >= 0, "sanity");
 214     assert (v < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
 215     OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)v);
 216   }
 217 
 218   T get() const {
 219     return (T)OrderAccess::load_acquire((volatile ShenandoahSharedValue*) &value);
 220   }
 221 
 222   T cmpxchg(T new_value, T expected) {
 223     assert (new_value >= 0, "sanity");
 224     assert (new_value < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
 225     return (T)Atomic::cmpxchg((ShenandoahSharedValue)new_value, &value, (ShenandoahSharedValue)expected);
 226   }
 227 
 228   volatile ShenandoahSharedValue* addr_of() {
 229     return &value;
 230   }
 231 
 232 private:
 233   volatile T* operator&() {
 234     fatal("Use addr_of() instead");
 235     return NULL;
 236   }
 237 
 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   bool operator<=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
 244 
 245 };
 246 
 247 #endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHSHAREDFLAG_HPP