summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbuzbee <buzbee@google.com>2013-09-14 08:21:05 -0700
committerBill Buzbee <buzbee@google.com>2013-09-14 20:56:54 +0000
commit5666afd6854b5634ae741dc8a3a633fc47d52168 (patch)
tree0260272bc233589d22fb18511b9f15753f58dc26
parent6fc9251ae4f34c31351d9d902dd6c6cbc7baba1c (diff)
downloadart-5666afd6854b5634ae741dc8a3a633fc47d52168.zip
art-5666afd6854b5634ae741dc8a3a633fc47d52168.tar.gz
art-5666afd6854b5634ae741dc8a3a633fc47d52168.tar.bz2
Timely color fix
See b/10690000 For efficiency, the Quick compiler will not flush incoming register arguments to the frame if their underlying Dalvik virtual registers have been promoted to physical registers. In this case, though, there was a bug on Arm devices in that an incoming Double was promoted to physical floating point registers, but not in a usable form. The entry code generation saw that both halves of the double were promoted, but failed to check if it was in a form usable as a double. In this particular case, it meant that subsequent uses of the incoming argument referred to the uninitialized home location in the frame, resulting in garbage color values. That's the bug. Another problem is that the incoming double should never have been promoted to an unusable state in the first place - but that's merely an efficiency issue and will be addressed in another CL. Note: no good way to generate a regression test for this issue. The bug triggered because of an unusual sequence of events driving register promotion that can't easily (or robustly) be triggered from Java source. Change-Id: I7242422277193a04376461134dde71e9dec55576 (cherry picked from commit d0a03b8099347dee6e4bab3af95e14cd5a03b29c)
-rw-r--r--compiler/dex/quick/gen_invoke.cc19
1 files changed, 18 insertions, 1 deletions
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 073b550..2a0a23c 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -283,11 +283,28 @@ void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) {
need_flush = true;
}
- // For wide args, force flush if only half is promoted
+ // For wide args, force flush if not fully promoted
if (t_loc->wide) {
PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1);
+ // Is only half promoted?
need_flush |= (p_map->core_location != v_map->core_location) ||
(p_map->fp_location != v_map->fp_location);
+ if ((cu_->instruction_set == kThumb2) && t_loc->fp && !need_flush) {
+ /*
+ * In Arm, a double is represented as a pair of consecutive single float
+ * registers starting at an even number. It's possible that both Dalvik vRegs
+ * representing the incoming double were independently promoted as singles - but
+ * not in a form usable as a double. If so, we need to flush - even though the
+ * incoming arg appears fully in register. At this point in the code, both
+ * halves of the double are promoted. Make sure they are in a usable form.
+ */
+ int lowreg_index = start_vreg + i + (t_loc->high_word ? -1 : 0);
+ int low_reg = promotion_map_[lowreg_index].FpReg;
+ int high_reg = promotion_map_[lowreg_index + 1].FpReg;
+ if (((low_reg & 0x1) != 0) || (high_reg != (low_reg + 1))) {
+ need_flush = true;
+ }
+ }
}
if (need_flush) {
StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i),