enum MIROptimizationFlagPositions {
kMIRIgnoreNullCheck = 0,
- kMIRNullCheckOnly,
kMIRIgnoreRangeCheck,
- kMIRRangeCheckOnly,
+ kMIRStoreNonNullValue, // Storing non-null value, always mark GC card.
kMIRClassIsInitialized,
kMIRClassIsInDexCache,
kMirIgnoreDivZeroCheck,
// If we're storing a non-aliasing reference, stop tracking it as non-aliasing now.
uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
HandleEscapingRef(base);
+ if (gvn_->CanModify() && null_checked_.count(base) != 0u) {
+ if (gvn_->GetCompilationUnit()->verbose) {
+ LOG(INFO) << "Removing GC card mark value null check for 0x" << std::hex << mir->offset;
+ }
+ mir->optimization_flags |= MIR_STORE_NON_NULL_VALUE;
+ }
}
void LocalValueNumbering::HandleEscapingRef(uint16_t base) {
EXPECT_NE(value_names_[13], value_names_[16]); // New value.
EXPECT_NE(value_names_[14], value_names_[17]); // New value.
for (size_t i = 0u; i != mir_count_; ++i) {
- int expected = (i != 0u && i != 3u && i != 6u) ? MIR_IGNORE_NULL_CHECK : 0;
+ int expected =
+ ((i != 0u && i != 3u && i != 6u) ? MIR_IGNORE_NULL_CHECK : 0) |
+ ((i == 3u) ? MIR_STORE_NON_NULL_VALUE: 0);
EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
}
}
for (size_t i = 0u; i != mir_count_; ++i) {
int expected =
((i != 0u && i != 3u && i != 6u && i != 9u) ? MIR_IGNORE_NULL_CHECK : 0u) |
- ((i >= 4 && i != 6u && i != 9u) ? MIR_IGNORE_RANGE_CHECK : 0u);
+ ((i >= 4 && i != 6u && i != 9u) ? MIR_IGNORE_RANGE_CHECK : 0u) |
+ ((i == 3u) ? MIR_STORE_NON_NULL_VALUE: 0);
EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
}
}
#define INVALID_OFFSET (0xDEADF00FU)
#define MIR_IGNORE_NULL_CHECK (1 << kMIRIgnoreNullCheck)
-#define MIR_NULL_CHECK_ONLY (1 << kMIRNullCheckOnly)
#define MIR_IGNORE_RANGE_CHECK (1 << kMIRIgnoreRangeCheck)
-#define MIR_RANGE_CHECK_ONLY (1 << kMIRRangeCheckOnly)
+#define MIR_STORE_NON_NULL_VALUE (1 << kMIRStoreNonNullValue)
#define MIR_CLASS_IS_INITIALIZED (1 << kMIRClassIsInitialized)
#define MIR_CLASS_IS_IN_DEX_CACHE (1 << kMIRClassIsInDexCache)
#define MIR_IGNORE_DIV_ZERO_CHECK (1 << kMirIgnoreDivZeroCheck)
if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
// Mark card for object assuming new value is stored.
- MarkGCCard(rl_new_value.reg, rl_object.reg);
+ MarkGCCard(0, rl_new_value.reg, rl_object.reg);
}
RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
FreeTemp(reg_ptr);
}
if (card_mark) {
- MarkGCCard(rl_src.reg, rl_array.reg);
+ MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
}
}
if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
// Mark card for object assuming new value is stored.
- MarkGCCard(rl_new_value.reg, rl_object.reg);
+ MarkGCCard(0, rl_new_value.reg, rl_object.reg);
}
RegStorage r_ptr = AllocTempRef();
FreeTemp(reg_ptr);
}
if (card_mark) {
- MarkGCCard(rl_src.reg, rl_array.reg);
+ MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
}
}
}
}
-void Mir2Lir::MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) {
+void Mir2Lir::MarkGCCard(int opt_flags, RegStorage val_reg, RegStorage tgt_addr_reg) {
DCHECK(val_reg.Valid());
DCHECK_EQ(val_reg.Is64Bit(), cu_->target64);
- LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, nullptr);
- UnconditionallyMarkGCCard(tgt_addr_reg);
- LIR* target = NewLIR0(kPseudoTargetLabel);
- branch_over->target = target;
+ if ((opt_flags & MIR_STORE_NON_NULL_VALUE) != 0) {
+ UnconditionallyMarkGCCard(tgt_addr_reg);
+ } else {
+ LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, nullptr);
+ UnconditionallyMarkGCCard(tgt_addr_reg);
+ LIR* target = NewLIR0(kPseudoTargetLabel);
+ branch_over->target = target;
+ }
}
/* Dump instructions and constant pool contents */
field_info.IsVolatile() ? kVolatile : kNotVolatile);
}
if (IsRef(size) && !mir_graph_->IsConstantNullRef(rl_src)) {
- MarkGCCard(rl_src.reg, r_base);
+ MarkGCCard(mir->optimization_flags, rl_src.reg, r_base);
}
FreeTemp(r_base);
} else {
}
MarkPossibleNullPointerExceptionAfter(opt_flags, store);
if (IsRef(size) && !mir_graph_->IsConstantNullRef(rl_src)) {
- MarkGCCard(rl_src.reg, rl_obj.reg);
+ MarkGCCard(opt_flags, rl_src.reg, rl_obj.reg);
}
} else {
QuickEntrypointEnum target;
GenMemBarrier(kAnyAny);
}
if (is_object) {
- MarkGCCard(rl_value.reg, rl_object.reg);
+ MarkGCCard(0, rl_value.reg, rl_object.reg);
}
return true;
}
FreeTemp(reg_ptr);
}
if (card_mark) {
- MarkGCCard(rl_src.reg, rl_array.reg);
+ MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
}
}
kNotVolatile);
}
if (IsRef(size)) {
- MarkGCCard(reg_src, reg_obj);
+ MarkGCCard(0, reg_src, reg_obj);
}
return true;
}
* @brief Mark a garbage collection card. Skip if the stored value is null.
* @param val_reg the register holding the stored value to check against null.
* @param tgt_addr_reg the address of the object or array where the value was stored.
+ * @param opt_flags the optimization flags which may indicate that the value is non-null.
*/
- void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
+ void MarkGCCard(int opt_flags, RegStorage val_reg, RegStorage tgt_addr_reg);
/*
* @brief Load the address of the dex method into the register.
if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
// Mark card for object assuming new value is stored.
FreeTemp(rs_r0); // Temporarily release EAX for MarkGCCard().
- MarkGCCard(rl_new_value.reg, rl_object.reg);
+ MarkGCCard(0, rl_new_value.reg, rl_object.reg);
LockTemp(rs_r0);
}
if (!constant_index) {
FreeTemp(rl_index.reg);
}
- MarkGCCard(rl_src.reg, rl_array.reg);
+ MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
}
}