src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp
changeset 52925 9c18c9d839d3
child 53244 9807daeb47c4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp	Mon Dec 10 15:47:44 2018 +0100
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHSHAREDFLAG_HPP
+#define SHARE_VM_GC_SHENANDOAH_SHENANDOAHSHAREDFLAG_HPP
+
+#include "memory/allocation.hpp"
+#include "runtime/orderAccess.hpp"
+
+typedef jbyte ShenandoahSharedValue;
+
+// Needed for cooperation with generated code.
+STATIC_ASSERT(sizeof(ShenandoahSharedValue) == 1);
+
+typedef struct ShenandoahSharedFlag {
+  enum {
+    UNSET = 0,
+    SET = 1,
+  };
+
+  DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile ShenandoahSharedValue));
+  volatile ShenandoahSharedValue value;
+  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
+
+  ShenandoahSharedFlag() {
+    unset();
+  }
+
+  void set() {
+    OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)SET);
+  }
+
+  void unset() {
+    OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)UNSET);
+  }
+
+  bool is_set() const {
+    return OrderAccess::load_acquire(&value) == SET;
+  }
+
+  bool is_unset() const {
+    return OrderAccess::load_acquire(&value) == UNSET;
+  }
+
+  void set_cond(bool value) {
+    if (value) {
+      set();
+    } else {
+      unset();
+    }
+  }
+
+  bool try_set() {
+    if (is_set()) {
+      return false;
+    }
+    ShenandoahSharedValue old = Atomic::cmpxchg((ShenandoahSharedValue)SET, &value, (ShenandoahSharedValue)UNSET);
+    return old == UNSET; // success
+  }
+
+  bool try_unset() {
+    if (!is_set()) {
+      return false;
+    }
+    ShenandoahSharedValue old = Atomic::cmpxchg((ShenandoahSharedValue)UNSET, &value, (ShenandoahSharedValue)SET);
+    return old == SET; // success
+  }
+
+  volatile ShenandoahSharedValue* addr_of() {
+    return &value;
+  }
+
+private:
+  volatile ShenandoahSharedValue* operator&() {
+    fatal("Use addr_of() instead");
+    return NULL;
+  }
+
+  bool operator==(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
+  bool operator!=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
+  bool operator> (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
+  bool operator>=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
+  bool operator< (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
+  bool operator<=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
+
+} ShenandoahSharedFlag;
+
+typedef struct ShenandoahSharedBitmap {
+  DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile ShenandoahSharedValue));
+  volatile ShenandoahSharedValue value;
+  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
+
+  ShenandoahSharedBitmap() {
+    clear();
+  }
+
+  void set(uint mask) {
+    assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
+    ShenandoahSharedValue mask_val = (ShenandoahSharedValue) mask;
+    while (true) {
+      ShenandoahSharedValue ov = OrderAccess::load_acquire(&value);
+      if ((ov & mask_val) != 0) {
+        // already set
+        return;
+      }
+
+      ShenandoahSharedValue nv = ov | mask_val;
+      if (Atomic::cmpxchg(nv, &value, ov) == ov) {
+        // successfully set
+        return;
+      }
+    }
+  }
+
+  void unset(uint mask) {
+    assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
+    ShenandoahSharedValue mask_val = (ShenandoahSharedValue) mask;
+    while (true) {
+      ShenandoahSharedValue ov = OrderAccess::load_acquire(&value);
+      if ((ov & mask_val) == 0) {
+        // already unset
+        return;
+      }
+
+      ShenandoahSharedValue nv = ov & ~mask_val;
+      if (Atomic::cmpxchg(nv, &value, ov) == ov) {
+        // successfully unset
+        return;
+      }
+    }
+  }
+
+  void clear() {
+    OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)0);
+  }
+
+  bool is_set(uint mask) const {
+    return !is_unset(mask);
+  }
+
+  bool is_unset(uint mask) const {
+    assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
+    return (OrderAccess::load_acquire(&value) & (ShenandoahSharedValue) mask) == 0;
+  }
+
+  bool is_clear() const {
+    return (OrderAccess::load_acquire(&value)) == 0;
+  }
+
+  void set_cond(uint mask, bool value) {
+    if (value) {
+      set(mask);
+    } else {
+      unset(mask);
+    }
+  }
+
+  volatile ShenandoahSharedValue* addr_of() {
+    return &value;
+  }
+
+  ShenandoahSharedValue raw_value() const {
+    return value;
+  }
+
+private:
+  volatile ShenandoahSharedValue* operator&() {
+    fatal("Use addr_of() instead");
+    return NULL;
+  }
+
+  bool operator==(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
+  bool operator!=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
+  bool operator> (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
+  bool operator>=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
+  bool operator< (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
+  bool operator<=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
+
+} ShenandoahSharedBitmap;
+
+template<class T>
+struct ShenandoahSharedEnumFlag {
+  DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile ShenandoahSharedValue));
+  volatile ShenandoahSharedValue value;
+  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
+
+  ShenandoahSharedEnumFlag() {
+    value = 0;
+  }
+
+  void set(T v) {
+    assert (v >= 0, "sanity");
+    assert (v < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
+    OrderAccess::release_store_fence(&value, (ShenandoahSharedValue)v);
+  }
+
+  T get() const {
+    return (T)OrderAccess::load_acquire(&value);
+  }
+
+  T cmpxchg(T new_value, T expected) {
+    assert (new_value >= 0, "sanity");
+    assert (new_value < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
+    return (T)Atomic::cmpxchg((ShenandoahSharedValue)new_value, &value, (ShenandoahSharedValue)expected);
+  }
+
+  volatile ShenandoahSharedValue* addr_of() {
+    return &value;
+  }
+
+private:
+  volatile T* operator&() {
+    fatal("Use addr_of() instead");
+    return NULL;
+  }
+
+  bool operator==(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
+  bool operator!=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
+  bool operator> (ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
+  bool operator>=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
+  bool operator< (ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
+  bool operator<=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
+
+};
+
+#endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHSHAREDFLAG_HPP