diff options
author | 2024-01-25 09:56:06 +0000 | |
---|---|---|
committer | 2024-01-29 08:47:22 +0000 | |
commit | d76551c7229060a3fe11258b490a11f4ee91e9f8 (patch) | |
tree | f8fcb5e839b1d2c0a61347b764f6a76dda117a84 /compiler/optimizing/graph_checker.cc | |
parent | b782659336403e125e33f829afad49b901027c22 (diff) |
Revert^7 "Disable write-barrier elimination pass"
This reverts commit 1ba3516e8c3e2b86c73084893dd297f468469181.
Reason for revert:
PS1 is reland as-is
PS2 has two related fixes (for RISC-V and arm64) taking into
account that when we store zero, we use a special register.
Bug: 301833859
Bug: 310755375
Bug: 260843353
Test: lunch cf_riscv64_wear-trunk_staging-userdebug && m
Test: lunch starnix_wear_yukawa-trunk_staging-userdebug && m
Change-Id: I5e69890fd56404ddde56ebc457179241363d9243
Diffstat (limited to 'compiler/optimizing/graph_checker.cc')
-rw-r--r-- | compiler/optimizing/graph_checker.cc | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc index d4b0bf2e81..d60ec06097 100644 --- a/compiler/optimizing/graph_checker.cc +++ b/compiler/optimizing/graph_checker.cc @@ -31,6 +31,7 @@ #include "mirror/class.h" #include "nodes.h" #include "obj_ptr-inl.h" +#include "optimizing/data_type.h" #include "scoped_thread_state_change-inl.h" #include "subtype_check.h" @@ -1273,6 +1274,26 @@ void GraphChecker::VisitNeg(HNeg* instruction) { } } +HInstruction* HuntForOriginalReference(HInstruction* ref) { + // An original reference can be transformed by instructions like: + // i0 NewArray + // i1 HInstruction(i0) <-- NullCheck, BoundType, IntermediateAddress. + // i2 ArraySet(i1, index, value) + DCHECK(ref != nullptr); + while (ref->IsNullCheck() || ref->IsBoundType() || ref->IsIntermediateAddress()) { + ref = ref->InputAt(0); + } + return ref; +} + +bool IsRemovedWriteBarrier(DataType::Type type, + WriteBarrierKind write_barrier_kind, + HInstruction* value) { + return write_barrier_kind == WriteBarrierKind::kDontEmit && + type == DataType::Type::kReference && + !value->IsNullConstant(); +} + void GraphChecker::VisitArraySet(HArraySet* instruction) { VisitInstruction(instruction); @@ -1286,6 +1307,80 @@ void GraphChecker::VisitArraySet(HArraySet* instruction) { StrBool(instruction->NeedsTypeCheck()), StrBool(instruction->GetSideEffects().Includes(SideEffects::CanTriggerGC())))); } + + if (IsRemovedWriteBarrier(instruction->GetComponentType(), + instruction->GetWriteBarrierKind(), + instruction->GetValue())) { + CheckWriteBarrier(instruction, [](HInstruction* it_instr) { + return it_instr->AsArraySet()->GetWriteBarrierKind(); + }); + } +} + +void GraphChecker::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { + VisitInstruction(instruction); + if (IsRemovedWriteBarrier(instruction->GetFieldType(), + instruction->GetWriteBarrierKind(), + instruction->GetValue())) { + CheckWriteBarrier(instruction, [](HInstruction* it_instr) { + return it_instr->AsInstanceFieldSet()->GetWriteBarrierKind(); + }); + } +} + +void GraphChecker::VisitStaticFieldSet(HStaticFieldSet* instruction) { + VisitInstruction(instruction); + if (IsRemovedWriteBarrier(instruction->GetFieldType(), + instruction->GetWriteBarrierKind(), + instruction->GetValue())) { + CheckWriteBarrier(instruction, [](HInstruction* it_instr) { + return it_instr->AsStaticFieldSet()->GetWriteBarrierKind(); + }); + } +} + +template <typename GetWriteBarrierKind> +void GraphChecker::CheckWriteBarrier(HInstruction* instruction, + GetWriteBarrierKind&& get_write_barrier_kind) { + DCHECK(instruction->IsStaticFieldSet() || + instruction->IsInstanceFieldSet() || + instruction->IsArraySet()); + + // For removed write barriers, we expect that the write barrier they are relying on is: + // A) In the same block, and + // B) There's no instruction between them that can trigger a GC. + HInstruction* object = HuntForOriginalReference(instruction->InputAt(0)); + bool found = false; + for (HBackwardInstructionIterator it(instruction); !it.Done(); it.Advance()) { + if (instruction->GetKind() == it.Current()->GetKind() && + object == HuntForOriginalReference(it.Current()->InputAt(0)) && + get_write_barrier_kind(it.Current()) == WriteBarrierKind::kEmitBeingReliedOn) { + // Found the write barrier we are relying on. + found = true; + break; + } + + // We check the `SideEffects::CanTriggerGC` after failing to find the write barrier since having + // a write barrier that's relying on an ArraySet that can trigger GC is fine because the card + // table is marked after the GC happens. + if (it.Current()->GetSideEffects().Includes(SideEffects::CanTriggerGC())) { + AddError( + StringPrintf("%s %d from block %d was expecting a write barrier and it didn't find " + "any. %s %d can trigger GC", + instruction->DebugName(), + instruction->GetId(), + instruction->GetBlock()->GetBlockId(), + it.Current()->DebugName(), + it.Current()->GetId())); + } + } + + if (!found) { + AddError(StringPrintf("%s %d in block %d didn't find a write barrier to latch onto", + instruction->DebugName(), + instruction->GetId(), + instruction->GetBlock()->GetBlockId())); + } } void GraphChecker::VisitBinaryOperation(HBinaryOperation* op) { |