Make inlined CAS32 loop until store is successful if values match.
The native implementation of compareAndSwap uses android_atomic_cas,
which will repeat the strex until it succeeds. The compiled version
was changed to do the same.
Bug: 10530407
Change-Id: I7efb3f92d0d0610fcc5a885e2c97f1d701b5a4ea
(cherry picked from commit 2de2aa1a96dfa5bebc004f29b5dbfafd37039cee)
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index f2ff58e..6fbdd2f 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -535,25 +535,26 @@
ClobberSReg(rl_offset.s_reg_low);
FreeTemp(rl_offset.low_reg);
- int r_old_value = AllocTemp();
- NewLIR3(kThumb2Ldrex, r_old_value, r_ptr, 0); // r_old_value := [r_ptr]
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ LoadConstant(rl_result.low_reg, 0); // r_result := 0
- RegLocation rl_expected = LoadValue(rl_src_expected, kCoreReg);
-
- // if (r_old_value == rExpected) {
+ // while ([r_ptr] == rExpected && r_result == 0) {
// [r_ptr] <- r_new_value && r_result := success ? 0 : 1
// r_result ^= 1
- // } else {
- // r_result := 0
// }
+ int r_old_value = AllocTemp();
+ LIR* target = NewLIR0(kPseudoTargetLabel);
+ NewLIR3(kThumb2Ldrex, r_old_value, r_ptr, 0);
+
+ RegLocation rl_expected = LoadValue(rl_src_expected, kCoreReg);
OpRegReg(kOpCmp, r_old_value, rl_expected.low_reg);
FreeTemp(r_old_value); // Now unneeded.
- RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
- OpIT(kCondEq, "TE");
- NewLIR4(kThumb2Strex, rl_result.low_reg, rl_new_value.low_reg, r_ptr, 0);
+ OpIT(kCondEq, "TT");
+ NewLIR4(kThumb2Strex /* eq */, rl_result.low_reg, rl_new_value.low_reg, r_ptr, 0);
FreeTemp(r_ptr); // Now unneeded.
- OpRegImm(kOpXor, rl_result.low_reg, 1);
- OpRegReg(kOpXor, rl_result.low_reg, rl_result.low_reg);
+ OpRegImm(kOpXor /* eq */, rl_result.low_reg, 1);
+ OpRegImm(kOpCmp /* eq */, rl_result.low_reg, 0);
+ OpCondBranch(kCondEq, target);
StoreValue(rl_dest, rl_result);