# HG changeset patch # Parent 535cce23fa8b222739e03f54a8c683d78be5cf49 8207169: Modularize cmpxchg-oop assembler for C1 diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -1926,24 +1926,9 @@ assert(newval != addr, "new value and addr must be in different registers"); if ( op->code() == lir_cas_obj) { -#ifdef _LP64 - if (UseCompressedOops) { - __ encode_heap_oop(cmpval); - __ mov(rscratch1, newval); - __ encode_heap_oop(rscratch1); - if (os::is_MP()) { - __ lock(); - } - // cmpval (rax) is implicitly used by this instruction - __ cmpxchgl(rscratch1, Address(addr, 0)); - } else -#endif - { - if (os::is_MP()) { - __ lock(); - } - __ cmpxchgptr(newval, Address(addr, 0)); - } + Register tmp1 = op->tmp1()->as_register(); + Register tmp2 = op->tmp2()->as_register(); + __ access_cmpxchg_oop_c1(Address(addr, 0), cmpval, newval, tmp1, tmp2); } else { assert(op->code() == lir_cas_int, "lir_cas_int expected"); if (os::is_MP()) { diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -33,6 +33,7 @@ #include "ci/ciArray.hpp" #include "ci/ciObjArrayKlass.hpp" #include "ci/ciTypeArrayKlass.hpp" +#include "gc/shared/barrierSetAssembler.hpp" #include "gc/shared/c1/barrierSetC1.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" @@ -660,7 +661,13 @@ if (type == T_OBJECT || type == T_ARRAY) { cmp_value.load_item_force(FrameMap::rax_oop_opr); new_value.load_item(); - __ cas_obj(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill); + LIR_Opr tmp1 = ill; + LIR_Opr tmp2 = ill; + if (BarrierSet::barrier_set()->barrier_set_assembler()->handle_cmpxchg_oop()) { + tmp1 = new_register(T_OBJECT); + tmp2 = new_register(T_OBJECT); + } + __ cas_obj(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), tmp1, tmp2); } else if (type == T_INT) { cmp_value.load_item_force(FrameMap::rax_opr); new_value.load_item(); diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp @@ -189,6 +189,50 @@ } } +void BarrierSetAssembler::cmpxchg_oop_c1(MacroAssembler* masm, + Address addr, Register oldval, Register newval, + Register tmp1, Register tmp2) { +#ifdef _LP64 + if (UseCompressedOops) { + __ encode_heap_oop(oldval); + __ mov(rscratch1, newval); + __ encode_heap_oop(rscratch1); + newval = rscratch1; + } +#endif + cmpxchg_oop(masm, noreg, addr, oldval, newval, tmp1, tmp2, true, false); +} + +void BarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, + Register res, Address addr, Register oldval, Register newval, + Register tmp1, Register tmp2, bool exchange, bool expect_null) { + +#ifdef _LP64 + if (UseCompressedOops) { + if (os::is_MP()) { + __ lock(); + } + // cmpval (rax) is implicitly used by this instruction + __ cmpxchgl(newval, addr); + } else +#endif + { + if (os::is_MP()) { + __ lock(); + } + __ cmpxchgptr(newval, addr); + } + + if (!exchange) { + assert(res != NULL, "need result register"); + __ setb(Assembler::equal, res); + __ movzbl(res, res); + } else { + assert(res == noreg, "don't use result register on this path"); + // exchanged value already in oldval (rax) + } +} + #ifndef _LP64 void BarrierSetAssembler::obj_equals(MacroAssembler* masm, Address obj1, jobject obj2) { diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp @@ -38,6 +38,14 @@ int con_size_in_bytes, Register t1); +protected: + // Atomically store newval into addr, if addr currently contains oldval. + // - exchange: if true, the previous value is returned in oldval, res is expected to be noreg + // - expect_null: if true, oldval is known to be NULL, might allow for optimizations + virtual void cmpxchg_oop(MacroAssembler* masm, + Register res, Address addr, Register oldval, Register newval, + Register tmp1, Register tmp2, bool exchange, bool expect_null); + public: virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count) {} @@ -49,6 +57,14 @@ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2); + virtual bool handle_cmpxchg_oop() const { return false; } + + // Atomically store newval into addr, if addr currently contains oldval. + // This version is intended for use by C1 assembler, and encodes uncompressed + // oops if necessary. + virtual void cmpxchg_oop_c1(MacroAssembler* masm, Address addr, Register oldval, Register newval, + Register tmp1, Register tmp2); + #ifndef _LP64 virtual void obj_equals(MacroAssembler* masm, Address obj1, jobject obj2); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -6178,6 +6178,12 @@ return bs->resolve(this, decorators, obj); } +void MacroAssembler::access_cmpxchg_oop_c1(Address addr, Register cmpval, Register newval, + Register tmp1, Register tmp2) { + BarrierSetAssembler* bsa = BarrierSet::barrier_set()->barrier_set_assembler(); + bsa->cmpxchg_oop_c1(this, addr, cmpval, newval, tmp1, tmp2); +} + void MacroAssembler::load_heap_oop(Register dst, Address src, Register tmp1, Register thread_tmp, DecoratorSet decorators) { access_load_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1, thread_tmp); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -323,6 +323,13 @@ // All other registers are preserved. void resolve(DecoratorSet decorators, Register obj); + // Atomically store newval into addr, if addr currently contains oldval. + // This version is intended for use by C1 assembler, and encodes uncompressed + // oops if necessary. C1 assembler expects flags state to be set according + // to success of the CAS. + void access_cmpxchg_oop_c1(Address addr, Register oldval, Register newval, + Register tmp1, Register tmp2); + void load_heap_oop(Register dst, Address src, Register tmp1 = noreg, Register thread_tmp = noreg, DecoratorSet decorators = 0); void load_heap_oop_not_null(Register dst, Address src, Register tmp1 = noreg,