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