# HG changeset patch # User iveresov # Date 1293515491 28800 # Node ID 1e06d2419258e3720f2babde279bf3d45d53be64 # Parent cee30a0f431568b8d73335547e0b98f0374bf18c 7009231: C1: Incorrect CAS code for longs on SPARC 32bit Summary: Fix CAS of longs on SPARC 32bit and cmove on SPARC 64bit. Reviewed-by: kvn diff -r cee30a0f4315 -r 1e06d2419258 hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Wed Dec 22 02:02:53 2010 -0800 +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Mon Dec 27 21:51:31 2010 -0800 @@ -1705,8 +1705,7 @@ } -void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result) { - +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { Assembler::Condition acond; switch (condition) { case lir_cond_equal: acond = Assembler::equal; break; @@ -1737,7 +1736,12 @@ ShouldNotReachHere(); } Label skip; - __ br(acond, false, Assembler::pt, skip); +#ifdef _LP64 + if (type == T_INT) { + __ br(acond, false, Assembler::pt, skip); + } else +#endif + __ brx(acond, false, Assembler::pt, skip); // checks icc on 32bit and xcc on 64bit if (opr1->is_constant() && opr1->type() == T_INT) { Register dest = result->as_register(); if (Assembler::is_simm13(opr1->as_jint())) { @@ -2688,6 +2692,11 @@ #ifdef _LP64 __ mov(cmp_value_lo, t1); __ mov(new_value_lo, t2); + // perform the compare and swap operation + __ casx(addr, t1, t2); + // generate condition code - if the swap succeeded, t2 ("new value" reg) was + // overwritten with the original value in "addr" and will be equal to t1. + __ cmp(t1, t2); #else // move high and low halves of long values into single registers __ sllx(cmp_value_hi, 32, t1); // shift high half into temp reg @@ -2696,13 +2705,15 @@ __ sllx(new_value_hi, 32, t2); __ srl(new_value_lo, 0, new_value_lo); __ or3(t2, new_value_lo, t2); // t2 holds 64-bit value to swap -#endif // perform the compare and swap operation __ casx(addr, t1, t2); // generate condition code - if the swap succeeded, t2 ("new value" reg) was // overwritten with the original value in "addr" and will be equal to t1. - __ cmp(t1, t2); - + // Produce icc flag for 32bit. + __ sub(t1, t2, t2); + __ srlx(t2, 32, t1); + __ orcc(t2, t1, G0); +#endif } else if (op->code() == lir_cas_int || op->code() == lir_cas_obj) { Register addr = op->addr()->as_pointer_register(); Register cmp_value = op->cmp_value()->as_register(); diff -r cee30a0f4315 -r 1e06d2419258 hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Wed Dec 22 02:02:53 2010 -0800 +++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Mon Dec 27 21:51:31 2010 -0800 @@ -662,7 +662,7 @@ // generate conditional move of boolean result LIR_Opr result = rlock_result(x); - __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), result); + __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), result, T_LONG); } @@ -699,10 +699,10 @@ else { ShouldNotReachHere(); } - // generate conditional move of boolean result LIR_Opr result = rlock_result(x); - __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), result); + __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), + result, as_BasicType(type)); if (type == objectType) { // Write-barrier needed for Object fields. // Precise card mark since could either be object or array post_barrier(addr, val.result()); diff -r cee30a0f4315 -r 1e06d2419258 hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Wed Dec 22 02:02:53 2010 -0800 +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Mon Dec 27 21:51:31 2010 -0800 @@ -2036,7 +2036,7 @@ } } -void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result) { +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { Assembler::Condition acond, ncond; switch (condition) { case lir_cond_equal: acond = Assembler::equal; ncond = Assembler::notEqual; break; diff -r cee30a0f4315 -r 1e06d2419258 hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Wed Dec 22 02:02:53 2010 -0800 +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Mon Dec 27 21:51:31 2010 -0800 @@ -741,7 +741,7 @@ // generate conditional move of boolean result LIR_Opr result = rlock_result(x); - __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), result); + __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), result, T_LONG); } @@ -810,7 +810,8 @@ // generate conditional move of boolean result LIR_Opr result = rlock_result(x); - __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), result); + __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), + result, as_BasicType(type)); if (type == objectType) { // Write-barrier needed for Object fields. // Seems to be precise post_barrier(addr, val.result()); diff -r cee30a0f4315 -r 1e06d2419258 hotspot/src/share/vm/c1/c1_LIR.hpp --- a/hotspot/src/share/vm/c1/c1_LIR.hpp Wed Dec 22 02:02:53 2010 -0800 +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp Mon Dec 27 21:51:31 2010 -0800 @@ -1568,15 +1568,16 @@ assert(code == lir_cmp, "code check"); } - LIR_Op2(LIR_Code code, LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result) + LIR_Op2(LIR_Code code, LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) : LIR_Op(code, result, NULL) , _opr1(opr1) , _opr2(opr2) - , _type(T_ILLEGAL) + , _type(type) , _condition(condition) , _fpu_stack_size(0) , _tmp(LIR_OprFact::illegalOpr) { assert(code == lir_cmove, "code check"); + assert(type != T_ILLEGAL, "cmove should have type"); } LIR_Op2(LIR_Code code, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result = LIR_OprFact::illegalOpr, @@ -1993,8 +1994,8 @@ void cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info); void cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Address* addr, CodeEmitInfo* info); - void cmove(LIR_Condition condition, LIR_Opr src1, LIR_Opr src2, LIR_Opr dst) { - append(new LIR_Op2(lir_cmove, condition, src1, src2, dst)); + void cmove(LIR_Condition condition, LIR_Opr src1, LIR_Opr src2, LIR_Opr dst, BasicType type) { + append(new LIR_Op2(lir_cmove, condition, src1, src2, dst, type)); } void cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, diff -r cee30a0f4315 -r 1e06d2419258 hotspot/src/share/vm/c1/c1_LIRAssembler.cpp --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Wed Dec 22 02:02:53 2010 -0800 +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Mon Dec 27 21:51:31 2010 -0800 @@ -685,7 +685,7 @@ break; case lir_cmove: - cmove(op->condition(), op->in_opr1(), op->in_opr2(), op->result_opr()); + cmove(op->condition(), op->in_opr1(), op->in_opr2(), op->result_opr(), op->type()); break; case lir_shl: diff -r cee30a0f4315 -r 1e06d2419258 hotspot/src/share/vm/c1/c1_LIRAssembler.hpp --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp Wed Dec 22 02:02:53 2010 -0800 +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp Mon Dec 27 21:51:31 2010 -0800 @@ -217,7 +217,7 @@ void volatile_move_op(LIR_Opr src, LIR_Opr result, BasicType type, CodeEmitInfo* info); void comp_mem_op(LIR_Opr src, LIR_Opr result, BasicType type, CodeEmitInfo* info); // info set for null exceptions void comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr result, LIR_Op2* op); - void cmove(LIR_Condition code, LIR_Opr left, LIR_Opr right, LIR_Opr result); + void cmove(LIR_Condition code, LIR_Opr left, LIR_Opr right, LIR_Opr result, BasicType type); void call( LIR_OpJavaCall* op, relocInfo::relocType rtype); void ic_call( LIR_OpJavaCall* op); diff -r cee30a0f4315 -r 1e06d2419258 hotspot/src/share/vm/c1/c1_LIRGenerator.cpp --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Wed Dec 22 02:02:53 2010 -0800 +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Mon Dec 27 21:51:31 2010 -0800 @@ -856,7 +856,7 @@ __ cmove(lir_cond(cond), LIR_OprFact::intptrConst(taken_count_offset), LIR_OprFact::intptrConst(not_taken_count_offset), - data_offset_reg); + data_offset_reg, as_BasicType(if_instr->x()->type())); // MDO cells are intptr_t, so the data_reg width is arch-dependent. LIR_Opr data_reg = new_pointer_register(); @@ -2591,7 +2591,7 @@ LIR_Opr reg = rlock_result(x); __ cmp(lir_cond(x->cond()), left.result(), right.result()); - __ cmove(lir_cond(x->cond()), t_val.result(), f_val.result(), reg); + __ cmove(lir_cond(x->cond()), t_val.result(), f_val.result(), reg, as_BasicType(x->x()->type())); } diff -r cee30a0f4315 -r 1e06d2419258 hotspot/test/compiler/7009231/Test7009231.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/7009231/Test7009231.java Mon Dec 27 21:51:31 2010 -0800 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +/** + * @test + * @bug 7009231 + * @summary C1: Incorrect CAS code for longs on SPARC 32bit + * + * @run main/othervm -Xbatch Test7009231 + * + */ + +import java.util.Random; +import java.util.concurrent.atomic.AtomicLong; + + +public class Test7009231 { + public static void main(String[] args) throws InterruptedException { + doTest(8); + } + + private static void doTest(int nThreads) throws InterruptedException { + Thread[] aThreads = new Thread[nThreads]; + final AtomicLong atl = new AtomicLong(); + + for (int i = 0; i < nThreads; i++) { + aThreads[i] = new RunnerThread(atl, 1L << (8 * i)); + } + + for (int i = 0; i < nThreads; i++) { + aThreads[i].start(); + } + + for (int i = 0; i < nThreads; i++) { + aThreads[i].join(); + } + } + + public static class RunnerThread extends Thread { + public RunnerThread(AtomicLong atomic, long lMask) { + m_lMask = lMask; + m_atomic = atomic; + } + + public void run() { + AtomicLong atomic = m_atomic; + long lMask = m_lMask; + for (int i = 0; i < 100000; i++) { + setBit(atomic, lMask); + clearBit(atomic, lMask); + } + } + + protected void setBit(AtomicLong atomic, long lMask) { + long lWord; + do { + lWord = atomic.get(); + } while (!atomic.compareAndSet(lWord, lWord | lMask)); + + if ((atomic.get() & lMask) == 0L) { + throw new InternalError(); + } + } + + protected void clearBit(AtomicLong atomic, long lMask) { + long lWord; + do { + lWord = atomic.get(); + } while (!atomic.compareAndSet(lWord, lWord & ~lMask)); + + if ((atomic.get() & lMask) != 0L) { + throw new InternalError(); + } + } + + private long m_lMask; + private AtomicLong m_atomic; + } +}