Merge "Ignore monitor exit for field load elimination"
diff --git a/src/main/java/com/android/tools/r8/ir/code/Monitor.java b/src/main/java/com/android/tools/r8/ir/code/Monitor.java
index 6b3c89c..3b1b2d1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Monitor.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Monitor.java
@@ -34,6 +34,14 @@
     return inValues.get(0);
   }
 
+  public boolean isEnter() {
+    return type == Type.ENTER;
+  }
+
+  public boolean isExit() {
+    return type == Type.EXIT;
+  }
+
   @Override
   public void buildDex(DexBuilder builder) {
     // If the monitor object is an argument, we use the argument register for all the monitor
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
index dee935e..905d4a8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
@@ -132,7 +132,8 @@
             }
           }
         }
-        if (instruction.isMonitor() || instruction.isInvokeMethod()) {
+        if ((instruction.isMonitor() && instruction.asMonitor().isEnter())
+            || instruction.isInvokeMethod()) {
           killAllActiveFields();
         }
       }
diff --git a/src/test/java/com/android/tools/r8/regress/b111250398/B111250398.java b/src/test/java/com/android/tools/r8/regress/b111250398/B111250398.java
index 90fba5f..84fc5c4 100644
--- a/src/test/java/com/android/tools/r8/regress/b111250398/B111250398.java
+++ b/src/test/java/com/android/tools/r8/regress/b111250398/B111250398.java
@@ -91,6 +91,16 @@
     t = f;
   }
 
+  public void mfWithMonitor() {
+    t = f;
+    synchronized (this) {
+      t = f;
+      t = f;
+    }
+    t = f;
+    t = f;
+  }
+
   public void msf() {
     t = sf;
     t = sf;
@@ -231,6 +241,8 @@
     assertThat(classA, isPresent());
     MethodSubject mfOnA = classA.method("void", "mf", ImmutableList.of());
     assertThat(mfOnA, isPresent());
+    MethodSubject mfWithMonitorOnA = classA.method("void", "mfWithMonitor", ImmutableList.of());
+    assertThat(mfWithMonitorOnA, isPresent());
     MethodSubject msfOnA = classA.method("void", "msf", ImmutableList.of());
     assertThat(msfOnA, isPresent());
     MethodSubject mvOnA = classA.method("void", "mv", ImmutableList.of());
@@ -264,6 +276,13 @@
     // compilation (R8) will eliminate field loads on non-volatile fields.
     assertEquals(1, countIget(mfOnA.getMethod().getCode().asDexCode(), fOnA.getField().field));
     assertEquals(1, countSget(msfOnA.getMethod().getCode().asDexCode(), sfOnA.getField().field));
+    // TODO(111380066). This could be 2 in stead of 4, but right now the optimization tracks the
+    // combined set of fields for all successors, and for synchronized code all blocks have
+    // exceptional edges for ensuring monitor exit causing the active load to be invalidated for
+    // both normal and exceptional successors.
+    assertEquals(4,
+        countIget(mfWithMonitorOnA.getMethod().getCode().asDexCode(), fOnA.getField().field));
+
     // For fields on other class both separate compilation (D8) and whole program
     // compilation (R8) will differ in the eliminated field loads of non-volatile fields.
     assertEquals(mfOnBGets,