summaryrefslogtreecommitdiff
path: root/compiler/optimizing/graph_checker.cc
diff options
context:
space:
mode:
author Santiago Aboy Solanes <solanes@google.com> 2024-01-25 09:56:06 +0000
committer Santiago Aboy Solanes <solanes@google.com> 2024-01-29 08:47:22 +0000
commitd76551c7229060a3fe11258b490a11f4ee91e9f8 (patch)
treef8fcb5e839b1d2c0a61347b764f6a76dda117a84 /compiler/optimizing/graph_checker.cc
parentb782659336403e125e33f829afad49b901027c22 (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.cc95
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) {