Fix wide volatile IGET/IPUT on ARM without atomic ldrd/strd.
If ldrd/strd isn't atomic, IPUT_WIDE uses ldrexd+strexd and
we need to record the safepoint for the ldrexd rather than
strexd. IGET_WIDE was simply missing the memory barrier.
Bug: 18993519
Change-Id: I4e9270b994f413c1a047c1c4bb9cce5f29e42cb4
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index 36d065f..73b68a5 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -1040,9 +1040,8 @@
// Use LDREXD for the atomic load. (Expect displacement > 0, don't optimize for == 0.)
RegStorage r_ptr = AllocTemp();
OpRegRegImm(kOpAdd, r_ptr, r_base, displacement);
- LIR* lir = NewLIR3(kThumb2Ldrexd, r_dest.GetLowReg(), r_dest.GetHighReg(), r_ptr.GetReg());
+ load = NewLIR3(kThumb2Ldrexd, r_dest.GetLowReg(), r_dest.GetHighReg(), r_ptr.GetReg());
FreeTemp(r_ptr);
- return lir;
} else {
load = LoadBaseDispBody(r_base, displacement, r_dest, size);
}
@@ -1174,7 +1173,7 @@
GenMemBarrier(kAnyStore);
}
- LIR* store;
+ LIR* null_ck_insn;
if (is_volatile == kVolatile && (size == k64 || size == kDouble) &&
!cu_->compiler_driver->GetInstructionSetFeatures()->
AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd()) {
@@ -1191,17 +1190,16 @@
RegStorage r_temp = AllocTemp();
RegStorage r_temp_high = AllocTemp(false); // We may not have another temp.
if (r_temp_high.Valid()) {
- NewLIR3(kThumb2Ldrexd, r_temp.GetReg(), r_temp_high.GetReg(), r_ptr.GetReg());
+ null_ck_insn = NewLIR3(kThumb2Ldrexd, r_temp.GetReg(), r_temp_high.GetReg(), r_ptr.GetReg());
FreeTemp(r_temp_high);
FreeTemp(r_temp);
} else {
// If we don't have another temp, clobber r_ptr in LDREXD and reload it.
- NewLIR3(kThumb2Ldrexd, r_temp.GetReg(), r_ptr.GetReg(), r_ptr.GetReg());
+ null_ck_insn = NewLIR3(kThumb2Ldrexd, r_temp.GetReg(), r_ptr.GetReg(), r_ptr.GetReg());
FreeTemp(r_temp); // May need the temp for kOpAdd.
OpRegRegImm(kOpAdd, r_ptr, r_base, displacement);
}
- store = NewLIR4(kThumb2Strexd, r_temp.GetReg(), r_src.GetLowReg(), r_src.GetHighReg(),
- r_ptr.GetReg());
+ NewLIR4(kThumb2Strexd, r_temp.GetReg(), r_src.GetLowReg(), r_src.GetHighReg(), r_ptr.GetReg());
OpCmpImmBranch(kCondNe, r_temp, 0, fail_target);
FreeTemp(r_ptr);
} else {
@@ -1210,7 +1208,7 @@
size = k32;
}
- store = StoreBaseDispBody(r_base, displacement, r_src, size);
+ null_ck_insn = StoreBaseDispBody(r_base, displacement, r_src, size);
}
if (UNLIKELY(is_volatile == kVolatile)) {
@@ -1219,7 +1217,7 @@
GenMemBarrier(kAnyAny);
}
- return store;
+ return null_ck_insn;
}
LIR* ArmMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 3733507..d2b32b5 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -939,15 +939,15 @@
}
GenNullCheck(rl_obj.reg, opt_flags);
int field_offset = field_info.FieldOffset().Int32Value();
- LIR* store;
+ LIR* null_ck_insn;
if (IsRef(size)) {
- store = StoreRefDisp(rl_obj.reg, field_offset, rl_src.reg, field_info.IsVolatile() ?
+ null_ck_insn = StoreRefDisp(rl_obj.reg, field_offset, rl_src.reg, field_info.IsVolatile() ?
kVolatile : kNotVolatile);
} else {
- store = StoreBaseDisp(rl_obj.reg, field_offset, rl_src.reg, size,
- field_info.IsVolatile() ? kVolatile : kNotVolatile);
+ null_ck_insn = StoreBaseDisp(rl_obj.reg, field_offset, rl_src.reg, size,
+ field_info.IsVolatile() ? kVolatile : kNotVolatile);
}
- MarkPossibleNullPointerExceptionAfter(opt_flags, store);
+ MarkPossibleNullPointerExceptionAfter(opt_flags, null_ck_insn);
if (IsRef(size) && !mir_graph_->IsConstantNullRef(rl_src)) {
MarkGCCard(opt_flags, rl_src.reg, rl_obj.reg);
}
diff --git a/test/122-npe/src/Main.java b/test/122-npe/src/Main.java
index 2fdcb9c..8f68205 100644
--- a/test/122-npe/src/Main.java
+++ b/test/122-npe/src/Main.java
@@ -191,6 +191,132 @@
check(npe, thisLine += 7);
try {
+ ((Value) null).volatileObjectField.toString();
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ ((Value) null).volatileObjectField = "Fisk";
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ useInt(((Value) null).volatileIntField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ ((Value) null).volatileIntField = 42;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ useFloat(((Value) null).volatileFloatField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ ((Value) null).volatileFloatField = 42.0F;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ useLong(((Value) null).volatileLongField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ ((Value) null).volatileLongField = 42L;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ useDouble(((Value) null).volatileDoubleField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ ((Value) null).volatileDoubleField = 42.0d;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ useInt(((Value) null).volatileByteField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ ((Value) null).volatileByteField = 42;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ if (((Value) null).volatileBooleanField) { }
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ ((Value) null).volatileBooleanField = true;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ useInt(((Value) null).volatileCharField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ ((Value) null).volatileCharField = '\u0042';
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ useInt(((Value) null).volatileShortField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ ((Value) null).volatileShortField = 42;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
((Object[]) null)[0].toString();
} catch (NullPointerException e) {
npe = e;
@@ -477,11 +603,22 @@
static class Value {
Object objectField;
int intField;
- float floatField; long longField;
+ float floatField;
+ long longField;
double doubleField;
byte byteField;
boolean booleanField;
char charField;
short shortField;
+
+ volatile Object volatileObjectField;
+ volatile int volatileIntField;
+ volatile float volatileFloatField;
+ volatile long volatileLongField;
+ volatile double volatileDoubleField;
+ volatile byte volatileByteField;
+ volatile boolean volatileBooleanField;
+ volatile char volatileCharField;
+ volatile short volatileShortField;
}
}