7009231: C1: Incorrect CAS code for longs on SPARC 32bit
Fix CAS of longs on SPARC 32bit and cmove on SPARC 64bit. Reviewed-by: kvn
This commit is contained in:
parent
a8a98509e7
commit
43280aa63e
@ -1705,8 +1705,7 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op
|
||||
}
|
||||
|
||||
|
||||
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 @@ void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, L
|
||||
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 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
|
||||
#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 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
|
||||
__ 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();
|
||||
|
@ -662,7 +662,7 @@ void LIRGenerator::do_AttemptUpdate(Intrinsic* x) {
|
||||
|
||||
// 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 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
|
||||
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());
|
||||
|
@ -2036,7 +2036,7 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -741,7 +741,7 @@ void LIRGenerator::do_AttemptUpdate(Intrinsic* x) {
|
||||
|
||||
// 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 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
|
||||
|
||||
// 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());
|
||||
|
@ -1568,15 +1568,16 @@ class LIR_Op2: public LIR_Op {
|
||||
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 @@ class LIR_List: public CompilationResourceObj {
|
||||
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,
|
||||
|
@ -685,7 +685,7 @@ void LIR_Assembler::emit_op2(LIR_Op2* op) {
|
||||
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:
|
||||
|
@ -217,7 +217,7 @@ class LIR_Assembler: public CompilationResourceObj {
|
||||
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);
|
||||
|
@ -856,7 +856,7 @@ void LIRGenerator::profile_branch(If* if_instr, If::Condition cond) {
|
||||
__ 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 @@ void LIRGenerator::do_IfOp(IfOp* x) {
|
||||
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()));
|
||||
}
|
||||
|
||||
|
||||
|
100
hotspot/test/compiler/7009231/Test7009231.java
Normal file
100
hotspot/test/compiler/7009231/Test7009231.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user