--- a/src/hotspot/share/opto/library_call.cpp Fri May 18 15:21:23 2018 +0200
+++ b/src/hotspot/share/opto/library_call.cpp Fri May 18 14:51:06 2018 +0200
@@ -244,12 +244,9 @@
// This returns Type::AnyPtr, RawPtr, or OopPtr.
int classify_unsafe_addr(Node* &base, Node* &offset, BasicType type);
Node* make_unsafe_address(Node*& base, Node* offset, BasicType type = T_ILLEGAL, bool can_cast = false);
- // Helper for inline_unsafe_access.
- // Generates the guards that check whether the result of
- // Unsafe.getObject should be recorded in an SATB log buffer.
- void insert_pre_barrier(Node* base_oop, Node* offset, Node* pre_val, bool need_mem_bar);
typedef enum { Relaxed, Opaque, Volatile, Acquire, Release } AccessKind;
+ DecoratorSet mo_decorator_for_access_kind(AccessKind kind);
bool inline_unsafe_access(bool is_store, BasicType type, AccessKind kind, bool is_unaligned);
static bool klass_needs_init_guard(Node* kls);
bool inline_unsafe_allocate();
@@ -269,7 +266,7 @@
bool inline_array_copyOf(bool is_copyOfRange);
bool inline_array_equals(StrIntrinsicNode::ArgEnc ae);
bool inline_preconditions_checkIndex();
- void copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, bool is_array, bool card_mark);
+ void copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, bool is_array);
bool inline_native_clone(bool is_virtual);
bool inline_native_Reflection_getCallerClass();
// Helper function for inlining native object hash method
@@ -285,8 +282,6 @@
uint new_idx);
typedef enum { LS_get_add, LS_get_set, LS_cmp_swap, LS_cmp_swap_weak, LS_cmp_exchange } LoadStoreKind;
- MemNode::MemOrd access_kind_to_memord_LS(AccessKind access_kind, bool is_store);
- MemNode::MemOrd access_kind_to_memord(AccessKind access_kind);
bool inline_unsafe_load_store(BasicType type, LoadStoreKind kind, AccessKind access_kind);
bool inline_unsafe_fence(vmIntrinsics::ID id);
bool inline_onspinwait();
@@ -2224,106 +2219,6 @@
//----------------------------inline_unsafe_access----------------------------
-// Helper that guards and inserts a pre-barrier.
-void LibraryCallKit::insert_pre_barrier(Node* base_oop, Node* offset,
- Node* pre_val, bool need_mem_bar) {
- // We could be accessing the referent field of a reference object. If so, when G1
- // is enabled, we need to log the value in the referent field in an SATB buffer.
- // This routine performs some compile time filters and generates suitable
- // runtime filters that guard the pre-barrier code.
- // Also add memory barrier for non volatile load from the referent field
- // to prevent commoning of loads across safepoint.
- if (!UseG1GC && !need_mem_bar)
- return;
-
- // Some compile time checks.
-
- // If offset is a constant, is it java_lang_ref_Reference::_reference_offset?
- const TypeX* otype = offset->find_intptr_t_type();
- if (otype != NULL && otype->is_con() &&
- otype->get_con() != java_lang_ref_Reference::referent_offset) {
- // Constant offset but not the reference_offset so just return
- return;
- }
-
- // We only need to generate the runtime guards for instances.
- const TypeOopPtr* btype = base_oop->bottom_type()->isa_oopptr();
- if (btype != NULL) {
- if (btype->isa_aryptr()) {
- // Array type so nothing to do
- return;
- }
-
- const TypeInstPtr* itype = btype->isa_instptr();
- if (itype != NULL) {
- // Can the klass of base_oop be statically determined to be
- // _not_ a sub-class of Reference and _not_ Object?
- ciKlass* klass = itype->klass();
- if ( klass->is_loaded() &&
- !klass->is_subtype_of(env()->Reference_klass()) &&
- !env()->Object_klass()->is_subtype_of(klass)) {
- return;
- }
- }
- }
-
- // The compile time filters did not reject base_oop/offset so
- // we need to generate the following runtime filters
- //
- // if (offset == java_lang_ref_Reference::_reference_offset) {
- // if (instance_of(base, java.lang.ref.Reference)) {
- // pre_barrier(_, pre_val, ...);
- // }
- // }
-
- float likely = PROB_LIKELY( 0.999);
- float unlikely = PROB_UNLIKELY(0.999);
-
- IdealKit ideal(this);
-#define __ ideal.
-
- Node* referent_off = __ ConX(java_lang_ref_Reference::referent_offset);
-
- __ if_then(offset, BoolTest::eq, referent_off, unlikely); {
- // Update graphKit memory and control from IdealKit.
- sync_kit(ideal);
-
- Node* ref_klass_con = makecon(TypeKlassPtr::make(env()->Reference_klass()));
- Node* is_instof = gen_instanceof(base_oop, ref_klass_con);
-
- // Update IdealKit memory and control from graphKit.
- __ sync_kit(this);
-
- Node* one = __ ConI(1);
- // is_instof == 0 if base_oop == NULL
- __ if_then(is_instof, BoolTest::eq, one, unlikely); {
-
- // Update graphKit from IdeakKit.
- sync_kit(ideal);
-
- // Use the pre-barrier to record the value in the referent field
- pre_barrier(false /* do_load */,
- __ ctrl(),
- NULL /* obj */, NULL /* adr */, max_juint /* alias_idx */, NULL /* val */, NULL /* val_type */,
- pre_val /* pre_val */,
- T_OBJECT);
- if (need_mem_bar) {
- // Add memory barrier to prevent commoning reads from this field
- // across safepoint since GC can change its value.
- insert_mem_bar(Op_MemBarCPUOrder);
- }
- // Update IdealKit from graphKit.
- __ sync_kit(this);
-
- } __ end_if(); // _ref_type != ref_none
- } __ end_if(); // offset == referent_offset
-
- // Final sync IdealKit and GraphKit.
- final_sync(ideal);
-#undef __
-}
-
-
const TypeOopPtr* LibraryCallKit::sharpen_unsafe_type(Compile::AliasType* alias_type, const TypePtr *adr_type) {
// Attempt to infer a sharper value type from the offset and base type.
ciKlass* sharpened_klass = NULL;
@@ -2362,12 +2257,39 @@
return NULL;
}
+DecoratorSet LibraryCallKit::mo_decorator_for_access_kind(AccessKind kind) {
+ switch (kind) {
+ case Relaxed:
+ return MO_UNORDERED;
+ case Opaque:
+ return MO_RELAXED;
+ case Acquire:
+ return MO_ACQUIRE;
+ case Release:
+ return MO_RELEASE;
+ case Volatile:
+ return MO_SEQ_CST;
+ default:
+ ShouldNotReachHere();
+ return 0;
+ }
+}
+
bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, const AccessKind kind, const bool unaligned) {
if (callee()->is_static()) return false; // caller must have the capability!
+ DecoratorSet decorators = C2_UNSAFE_ACCESS;
guarantee(!is_store || kind != Acquire, "Acquire accesses can be produced only for loads");
guarantee( is_store || kind != Release, "Release accesses can be produced only for stores");
assert(type != T_OBJECT || !unaligned, "unaligned access not supported with object type");
+ if (type == T_OBJECT || type == T_ARRAY) {
+ decorators |= ON_UNKNOWN_OOP_REF;
+ }
+
+ if (unaligned) {
+ decorators |= C2_UNALIGNED;
+ }
+
#ifndef PRODUCT
{
ResourceMark rm;
@@ -2426,6 +2348,10 @@
// Can base be NULL? Otherwise, always on-heap access.
bool can_access_non_heap = TypePtr::NULL_PTR->higher_equal(_gvn.type(heap_base_oop));
+ if (!can_access_non_heap) {
+ decorators |= IN_HEAP;
+ }
+
val = is_store ? argument(4) : NULL;
const TypePtr *adr_type = _gvn.type(adr)->isa_ptr();
@@ -2463,60 +2389,15 @@
assert(!mismatched || alias_type->adr_type()->is_oopptr(), "off-heap access can't be mismatched");
+ if (mismatched) {
+ decorators |= C2_MISMATCHED;
+ }
+
// First guess at the value type.
const Type *value_type = Type::get_const_basic_type(type);
- // We will need memory barriers unless we can determine a unique
- // alias category for this reference. (Note: If for some reason
- // the barriers get omitted and the unsafe reference begins to "pollute"
- // the alias analysis of the rest of the graph, either Compile::can_alias
- // or Compile::must_alias will throw a diagnostic assert.)
- bool need_mem_bar = false;
- switch (kind) {
- case Relaxed:
- need_mem_bar = (mismatched && !adr_type->isa_aryptr()) || can_access_non_heap;
- break;
- case Opaque:
- // Opaque uses CPUOrder membars for protection against code movement.
- case Acquire:
- case Release:
- case Volatile:
- need_mem_bar = true;
- break;
- default:
- ShouldNotReachHere();
- }
-
- // Some accesses require access atomicity for all types, notably longs and doubles.
- // When AlwaysAtomicAccesses is enabled, all accesses are atomic.
- bool requires_atomic_access = false;
- switch (kind) {
- case Relaxed:
- requires_atomic_access = AlwaysAtomicAccesses;
- break;
- case Opaque:
- // Opaque accesses are atomic.
- case Acquire:
- case Release:
- case Volatile:
- requires_atomic_access = true;
- break;
- default:
- ShouldNotReachHere();
- }
-
// Figure out the memory ordering.
- // Acquire/Release/Volatile accesses require marking the loads/stores with MemOrd
- MemNode::MemOrd mo = access_kind_to_memord_LS(kind, is_store);
-
- // If we are reading the value of the referent field of a Reference
- // object (either by using Unsafe directly or through reflection)
- // then, if G1 is enabled, we need to record the referent in an
- // SATB log buffer using the pre-barrier mechanism.
- // Also we need to add memory barrier to prevent commoning reads
- // from this field across safepoint since GC can change its value.
- bool need_read_barrier = !is_store &&
- offset != top() && heap_base_oop != top();
+ decorators |= mo_decorator_for_access_kind(kind);
if (!is_store && type == T_OBJECT) {
const TypeOopPtr* tjp = sharpen_unsafe_type(alias_type, adr_type);
@@ -2534,39 +2415,6 @@
// and it is not possible to fully distinguish unintended nulls
// from intended ones in this API.
- // We need to emit leading and trailing CPU membars (see below) in
- // addition to memory membars for special access modes. This is a little
- // too strong, but avoids the need to insert per-alias-type
- // volatile membars (for stores; compare Parse::do_put_xxx), which
- // we cannot do effectively here because we probably only have a
- // rough approximation of type.
-
- switch(kind) {
- case Relaxed:
- case Opaque:
- case Acquire:
- break;
- case Release:
- case Volatile:
- if (is_store) {
- insert_mem_bar(Op_MemBarRelease);
- } else {
- if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
- insert_mem_bar(Op_MemBarVolatile);
- }
- }
- break;
- default:
- ShouldNotReachHere();
- }
-
- // Memory barrier to prevent normal and 'unsafe' accesses from
- // bypassing each other. Happens after null checks, so the
- // exception paths do not take memory state from the memory barrier,
- // so there's no problems making a strong assert about mixing users
- // of safe & unsafe memory.
- if (need_mem_bar) insert_mem_bar(Op_MemBarCPUOrder);
-
if (!is_store) {
Node* p = NULL;
// Try to constant fold a load from a constant field
@@ -2575,37 +2423,17 @@
// final or stable field
p = make_constant_from_field(field, heap_base_oop);
}
- if (p == NULL) {
- // To be valid, unsafe loads may depend on other conditions than
- // the one that guards them: pin the Load node
- LoadNode::ControlDependency dep = LoadNode::Pinned;
- Node* ctrl = control();
- // non volatile loads may be able to float
- if (!need_mem_bar && adr_type->isa_instptr()) {
- assert(adr_type->meet(TypePtr::NULL_PTR) != adr_type->remove_speculative(), "should be not null");
- intptr_t offset = Type::OffsetBot;
- AddPNode::Ideal_base_and_offset(adr, &_gvn, offset);
- if (offset >= 0) {
- int s = Klass::layout_helper_size_in_bytes(adr_type->isa_instptr()->klass()->layout_helper());
- if (offset < s) {
- // Guaranteed to be a valid access, no need to pin it
- dep = LoadNode::DependsOnlyOnTest;
- ctrl = NULL;
- }
- }
- }
- p = make_load(ctrl, adr, value_type, type, adr_type, mo, dep, requires_atomic_access, unaligned, mismatched);
- // load value
- switch (type) {
- case T_BOOLEAN:
- {
- // Normalize the value returned by getBoolean in the following cases
- if (mismatched ||
- heap_base_oop == top() || // - heap_base_oop is NULL or
- (can_access_non_heap && alias_type->field() == NULL) // - heap_base_oop is potentially NULL
- // and the unsafe access is made to large offset
- // (i.e., larger than the maximum offset necessary for any
- // field access)
+
+ if (p == NULL) { // Could not constant fold the load
+ p = access_load_at(heap_base_oop, adr, adr_type, value_type, type, decorators);
+ // Normalize the value returned by getBoolean in the following cases
+ if (type == T_BOOLEAN &&
+ (mismatched ||
+ heap_base_oop == top() || // - heap_base_oop is NULL or
+ (can_access_non_heap && field == NULL)) // - heap_base_oop is potentially NULL
+ // and the unsafe access is made to large offset
+ // (i.e., larger than the maximum offset necessary for any
+ // field access)
) {
IdealKit ideal = IdealKit(this);
#define __ ideal.
@@ -2618,32 +2446,11 @@
final_sync(ideal);
p = __ value(normalized_result);
#undef __
- }
}
- case T_CHAR:
- case T_BYTE:
- case T_SHORT:
- case T_INT:
- case T_LONG:
- case T_FLOAT:
- case T_DOUBLE:
- break;
- case T_OBJECT:
- if (need_read_barrier) {
- // We do not require a mem bar inside pre_barrier if need_mem_bar
- // is set: the barriers would be emitted by us.
- insert_pre_barrier(heap_base_oop, offset, p, !need_mem_bar);
- }
- break;
- case T_ADDRESS:
- // Cast to an int type.
- p = _gvn.transform(new CastP2XNode(NULL, p));
- p = ConvX2UL(p);
- break;
- default:
- fatal("unexpected type %d: %s", type, type2name(type));
- break;
- }
+ }
+ if (type == T_ADDRESS) {
+ p = gvn().transform(new CastP2XNode(NULL, p));
+ p = ConvX2UL(p);
}
// The load node has the control of the preceding MemBarCPUOrder. All
// following nodes will have the control of the MemBarCPUOrder inserted at
@@ -2651,47 +2458,13 @@
// point is fine.
set_result(p);
} else {
- // place effect of store into memory
- switch (type) {
- case T_DOUBLE:
- val = dstore_rounding(val);
- break;
- case T_ADDRESS:
+ if (bt == T_ADDRESS) {
// Repackage the long as a pointer.
val = ConvL2X(val);
- val = _gvn.transform(new CastX2PNode(val));
- break;
- default:
- break;
- }
-
- if (type == T_OBJECT) {
- store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo, mismatched);
- } else {
- store_to_memory(control(), adr, val, type, adr_type, mo, requires_atomic_access, unaligned, mismatched);
+ val = gvn().transform(new CastX2PNode(val));
}
- }
-
- switch(kind) {
- case Relaxed:
- case Opaque:
- case Release:
- break;
- case Acquire:
- case Volatile:
- if (!is_store) {
- insert_mem_bar(Op_MemBarAcquire);
- } else {
- if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
- insert_mem_bar(Op_MemBarVolatile);
- }
- }
- break;
- default:
- ShouldNotReachHere();
- }
-
- if (need_mem_bar) insert_mem_bar(Op_MemBarCPUOrder);
+ access_store_at(control(), heap_base_oop, adr, adr_type, val, value_type, type, decorators);
+ }
return true;
}
@@ -2757,6 +2530,9 @@
if (callee()->is_static()) return false; // caller must have the capability!
+ DecoratorSet decorators = C2_UNSAFE_ACCESS;
+ decorators |= mo_decorator_for_access_kind(access_kind);
+
#ifndef PRODUCT
BasicType rtype;
{
@@ -2888,318 +2664,54 @@
int alias_idx = C->get_alias_index(adr_type);
- // Memory-model-wise, a LoadStore acts like a little synchronized
- // block, so needs barriers on each side. These don't translate
- // into actual barriers on most machines, but we still need rest of
- // compiler to respect ordering.
-
- switch (access_kind) {
- case Relaxed:
- case Acquire:
- break;
- case Release:
- insert_mem_bar(Op_MemBarRelease);
- break;
- case Volatile:
- if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
- insert_mem_bar(Op_MemBarVolatile);
- } else {
- insert_mem_bar(Op_MemBarRelease);
- }
- break;
- default:
- ShouldNotReachHere();
- }
- insert_mem_bar(Op_MemBarCPUOrder);
-
- // Figure out the memory ordering.
- MemNode::MemOrd mo = access_kind_to_memord(access_kind);
-
- // 4984716: MemBars must be inserted before this
- // memory node in order to avoid a false
- // dependency which will confuse the scheduler.
- Node *mem = memory(alias_idx);
-
- // For now, we handle only those cases that actually exist: ints,
- // longs, and Object. Adding others should be straightforward.
- Node* load_store = NULL;
- switch(type) {
- case T_BYTE:
- switch(kind) {
- case LS_get_add:
- load_store = _gvn.transform(new GetAndAddBNode(control(), mem, adr, newval, adr_type));
- break;
- case LS_get_set:
- load_store = _gvn.transform(new GetAndSetBNode(control(), mem, adr, newval, adr_type));
- break;
- case LS_cmp_swap_weak:
- load_store = _gvn.transform(new WeakCompareAndSwapBNode(control(), mem, adr, newval, oldval, mo));
- break;
- case LS_cmp_swap:
- load_store = _gvn.transform(new CompareAndSwapBNode(control(), mem, adr, newval, oldval, mo));
- break;
- case LS_cmp_exchange:
- load_store = _gvn.transform(new CompareAndExchangeBNode(control(), mem, adr, newval, oldval, adr_type, mo));
- break;
- default:
- ShouldNotReachHere();
- }
- break;
- case T_SHORT:
- switch(kind) {
- case LS_get_add:
- load_store = _gvn.transform(new GetAndAddSNode(control(), mem, adr, newval, adr_type));
- break;
- case LS_get_set:
- load_store = _gvn.transform(new GetAndSetSNode(control(), mem, adr, newval, adr_type));
- break;
- case LS_cmp_swap_weak:
- load_store = _gvn.transform(new WeakCompareAndSwapSNode(control(), mem, adr, newval, oldval, mo));
- break;
- case LS_cmp_swap:
- load_store = _gvn.transform(new CompareAndSwapSNode(control(), mem, adr, newval, oldval, mo));
- break;
- case LS_cmp_exchange:
- load_store = _gvn.transform(new CompareAndExchangeSNode(control(), mem, adr, newval, oldval, adr_type, mo));
- break;
- default:
- ShouldNotReachHere();
- }
- break;
- case T_INT:
- switch(kind) {
- case LS_get_add:
- load_store = _gvn.transform(new GetAndAddINode(control(), mem, adr, newval, adr_type));
- break;
- case LS_get_set:
- load_store = _gvn.transform(new GetAndSetINode(control(), mem, adr, newval, adr_type));
- break;
- case LS_cmp_swap_weak:
- load_store = _gvn.transform(new WeakCompareAndSwapINode(control(), mem, adr, newval, oldval, mo));
- break;
- case LS_cmp_swap:
- load_store = _gvn.transform(new CompareAndSwapINode(control(), mem, adr, newval, oldval, mo));
- break;
- case LS_cmp_exchange:
- load_store = _gvn.transform(new CompareAndExchangeINode(control(), mem, adr, newval, oldval, adr_type, mo));
- break;
- default:
- ShouldNotReachHere();
- }
- break;
- case T_LONG:
- switch(kind) {
- case LS_get_add:
- load_store = _gvn.transform(new GetAndAddLNode(control(), mem, adr, newval, adr_type));
- break;
- case LS_get_set:
- load_store = _gvn.transform(new GetAndSetLNode(control(), mem, adr, newval, adr_type));
- break;
- case LS_cmp_swap_weak:
- load_store = _gvn.transform(new WeakCompareAndSwapLNode(control(), mem, adr, newval, oldval, mo));
- break;
- case LS_cmp_swap:
- load_store = _gvn.transform(new CompareAndSwapLNode(control(), mem, adr, newval, oldval, mo));
- break;
- case LS_cmp_exchange:
- load_store = _gvn.transform(new CompareAndExchangeLNode(control(), mem, adr, newval, oldval, adr_type, mo));
- break;
- default:
- ShouldNotReachHere();
- }
- break;
- case T_OBJECT:
+ if (type == T_OBJECT || type == T_ARRAY) {
+ decorators |= IN_HEAP | ON_UNKNOWN_OOP_REF;
+
// Transformation of a value which could be NULL pointer (CastPP #NULL)
// could be delayed during Parse (for example, in adjust_map_after_if()).
// Execute transformation here to avoid barrier generation in such case.
if (_gvn.type(newval) == TypePtr::NULL_PTR)
newval = _gvn.makecon(TypePtr::NULL_PTR);
- // Reference stores need a store barrier.
- switch(kind) {
- case LS_get_set: {
- // If pre-barrier must execute before the oop store, old value will require do_load here.
- if (!can_move_pre_barrier()) {
- pre_barrier(true /* do_load*/,
- control(), base, adr, alias_idx, newval, value_type->make_oopptr(),
- NULL /* pre_val*/,
- T_OBJECT);
- } // Else move pre_barrier to use load_store value, see below.
- break;
- }
- case LS_cmp_swap_weak:
- case LS_cmp_swap:
- case LS_cmp_exchange: {
- // Same as for newval above:
- if (_gvn.type(oldval) == TypePtr::NULL_PTR) {
- oldval = _gvn.makecon(TypePtr::NULL_PTR);
- }
- // The only known value which might get overwritten is oldval.
- pre_barrier(false /* do_load */,
- control(), NULL, NULL, max_juint, NULL, NULL,
- oldval /* pre_val */,
- T_OBJECT);
- break;
- }
- default:
- ShouldNotReachHere();
+ if (oldval != NULL && _gvn.type(oldval) == TypePtr::NULL_PTR) {
+ // Refine the value to a null constant, when it is known to be null
+ oldval = _gvn.makecon(TypePtr::NULL_PTR);
+ }
+ }
+
+ Node* result = NULL;
+ switch (kind) {
+ case LS_cmp_exchange: {
+ result = access_atomic_cmpxchg_val_at(control(), base, adr, adr_type, alias_idx,
+ oldval, newval, value_type, type, decorators);
+ break;
}
-
-#ifdef _LP64
- if (adr->bottom_type()->is_ptr_to_narrowoop()) {
- Node *newval_enc = _gvn.transform(new EncodePNode(newval, newval->bottom_type()->make_narrowoop()));
-
- switch(kind) {
- case LS_get_set:
- load_store = _gvn.transform(new GetAndSetNNode(control(), mem, adr, newval_enc, adr_type, value_type->make_narrowoop()));
- break;
- case LS_cmp_swap_weak: {
- Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop()));
- load_store = _gvn.transform(new WeakCompareAndSwapNNode(control(), mem, adr, newval_enc, oldval_enc, mo));
- break;
- }
- case LS_cmp_swap: {
- Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop()));
- load_store = _gvn.transform(new CompareAndSwapNNode(control(), mem, adr, newval_enc, oldval_enc, mo));
- break;
- }
- case LS_cmp_exchange: {
- Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop()));
- load_store = _gvn.transform(new CompareAndExchangeNNode(control(), mem, adr, newval_enc, oldval_enc, adr_type, value_type->make_narrowoop(), mo));
- break;
- }
- default:
- ShouldNotReachHere();
- }
- } else
-#endif
- switch (kind) {
- case LS_get_set:
- load_store = _gvn.transform(new GetAndSetPNode(control(), mem, adr, newval, adr_type, value_type->is_oopptr()));
- break;
- case LS_cmp_swap_weak:
- load_store = _gvn.transform(new WeakCompareAndSwapPNode(control(), mem, adr, newval, oldval, mo));
- break;
- case LS_cmp_swap:
- load_store = _gvn.transform(new CompareAndSwapPNode(control(), mem, adr, newval, oldval, mo));
- break;
- case LS_cmp_exchange:
- load_store = _gvn.transform(new CompareAndExchangePNode(control(), mem, adr, newval, oldval, adr_type, value_type->is_oopptr(), mo));
- break;
- default:
- ShouldNotReachHere();
+ case LS_cmp_swap_weak:
+ decorators |= C2_WEAK_CMPXCHG;
+ case LS_cmp_swap: {
+ result = access_atomic_cmpxchg_bool_at(control(), base, adr, adr_type, alias_idx,
+ oldval, newval, value_type, type, decorators);
+ break;
}
-
- // Emit the post barrier only when the actual store happened. This makes sense
- // to check only for LS_cmp_* that can fail to set the value.
- // LS_cmp_exchange does not produce any branches by default, so there is no
- // boolean result to piggyback on. TODO: When we merge CompareAndSwap with
- // CompareAndExchange and move branches here, it would make sense to conditionalize
- // post_barriers for LS_cmp_exchange as well.
- //
- // CAS success path is marked more likely since we anticipate this is a performance
- // critical path, while CAS failure path can use the penalty for going through unlikely
- // path as backoff. Which is still better than doing a store barrier there.
- switch (kind) {
- case LS_get_set:
- case LS_cmp_exchange: {
- post_barrier(control(), load_store, base, adr, alias_idx, newval, T_OBJECT, true);
- break;
- }
- case LS_cmp_swap_weak:
- case LS_cmp_swap: {
- IdealKit ideal(this);
- ideal.if_then(load_store, BoolTest::ne, ideal.ConI(0), PROB_STATIC_FREQUENT); {
- sync_kit(ideal);
- post_barrier(ideal.ctrl(), load_store, base, adr, alias_idx, newval, T_OBJECT, true);
- ideal.sync_kit(this);
- } ideal.end_if();
- final_sync(ideal);
- break;
- }
- default:
- ShouldNotReachHere();
+ case LS_get_set: {
+ result = access_atomic_xchg_at(control(), base, adr, adr_type, alias_idx,
+ newval, value_type, type, decorators);
+ break;
}
- break;
- default:
- fatal("unexpected type %d: %s", type, type2name(type));
- break;
- }
-
- // SCMemProjNodes represent the memory state of a LoadStore. Their
- // main role is to prevent LoadStore nodes from being optimized away
- // when their results aren't used.
- Node* proj = _gvn.transform(new SCMemProjNode(load_store));
- set_memory(proj, alias_idx);
-
- if (type == T_OBJECT && (kind == LS_get_set || kind == LS_cmp_exchange)) {
-#ifdef _LP64
- if (adr->bottom_type()->is_ptr_to_narrowoop()) {
- load_store = _gvn.transform(new DecodeNNode(load_store, load_store->get_ptr_type()));
+ case LS_get_add: {
+ result = access_atomic_add_at(control(), base, adr, adr_type, alias_idx,
+ newval, value_type, type, decorators);
+ break;
}
-#endif
- if (can_move_pre_barrier() && kind == LS_get_set) {
- // Don't need to load pre_val. The old value is returned by load_store.
- // The pre_barrier can execute after the xchg as long as no safepoint
- // gets inserted between them.
- pre_barrier(false /* do_load */,
- control(), NULL, NULL, max_juint, NULL, NULL,
- load_store /* pre_val */,
- T_OBJECT);
- }
- }
-
- // Add the trailing membar surrounding the access
- insert_mem_bar(Op_MemBarCPUOrder);
-
- switch (access_kind) {
- case Relaxed:
- case Release:
- break; // do nothing
- case Acquire:
- case Volatile:
- insert_mem_bar(Op_MemBarAcquire);
- // !support_IRIW_for_not_multiple_copy_atomic_cpu handled in platform code
- break;
default:
ShouldNotReachHere();
}
- assert(type2size[load_store->bottom_type()->basic_type()] == type2size[rtype], "result type should match");
- set_result(load_store);
+ assert(type2size[result->bottom_type()->basic_type()] == type2size[rtype], "result type should match");
+ set_result(result);
return true;
}
-MemNode::MemOrd LibraryCallKit::access_kind_to_memord_LS(AccessKind kind, bool is_store) {
- MemNode::MemOrd mo = MemNode::unset;
- switch(kind) {
- case Opaque:
- case Relaxed: mo = MemNode::unordered; break;
- case Acquire: mo = MemNode::acquire; break;
- case Release: mo = MemNode::release; break;
- case Volatile: mo = is_store ? MemNode::release : MemNode::acquire; break;
- default:
- ShouldNotReachHere();
- }
- guarantee(mo != MemNode::unset, "Should select memory ordering");
- return mo;
-}
-
-MemNode::MemOrd LibraryCallKit::access_kind_to_memord(AccessKind kind) {
- MemNode::MemOrd mo = MemNode::unset;
- switch(kind) {
- case Opaque:
- case Relaxed: mo = MemNode::unordered; break;
- case Acquire: mo = MemNode::acquire; break;
- case Release: mo = MemNode::release; break;
- case Volatile: mo = MemNode::seqcst; break;
- default:
- ShouldNotReachHere();
- }
- guarantee(mo != MemNode::unset, "Should select memory ordering");
- return mo;
-}
-
bool LibraryCallKit::inline_unsafe_fence(vmIntrinsics::ID id) {
// Regardless of form, don't allow previous ld/st to move down,
// then issue acquire, release, or volatile mem_bar.
@@ -4636,7 +4148,7 @@
//------------------------clone_coping-----------------------------------
// Helper function for inline_native_clone.
-void LibraryCallKit::copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, bool is_array, bool card_mark) {
+void LibraryCallKit::copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, bool is_array) {
assert(obj_size != NULL, "");
Node* raw_obj = alloc_obj->in(1);
assert(alloc_obj->is_CheckCastPP() && raw_obj->is_Proj() && raw_obj->in(0)->is_Allocate(), "");
@@ -4656,66 +4168,9 @@
// Copy the fastest available way.
// TODO: generate fields copies for small objects instead.
- Node* src = obj;
- Node* dest = alloc_obj;
Node* size = _gvn.transform(obj_size);
- // Exclude the header but include array length to copy by 8 bytes words.
- // Can't use base_offset_in_bytes(bt) since basic type is unknown.
- int base_off = is_array ? arrayOopDesc::length_offset_in_bytes() :
- instanceOopDesc::base_offset_in_bytes();
- // base_off:
- // 8 - 32-bit VM
- // 12 - 64-bit VM, compressed klass
- // 16 - 64-bit VM, normal klass
- if (base_off % BytesPerLong != 0) {
- assert(UseCompressedClassPointers, "");
- if (is_array) {
- // Exclude length to copy by 8 bytes words.
- base_off += sizeof(int);
- } else {
- // Include klass to copy by 8 bytes words.
- base_off = instanceOopDesc::klass_offset_in_bytes();
- }
- assert(base_off % BytesPerLong == 0, "expect 8 bytes alignment");
- }
- src = basic_plus_adr(src, base_off);
- dest = basic_plus_adr(dest, base_off);
-
- // Compute the length also, if needed:
- Node* countx = size;
- countx = _gvn.transform(new SubXNode(countx, MakeConX(base_off)));
- countx = _gvn.transform(new URShiftXNode(countx, intcon(LogBytesPerLong) ));
-
- const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM;
-
- ArrayCopyNode* ac = ArrayCopyNode::make(this, false, src, NULL, dest, NULL, countx, false, false);
- ac->set_clonebasic();
- Node* n = _gvn.transform(ac);
- if (n == ac) {
- set_predefined_output_for_runtime_call(ac, ac->in(TypeFunc::Memory), raw_adr_type);
- } else {
- set_all_memory(n);
- }
-
- // If necessary, emit some card marks afterwards. (Non-arrays only.)
- if (card_mark) {
- assert(!is_array, "");
- // Put in store barrier for any and all oops we are sticking
- // into this object. (We could avoid this if we could prove
- // that the object type contains no oop fields at all.)
- Node* no_particular_value = NULL;
- Node* no_particular_field = NULL;
- int raw_adr_idx = Compile::AliasIdxRaw;
- post_barrier(control(),
- memory(raw_adr_type),
- alloc_obj,
- no_particular_field,
- raw_adr_idx,
- no_particular_value,
- T_OBJECT,
- false);
- }
+ access_clone(control(), obj, alloc_obj, size, is_array);
// Do not let reads from the cloned object float above the arraycopy.
if (alloc != NULL) {
@@ -4805,9 +4260,6 @@
PhiNode* result_mem = new PhiNode(result_reg, Type::MEMORY, TypePtr::BOTTOM);
record_for_igvn(result_reg);
- const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM;
- int raw_adr_idx = Compile::AliasIdxRaw;
-
Node* array_ctl = generate_array_guard(obj_klass, (RegionNode*)NULL);
if (array_ctl != NULL) {
// It's an array.
@@ -4817,9 +4269,10 @@
Node* obj_size = NULL;
Node* alloc_obj = new_array(obj_klass, obj_length, 0, &obj_size); // no arguments to push
- if (!use_ReduceInitialCardMarks()) {
+ BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
+ if (bs->array_copy_requires_gc_barriers(T_OBJECT)) {
// If it is an oop array, it requires very special treatment,
- // because card marking is required on each card of the array.
+ // because gc barriers are required when accessing the array.
Node* is_obja = generate_objArray_guard(obj_klass, (RegionNode*)NULL);
if (is_obja != NULL) {
PreserveJVMState pjvms2(this);
@@ -4838,7 +4291,7 @@
result_mem ->set_req(_objArray_path, reset_memory());
}
}
- // Otherwise, there are no card marks to worry about.
+ // Otherwise, there are no barriers to worry about.
// (We can dispense with card marks if we know the allocation
// comes out of eden (TLAB)... In fact, ReduceInitialCardMarks
// causes the non-eden paths to take compensating steps to
@@ -4847,7 +4300,7 @@
// the object.)
if (!stopped()) {
- copy_to_clone(obj, alloc_obj, obj_size, true, false);
+ copy_to_clone(obj, alloc_obj, obj_size, true);
// Present the results of the copy.
result_reg->init_req(_array_path, control());
@@ -4893,7 +4346,7 @@
// exception state between multiple Object.clone versions (reexecute=true vs reexecute=false).
Node* alloc_obj = new_instance(obj_klass, NULL, &obj_size, /*deoptimize_on_exception=*/true);
- copy_to_clone(obj, alloc_obj, obj_size, false, !use_ReduceInitialCardMarks());
+ copy_to_clone(obj, alloc_obj, obj_size, false);
// Present the results of the slow call.
result_reg->init_req(_instance_path, control());
@@ -6100,21 +5553,23 @@
Node* reference_obj = null_check_receiver();
if (stopped()) return true;
+ const TypeInstPtr* tinst = _gvn.type(reference_obj)->isa_instptr();
+ assert(tinst != NULL, "obj is null");
+ assert(tinst->klass()->is_loaded(), "obj is not loaded");
+ ciInstanceKlass* referenceKlass = tinst->klass()->as_instance_klass();
+ ciField* field = referenceKlass->get_field_by_name(ciSymbol::make("referent"),
+ ciSymbol::make("Ljava/lang/Object;"),
+ false);
+ assert (field != NULL, "undefined field");
+
Node* adr = basic_plus_adr(reference_obj, reference_obj, referent_offset);
+ const TypePtr* adr_type = C->alias_type(field)->adr_type();
ciInstanceKlass* klass = env()->Object_klass();
const TypeOopPtr* object_type = TypeOopPtr::make_from_klass(klass);
- Node* no_ctrl = NULL;
- Node* result = make_load(no_ctrl, adr, object_type, T_OBJECT, MemNode::unordered);
-
- // Use the pre-barrier to record the value in the referent field
- pre_barrier(false /* do_load */,
- control(),
- NULL /* obj */, NULL /* adr */, max_juint /* alias_idx */, NULL /* val */, NULL /* val_type */,
- result /* pre_val */,
- T_OBJECT);
-
+ DecoratorSet decorators = IN_HEAP | ON_WEAK_OOP_REF;
+ Node* result = access_load_at(reference_obj, adr, adr_type, object_type, T_OBJECT, decorators);
// Add memory barrier to prevent commoning reads from this field
// across safepoint since GC can change its value.
insert_mem_bar(Op_MemBarCPUOrder);
@@ -6167,20 +5622,13 @@
type = Type::get_const_basic_type(bt);
}
- if (support_IRIW_for_not_multiple_copy_atomic_cpu && is_vol) {
- insert_mem_bar(Op_MemBarVolatile); // StoreLoad barrier
- }
- // Build the load.
- MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered;
- Node* loadedField = make_load(NULL, adr, type, bt, adr_type, mo, LoadNode::DependsOnlyOnTest, is_vol);
- // If reference is volatile, prevent following memory ops from
- // floating up past the volatile read. Also prevents commoning
- // another volatile read.
+ DecoratorSet decorators = IN_HEAP;
+
if (is_vol) {
- // Memory barrier includes bogus read of value to force load BEFORE membar
- insert_mem_bar(Op_MemBarAcquire, loadedField);
- }
- return loadedField;
+ decorators |= MO_SEQ_CST;
+ }
+
+ return access_load_at(fromObj, adr, adr_type, type, bt, decorators);
}
Node * LibraryCallKit::field_address_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString,