--- /dev/null 2018-12-03 11:58:50.256341286 +0100 +++ new/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp 2018-12-03 17:47:46.298272694 +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 +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