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 
  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 value) {
  66     if (value) {
  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 
  93 private:
  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 
 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 
 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 value) {
 171     if (value) {
 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 
 186 private:
 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 
 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 
 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 
 231 private:
 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_VM_GC_SHENANDOAH_SHENANDOAHSHAREDFLAG_HPP