Merge commit 'a2ffb5e15aa342650f0aa5fdd16f8effc77661ee' into dev-release

Change-Id: Ic73cfbd73d08c5800226461f02bf48d8b63df2c3
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 0bd58e6..1372ccb 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -387,7 +387,7 @@
         R8Command.Builder r8Builder =
             R8Command.builder(getReporter())
                 .addProgramResourceProvider((ProgramResourceProvider) l8CfConsumer)
-                .setEnableEmptyMemberRulesToDefaultInitRuleConversion(false)
+                .enableLegacyFullModeForKeepRules(false)
                 .setSynthesizedClassesPrefix(
                     desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix())
                 .setMinApiLevel(getMinApiLevel())
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 52ae388..489f9e0 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -506,10 +506,15 @@
      *
      * <p>This currently defaults to true in stable versions.
      */
-    public Builder setEnableEmptyMemberRulesToDefaultInitRuleConversion(
-        boolean enableEmptyMemberRulesToDefaultInitRuleConversion) {
-      parserOptionsBuilder.setEnableEmptyMemberRulesToDefaultInitRuleConversion(
-          enableEmptyMemberRulesToDefaultInitRuleConversion);
+    public Builder enableLegacyFullModeForKeepRules(boolean enableLegacyFullModeForKeepRules) {
+      parserOptionsBuilder.setEnableLegacyFullModeForKeepRules(enableLegacyFullModeForKeepRules);
+      return this;
+    }
+
+    public Builder enableLegacyFullModeForKeepRulesWarnings(
+        boolean enableLegacyFullModeForKeepRulesWarnings) {
+      parserOptionsBuilder.setEnableLegacyFullModeForKeepRulesWarnings(
+          enableLegacyFullModeForKeepRulesWarnings);
       return this;
     }
 
diff --git a/src/main/java/com/android/tools/r8/R8Partial.java b/src/main/java/com/android/tools/r8/R8Partial.java
index 42b5b5b..2fc67d4 100644
--- a/src/main/java/com/android/tools/r8/R8Partial.java
+++ b/src/main/java/com/android/tools/r8/R8Partial.java
@@ -220,7 +220,7 @@
             .addClasspathFiles(d8Program)
             .addProgramFiles(r8Program)
             .addProguardConfigurationFiles(dump.getProguardConfigFile(), traceReferencesRules)
-            .setEnableEmptyMemberRulesToDefaultInitRuleConversion(true)
+            .enableLegacyFullModeForKeepRules(true)
             .setMode(dump.getBuildProperties().getCompilationMode())
             .setOutput(r8Output, OutputMode.DexIndexed);
     if (dump.hasDesugaredLibrary()) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 8f6be1b..3ac2bd6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -693,6 +693,8 @@
       new JavaLangReflectArrayMembers();
   public final JavaLangAnnotationRetentionPolicyMembers javaLangAnnotationRetentionPolicyMembers =
       new JavaLangAnnotationRetentionPolicyMembers();
+  public final JavaLangInvokeVarHandleMembers javaLangInvokeVarHandleMembers =
+      new JavaLangInvokeVarHandleMembers();
   public final JavaLangSystemMembers javaLangSystemMembers = new JavaLangSystemMembers();
   public final JavaIoPrintStreamMembers javaIoPrintStreamMembers = new JavaIoPrintStreamMembers();
   public final NullPointerExceptionMethods npeMethods = new NullPointerExceptionMethods();
@@ -2023,6 +2025,14 @@
     private JavaLangAnnotationRetentionPolicyMembers() {}
   }
 
+  public class JavaLangInvokeVarHandleMembers {
+
+    public final DexMethod storeStoreFence =
+        createMethod(varHandleType, createProto(voidType), "storeStoreFence");
+
+    private JavaLangInvokeVarHandleMembers() {}
+  }
+
   public class JavaLangReflectArrayMembers {
 
     public final DexMethod newInstanceMethodWithDimensions =
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java
index 93b681a..9528327 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java
@@ -33,6 +33,7 @@
 import com.android.tools.r8.ir.desugar.lambda.LambdaDeserializationMethodRemover;
 import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
+import com.android.tools.r8.kotlin.KotlinInlineMethodRemover;
 import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.threading.ThreadingModule;
@@ -57,6 +58,7 @@
   public void convert(AppView<AppInfo> appView, ExecutorService executorService)
       throws ExecutionException {
     LambdaDeserializationMethodRemover.run(appView);
+    new KotlinInlineMethodRemover(appView).run(executorService);
     workaroundAbstractMethodOnNonAbstractClassVerificationBug(executorService);
     DexApplication application = appView.appInfo().app();
     ProfileCollectionAdditions profileCollectionAdditions =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index 473d188..a3881fc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -489,6 +489,7 @@
     // Make sure constructor inlining is legal.
     if (singleTarget.getDefinition().isInstanceInitializer()
         && !canInlineInstanceInitializer(
+            actionBuilder,
             code,
             invoke.asInvokeDirect(),
             singleTarget,
@@ -655,6 +656,7 @@
   @Override
   @SuppressWarnings("ReferenceEquality")
   public boolean canInlineInstanceInitializer(
+      InlineAction.Builder actionBuilder,
       IRCode code,
       InvokeDirect invoke,
       ProgramMethod singleTarget,
@@ -687,7 +689,6 @@
       return true;
     }
 
-    @SuppressWarnings("ReferenceEquality")
     // Only allow inlining a constructor into a non-constructor if:
     // (1) the first use of the uninitialized object is the receiver of an invoke of <init>(),
     // (2) the constructor does not initialize any final fields, as such is only allowed from within
@@ -727,11 +728,24 @@
         InstancePut instancePut = instruction.asInstancePut();
         DexField field = instancePut.getField();
         DexEncodedField target = appView.appInfo().lookupInstanceTarget(field);
-        if (target == null || target.isFinal()) {
-          whyAreYouNotInliningReporter.reportUnsafeConstructorInliningDueToFinalFieldAssignment(
+        if (target == null) {
+          whyAreYouNotInliningReporter.reportUnsafeConstructorInliningDueToMissingFieldAssignment(
               instancePut);
           return false;
         }
+        if (target.isFinal()) {
+          // TODO(b/278964529): We should unset the final flag for good measure. Find a way to do
+          //  this in a thread safe manner.
+          if (inlinerOptions.enableConstructorInliningWithFinalFields
+              && options.canAssignFinalInstanceFieldOutsideConstructor()
+              && options.canUseJavaLangVarHandleStoreStoreFence(appView)) {
+            actionBuilder.setShouldEnsureStoreStoreBarrier();
+          } else {
+            whyAreYouNotInliningReporter.reportUnsafeConstructorInliningDueToFinalFieldAssignment(
+                instancePut);
+            return false;
+          }
+        }
       }
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
index a3fb7e7..5b67472 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
@@ -84,6 +84,7 @@
 
   @Override
   public boolean canInlineInstanceInitializer(
+      InlineAction.Builder actionBuilder,
       IRCode code,
       InvokeDirect invoke,
       ProgramMethod singleTarget,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 99463ac..d73ab2a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -37,6 +37,7 @@
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeStatic;
 import com.android.tools.r8.ir.code.InvokeVirtual;
 import com.android.tools.r8.ir.code.Monitor;
 import com.android.tools.r8.ir.code.MonitorType;
@@ -564,6 +565,7 @@
     final Reason reason;
 
     private boolean shouldEnsureStaticInitialization;
+    private boolean shouldEnsureStoreStoreBarrier;
 
     private DexProgramClass downcastClass;
 
@@ -594,6 +596,10 @@
       shouldEnsureStaticInitialization = true;
     }
 
+    void setShouldEnsureStoreStoreBarrier() {
+      shouldEnsureStoreStoreBarrier = true;
+    }
+
     boolean mustBeInlined() {
       return reason == Reason.ALWAYS;
     }
@@ -620,6 +626,11 @@
             failingBlock -> synthesizeInitClass(code, failingBlock));
       }
 
+      // Insert a store-store barrier at the end of the method.
+      if (shouldEnsureStoreStoreBarrier) {
+        synthesizeStoreStoreBarrier(appView, code);
+      }
+
       // Insert a null check if this is needed to preserve the implicit null check for the receiver.
       // This is only needed if we do not also insert a monitor-enter instruction, since that will
       // throw a NPE if the receiver is null.
@@ -812,6 +823,29 @@
       }
     }
 
+    private void synthesizeStoreStoreBarrier(AppView<AppInfoWithLiveness> appView, IRCode code) {
+      assert target.getDefinition().isInstanceInitializer();
+      BasicBlockIterator blockIterator = code.listIterator();
+      while (blockIterator.hasNext()) {
+        BasicBlock block = blockIterator.next();
+        if (!block.isReturnBlock()) {
+          continue;
+        }
+        // It is an invariant that return blocks do not have catch handlers.
+        assert !block.hasCatchHandlers();
+        InstructionListIterator instructionIterator =
+            block.listIterator(code, block.getInstructions().size() - 1);
+        DexMethod storeStoreFenceMethod =
+            appView.dexItemFactory().javaLangInvokeVarHandleMembers.storeStoreFence;
+        assert appView.definitionFor(storeStoreFenceMethod) != null;
+        instructionIterator.add(
+            InvokeStatic.builder()
+                .setMethod(storeStoreFenceMethod)
+                .setPosition(Position.syntheticNone())
+                .build());
+      }
+    }
+
     private void setRemoveInnerFramePositionForReceiverUse(Instruction instruction) {
       Position position = instruction.getPosition();
       if (position == null) {
@@ -831,6 +865,7 @@
       private InvokeMethod invoke;
       private Reason reason;
       private boolean shouldEnsureStaticInitialization;
+      private boolean shouldEnsureStoreStoreBarrier;
       private ProgramMethod target;
 
       Builder setDowncastClass(DexProgramClass downcastClass) {
@@ -853,6 +888,11 @@
         return this;
       }
 
+      Builder setShouldEnsureStoreStoreBarrier() {
+        this.shouldEnsureStoreStoreBarrier = true;
+        return this;
+      }
+
       Builder setTarget(ProgramMethod target) {
         this.target = target;
         return this;
@@ -866,6 +906,9 @@
         if (shouldEnsureStaticInitialization) {
           action.setShouldEnsureStaticInitialization();
         }
+        if (shouldEnsureStoreStoreBarrier) {
+          action.setShouldEnsureStoreStoreBarrier();
+        }
         return action;
       }
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
index a684ab7..e24b2c1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
@@ -30,6 +30,7 @@
   AppView<AppInfoWithLiveness> appView();
 
   boolean canInlineInstanceInitializer(
+      InlineAction.Builder actionBuilder,
       IRCode code,
       InvokeDirect invoke,
       ProgramMethod singleTarget,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index ab67530..aa435cf 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -748,7 +748,9 @@
       FieldAndObject fieldAndObject = new FieldAndObject(field.getReference(), object);
       ExistingValue value = new ExistingValue(instancePut.value());
       if (field.isFinalOrEffectivelyFinal(appView)) {
-        assert !field.getDefinition().isFinal() || method.getDefinition().isInstanceInitializer();
+        assert !field.getDefinition().isFinal()
+            || method.getDefinition().isInstanceInitializer()
+            || options.inlinerOptions().enableConstructorInliningWithFinalFields;
         activeState.putFinalOrEffectivelyFinalInstanceField(fieldAndObject, value);
       } else {
         activeState.putNonFinalInstanceField(fieldAndObject, value);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java
index cb7523f..0f939fc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/NopWhyAreYouNotInliningReporter.java
@@ -118,6 +118,9 @@
   public void reportUnsafeConstructorInliningDueToFinalFieldAssignment(InstancePut instancePut) {}
 
   @Override
+  public void reportUnsafeConstructorInliningDueToMissingFieldAssignment(InstancePut instancePut) {}
+
+  @Override
   public void reportUnsafeConstructorInliningDueToIndirectConstructorCall(InvokeDirect invoke) {}
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
index ca2d508..e70e49e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporter.java
@@ -114,6 +114,9 @@
   public abstract void reportUnsafeConstructorInliningDueToFinalFieldAssignment(
       InstancePut instancePut);
 
+  public abstract void reportUnsafeConstructorInliningDueToMissingFieldAssignment(
+      InstancePut instancePut);
+
   public abstract void reportUnsafeConstructorInliningDueToIndirectConstructorCall(
       InvokeDirect invoke);
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
index 8a04363..857fa35 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/WhyAreYouNotInliningReporterImpl.java
@@ -251,6 +251,11 @@
   }
 
   @Override
+  public void reportUnsafeConstructorInliningDueToMissingFieldAssignment(InstancePut instancePut) {
+    report("assignment to missing field `" + instancePut.getField() + "`.");
+  }
+
+  @Override
   public void reportUnsafeConstructorInliningDueToIndirectConstructorCall(InvokeDirect invoke) {
     report(
         "must invoke a constructor from the class being instantiated (would invoke `"
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinInlineMethodRemover.java b/src/main/java/com/android/tools/r8/kotlin/KotlinInlineMethodRemover.java
new file mode 100644
index 0000000..595e6a9
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinInlineMethodRemover.java
@@ -0,0 +1,97 @@
+// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.kotlin;
+
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DefaultUseRegistryWithResult;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.google.common.collect.Sets;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
+
+public class KotlinInlineMethodRemover {
+
+  private final AppView<AppInfo> appView;
+  private final DexType kotlinInlineMarkerType;
+  private final DexType kotlinMetadataType;
+
+  public KotlinInlineMethodRemover(AppView<AppInfo> appView) {
+    this.appView = appView;
+    this.kotlinInlineMarkerType =
+        appView.dexItemFactory().createType("Lkotlin/jvm/internal/InlineMarker;");
+    this.kotlinMetadataType = appView.dexItemFactory().kotlinMetadataType;
+  }
+
+  public void run(ExecutorService executorService) throws ExecutionException {
+    if (appView.options().isGeneratingDex()) {
+      ThreadUtils.processItems(
+          this::forEachKotlinClass,
+          this::processClass,
+          appView.options().getThreadingModule(),
+          executorService);
+    }
+  }
+
+  private void forEachKotlinClass(Consumer<DexProgramClass> consumer) {
+    for (DexProgramClass clazz : appView.appInfo().classes()) {
+      if (clazz.annotations().hasAnnotation(kotlinMetadataType)) {
+        consumer.accept(clazz);
+      } else {
+        assert verifyNoKotlinInlineFunctions(clazz);
+      }
+    }
+  }
+
+  private void processClass(DexProgramClass clazz) {
+    Set<DexEncodedMethod> methodsToRemove = null;
+    for (ProgramMethod method : clazz.programMethods()) {
+      if (isKotlinInlineFunction(method)) {
+        assert method.getHolder().annotations().hasAnnotation(kotlinMetadataType);
+        if (methodsToRemove == null) {
+          methodsToRemove = Sets.newIdentityHashSet();
+        }
+        methodsToRemove.add(method.getDefinition());
+      }
+    }
+    if (methodsToRemove != null) {
+      clazz.getMethodCollection().removeMethods(methodsToRemove);
+    }
+  }
+
+  private boolean isKotlinInlineFunction(ProgramMethod method) {
+    return method.registerCodeReferencesWithResult(
+        new DefaultUseRegistryWithResult<>(appView, method, false) {
+
+          @Override
+          public void registerInvokeStatic(DexMethod method) {
+            if (method.getHolderType().isIdenticalTo(kotlinInlineMarkerType)) {
+              setResult(true);
+            }
+          }
+
+          @Override
+          public void registerInvokeSpecial(DexMethod method) {
+            // Intentionally empty. Override the default use registry behavior that attempts to
+            // convert this invoke-special to its corresponding dex invoke type. This is only
+            // possible after desugaring.
+          }
+        });
+  }
+
+  private boolean verifyNoKotlinInlineFunctions(DexProgramClass clazz) {
+    for (ProgramMethod method : clazz.programMethods()) {
+      assert !isKotlinInlineFunction(method);
+    }
+    return true;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index ceb9671..8c6aa57 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -129,7 +129,7 @@
         dexItemFactory,
         reporter,
         ProguardConfigurationParserOptions.builder()
-            .setEnableEmptyMemberRulesToDefaultInitRuleConversion(false)
+            .setEnableLegacyFullModeForKeepRules(false)
             .setEnableExperimentalCheckEnumUnboxed(false)
             .setEnableExperimentalConvertCheckNotNull(false)
             .setEnableExperimentalWhyAreYouNotInlining(false)
@@ -852,13 +852,12 @@
       Position end = getPosition();
       ProguardKeepRule rule =
           keepRuleBuilder.setSource(getSourceSnippet(contents, start, end)).setEnd(end).build();
-      if (options.isEmptyMemberRulesToDefaultInitRuleConversionEnabled(configurationBuilder)
+      if (options.isLegacyFullModeForKeepRulesEnabled(configurationBuilder)
           && rule.getMemberRules().isEmpty()
           && rule.getType() != ProguardKeepRuleType.KEEP_CLASSES_WITH_MEMBERS) {
         // If there are no member rules, a default rule for the parameterless constructor applies
         // in compatibility mode.
-        if (options.isEmptyMemberRulesToDefaultInitRuleConversionWarningsEnabled(
-            configurationBuilder)) {
+        if (options.isLegacyFullModeForKeepRulesWarningsEnabled(configurationBuilder)) {
           reporter.warning(
               EmptyMemberRulesToDefaultInitRuleConversionDiagnostic.Factory.create(rule));
         }
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParserOptions.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParserOptions.java
index 02373b6..ab5db09 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParserOptions.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParserOptions.java
@@ -6,20 +6,18 @@
 
 import static com.android.tools.r8.utils.SystemPropertyUtils.parseSystemPropertyOrDefault;
 
-import com.android.tools.r8.utils.OptionalBool;
-
 public class ProguardConfigurationParserOptions {
 
-  private final OptionalBool enableEmptyMemberRulesToDefaultInitRuleConversion;
-  private final boolean enableEmptyMemberRulesToDefaultInitRuleConversionWarnings;
+  private final boolean enableLegacyFullModeForKeepRules;
+  private final boolean enableLegacyFullModeForKeepRulesWarnings;
   private final boolean enableExperimentalCheckEnumUnboxed;
   private final boolean enableExperimentalConvertCheckNotNull;
   private final boolean enableExperimentalWhyAreYouNotInlining;
   private final boolean enableTestingOptions;
 
   ProguardConfigurationParserOptions(
-      OptionalBool enableEmptyMemberRulesToDefaultInitRuleConversion,
-      boolean enableEmptyMemberRulesToDefaultInitRuleConversionWarnings,
+      boolean enableLegacyFullModeForKeepRules,
+      boolean enableLegacyFullModeForKeepRulesWarnings,
       boolean enableExperimentalCheckEnumUnboxed,
       boolean enableExperimentalConvertCheckNotNull,
       boolean enableExperimentalWhyAreYouNotInlining,
@@ -28,28 +26,25 @@
     this.enableExperimentalConvertCheckNotNull = enableExperimentalConvertCheckNotNull;
     this.enableExperimentalWhyAreYouNotInlining = enableExperimentalWhyAreYouNotInlining;
     this.enableTestingOptions = enableTestingOptions;
-    this.enableEmptyMemberRulesToDefaultInitRuleConversion =
-        enableEmptyMemberRulesToDefaultInitRuleConversion;
-    this.enableEmptyMemberRulesToDefaultInitRuleConversionWarnings =
-        enableEmptyMemberRulesToDefaultInitRuleConversionWarnings;
+    this.enableLegacyFullModeForKeepRules = enableLegacyFullModeForKeepRules;
+    this.enableLegacyFullModeForKeepRulesWarnings = enableLegacyFullModeForKeepRulesWarnings;
   }
 
   public static Builder builder() {
     return new Builder();
   }
 
-  public boolean isEmptyMemberRulesToDefaultInitRuleConversionEnabled(
+  public boolean isLegacyFullModeForKeepRulesEnabled(
       ProguardConfiguration.Builder configurationBuilder) {
     // TODO(b/356344563): Disable in full mode in the next major version.
-    return configurationBuilder.isForceProguardCompatibility()
-        || enableEmptyMemberRulesToDefaultInitRuleConversion.getOrDefault(true);
+    return configurationBuilder.isForceProguardCompatibility() || enableLegacyFullModeForKeepRules;
   }
 
-  public boolean isEmptyMemberRulesToDefaultInitRuleConversionWarningsEnabled(
+  public boolean isLegacyFullModeForKeepRulesWarningsEnabled(
       ProguardConfiguration.Builder configurationBuilder) {
-    assert isEmptyMemberRulesToDefaultInitRuleConversionEnabled(configurationBuilder);
+    assert isLegacyFullModeForKeepRulesEnabled(configurationBuilder);
     return !configurationBuilder.isForceProguardCompatibility()
-        && enableEmptyMemberRulesToDefaultInitRuleConversionWarnings;
+        && enableLegacyFullModeForKeepRulesWarnings;
   }
 
   public boolean isExperimentalCheckEnumUnboxedEnabled() {
@@ -70,22 +65,20 @@
 
   public static class Builder {
 
-    private OptionalBool enableEmptyMemberRulesToDefaultInitRuleConversion = OptionalBool.UNKNOWN;
-    private boolean enableEmptyMemberRulesToDefaultInitRuleConversionWarnings = false;
+    private boolean enableLegacyFullModeForKeepRules = true;
+    private boolean enableLegacyFullModeForKeepRulesWarnings = false;
     private boolean enableExperimentalCheckEnumUnboxed;
     private boolean enableExperimentalConvertCheckNotNull;
     private boolean enableExperimentalWhyAreYouNotInlining;
     private boolean enableTestingOptions;
 
     public Builder readEnvironment() {
-      enableEmptyMemberRulesToDefaultInitRuleConversion =
+      enableLegacyFullModeForKeepRules =
           parseSystemPropertyOrDefault(
-              "com.android.tools.r8.enableEmptyMemberRulesToDefaultInitRuleConversion",
-              OptionalBool.UNKNOWN);
-      enableEmptyMemberRulesToDefaultInitRuleConversionWarnings =
+              "com.android.tools.r8.enableLegacyFullModeForKeepRules", true);
+      enableLegacyFullModeForKeepRulesWarnings =
           parseSystemPropertyOrDefault(
-              "com.android.tools.r8.enableEmptyMemberRulesToDefaultInitRuleConversionWarnings",
-              false);
+              "com.android.tools.r8.enableLegacyFullModeForKeepRulesWarnings", false);
       enableExperimentalCheckEnumUnboxed =
           parseSystemPropertyOrDefault(
               "com.android.tools.r8.experimental.enablecheckenumunboxed", false);
@@ -100,10 +93,14 @@
       return this;
     }
 
-    public Builder setEnableEmptyMemberRulesToDefaultInitRuleConversion(
-        boolean enableEmptyMemberRulesToDefaultInitRuleConversion) {
-      this.enableEmptyMemberRulesToDefaultInitRuleConversion =
-          OptionalBool.of(enableEmptyMemberRulesToDefaultInitRuleConversion);
+    public Builder setEnableLegacyFullModeForKeepRules(boolean enableLegacyFullModeForKeepRules) {
+      this.enableLegacyFullModeForKeepRules = enableLegacyFullModeForKeepRules;
+      return this;
+    }
+
+    public Builder setEnableLegacyFullModeForKeepRulesWarnings(
+        boolean enableLegacyFullModeForKeepRulesWarnings) {
+      this.enableLegacyFullModeForKeepRulesWarnings = enableLegacyFullModeForKeepRulesWarnings;
       return this;
     }
 
@@ -132,8 +129,8 @@
 
     public ProguardConfigurationParserOptions build() {
       return new ProguardConfigurationParserOptions(
-          enableEmptyMemberRulesToDefaultInitRuleConversion,
-          enableEmptyMemberRulesToDefaultInitRuleConversionWarnings,
+          enableLegacyFullModeForKeepRules,
+          enableLegacyFullModeForKeepRulesWarnings,
           enableExperimentalCheckEnumUnboxed,
           enableExperimentalConvertCheckNotNull,
           enableExperimentalWhyAreYouNotInlining,
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index ad6845e..cbd5675 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -6,6 +6,7 @@
 import static com.android.tools.r8.utils.AndroidApiLevel.B;
 import static com.android.tools.r8.utils.CfUtils.extractClassDescriptor;
 import static com.android.tools.r8.utils.SystemPropertyUtils.parseSystemPropertyForDevelopmentOrDefault;
+import static com.android.tools.r8.utils.SystemPropertyUtils.parseSystemPropertyOrDefault;
 
 import com.android.tools.r8.AndroidResourceConsumer;
 import com.android.tools.r8.AndroidResourceProvider;
@@ -54,6 +55,7 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexClasspathClass;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItem;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -1831,6 +1833,9 @@
   public static class InlinerOptions {
 
     public boolean enableConstructorInlining = true;
+    public boolean enableConstructorInliningWithFinalFields =
+        parseSystemPropertyOrDefault(
+            "com.android.tools.r8.enableConstructorInliningWithFinalFields", false);
 
     public boolean enableInlining =
         !parseSystemPropertyForDevelopmentOrDefault("com.android.tools.r8.disableinlining", false);
@@ -2659,6 +2664,11 @@
     return !appView.enableWholeProgramOptimizations();
   }
 
+  public boolean canAssignFinalInstanceFieldOutsideConstructor() {
+    // ART does not check this property.
+    return isGeneratingDex();
+  }
+
   /**
    * Dex2Oat issues a warning for abstract methods on non-abstract classes, so we never allow this.
    *
@@ -2859,6 +2869,14 @@
     return intermediate || hasMinApi(AndroidApiLevel.L);
   }
 
+  public boolean canUseJavaLangVarHandleStoreStoreFence(DexDefinitionSupplier definitions) {
+    if (isGeneratingDex() && hasMinApi(AndroidApiLevel.P)) {
+      DexItemFactory factory = definitions.dexItemFactory();
+      return definitions.hasDefinitionFor(factory.javaLangInvokeVarHandleMembers.storeStoreFence);
+    }
+    return false;
+  }
+
   public boolean canUseJavaUtilObjects() {
     return hasFeaturePresentFrom(AndroidApiLevel.K);
   }
diff --git a/src/test/java/com/android/tools/r8/compilerapi/diagnostics/ProguardKeepRuleDiagnosticsApiTest.java b/src/test/java/com/android/tools/r8/compilerapi/diagnostics/ProguardKeepRuleDiagnosticsApiTest.java
index e4ed3bb..cb50996 100644
--- a/src/test/java/com/android/tools/r8/compilerapi/diagnostics/ProguardKeepRuleDiagnosticsApiTest.java
+++ b/src/test/java/com/android/tools/r8/compilerapi/diagnostics/ProguardKeepRuleDiagnosticsApiTest.java
@@ -98,7 +98,7 @@
               .addProguardConfiguration(
                   Collections.singletonList("-keep class NotPresent {}"), Origin.unknown())
               .addLibraryFiles(getJava8RuntimeJar())
-              .setEnableEmptyMemberRulesToDefaultInitRuleConversion(false)
+              .enableLegacyFullModeForKeepRules(false)
               .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
               .setMinApiLevel(1)
               .build());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineConstructorWithFinalFieldsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineConstructorWithFinalFieldsTest.java
new file mode 100644
index 0000000..e5cca20
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineConstructorWithFinalFieldsTest.java
@@ -0,0 +1,108 @@
+// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.optimize.inliner;
+
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsentIf;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertFalse;
+
+import com.android.tools.r8.AlwaysInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class InlineConstructorWithFinalFieldsTest extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        // Use most recent android.jar so that VarHandle is present.
+        .applyIf(
+            parameters.isDexRuntime(),
+            testBuilder -> testBuilder.addLibraryFiles(ToolHelper.getMostRecentAndroidJar()))
+        .addKeepMainRule(Main.class)
+        .addOptionsModification(
+            options -> {
+              assertFalse(options.inlinerOptions().enableConstructorInliningWithFinalFields);
+              options.inlinerOptions().enableConstructorInliningWithFinalFields = true;
+            })
+        .enableAlwaysInliningAnnotations()
+        .setMinApi(parameters)
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject mainClassSubject = inspector.clazz(Main.class);
+              assertThat(mainClassSubject, isPresent());
+
+              MethodSubject initMethodSubject = mainClassSubject.init("int", "int");
+              assertThat(
+                  initMethodSubject,
+                  isAbsentIf(
+                      parameters.isDexRuntime()
+                          && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.P)));
+
+              MethodSubject mainMethodSubject = mainClassSubject.mainMethod();
+              assertThat(mainMethodSubject, isPresent());
+              if (initMethodSubject.isPresent()) {
+                assertThat(mainMethodSubject, invokesMethod(initMethodSubject));
+              } else {
+                assertThat(
+                    mainMethodSubject,
+                    invokesMethod(MethodReferenceUtils.instanceConstructor(Object.class)));
+                assertThat(
+                    mainMethodSubject,
+                    invokesMethod(
+                        Reference.methodFromDescriptor(
+                            "Ljava/lang/invoke/VarHandle;", "storeStoreFence", "()V")));
+              }
+            })
+        .run(parameters.getRuntime(), Main.class, "20", "22")
+        .assertSuccessWithOutputLines("42");
+  }
+
+  static class Main {
+
+    final int x;
+    final int y;
+
+    @AlwaysInline
+    Main(int x, int y) {
+      this.x = x;
+      this.y = y;
+    }
+
+    public static void main(String[] args) {
+      Main main = new Main(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
+      System.out.println(main);
+    }
+
+    @Override
+    public String toString() {
+      return Integer.toString(x + y);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/ArgumentIn4BitRegisterTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/ArgumentIn4BitRegisterTest.java
new file mode 100644
index 0000000..d2b9b6e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/ArgumentIn4BitRegisterTest.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.regalloc;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ArgumentIn4BitRegisterTest extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimesAndAllApiLevels().build();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForD8()
+        .addInnerClasses(getClass())
+        .release()
+        .setMinApi(parameters)
+        .compile()
+        .inspect(
+            inspector -> {
+              MethodSubject testMethodSubject =
+                  inspector.clazz(Main.class).uniqueMethodWithOriginalName("test");
+              assertThat(testMethodSubject, isPresent());
+              // TODO(b/374266460): Should be 0.
+              assertEquals(
+                  1,
+                  testMethodSubject
+                      .streamInstructions()
+                      .filter(InstructionSubject::isMove)
+                      .count());
+            });
+  }
+
+  static class Main {
+
+    public static void test(
+        Object a, long b, long c, long d, long e, long f, long g, long h, long i) {
+      Main main = (Main) a;
+      // Keep all argument alive.
+      use(b);
+      use(c);
+      use(d);
+      use(e);
+      use(f);
+      use(h);
+      use(i);
+    }
+
+    private static void use(long a) {}
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/RedundantArgumentToPhiMoveIn16BitRegisterAllocationTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/RedundantArgumentToPhiMoveIn16BitRegisterAllocationTest.java
new file mode 100644
index 0000000..d1977ab
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/RedundantArgumentToPhiMoveIn16BitRegisterAllocationTest.java
@@ -0,0 +1,61 @@
+// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.regalloc;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RedundantArgumentToPhiMoveIn16BitRegisterAllocationTest extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDefaultDexRuntime().withMaximumApiLevel().build();
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    testForD8()
+        .addInnerClasses(getClass())
+        .release()
+        .setMinApi(parameters)
+        .compile()
+        .inspect(
+            inspector -> {
+              MethodSubject testMethodSubject =
+                  inspector.clazz(Main.class).uniqueMethodWithOriginalName("test");
+              assertThat(testMethodSubject, isPresent());
+              // TODO(b/374262806): We should not need to move the argument value to a local
+              //  register. Instead, we should use the argument register for the phi and load the
+              //  constant 42 into this register, thereby avoiding any moves.
+              assertTrue(
+                  testMethodSubject.streamInstructions().anyMatch(InstructionSubject::isMove));
+            });
+  }
+
+  static class Main {
+
+    static void test(long a, long b, long c, long d, long e, long f, long g, long h, int def) {
+      long i = (def & 1) == 0 ? a : 42;
+      accept(i);
+    }
+
+    static void accept(long a) {}
+  }
+}
diff --git a/src/test/testbase/java/com/android/tools/r8/AlwaysInline.java b/src/test/testbase/java/com/android/tools/r8/AlwaysInline.java
index 97a799a..30fc4bd 100644
--- a/src/test/testbase/java/com/android/tools/r8/AlwaysInline.java
+++ b/src/test/testbase/java/com/android/tools/r8/AlwaysInline.java
@@ -6,5 +6,5 @@
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Target;
 
-@Target({ElementType.METHOD})
+@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
 public @interface AlwaysInline {}
diff --git a/src/test/testbase/java/com/android/tools/r8/R8TestBuilder.java b/src/test/testbase/java/com/android/tools/r8/R8TestBuilder.java
index 72fd0ae..51174be 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8TestBuilder.java
@@ -153,7 +153,7 @@
     libraryDesugaringTestConfiguration.configure(builder);
     builder.setAndroidPlatformBuild(androidPlatformBuild);
     if (!enableEmptyMemberRulesToDefaultInitRuleConversion.isUnknown()) {
-      builder.setEnableEmptyMemberRulesToDefaultInitRuleConversion(
+      builder.enableLegacyFullModeForKeepRules(
           enableEmptyMemberRulesToDefaultInitRuleConversion.toBoolean());
     }
     builder.setEnableIsolatedSplits(enableIsolatedSplits);
diff --git a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
index 9c37579..2c24643 100644
--- a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
+++ b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
@@ -397,6 +397,11 @@
   }
 
   @Override
+  public boolean isMove() {
+    return false;
+  }
+
+  @Override
   public boolean isFilledNewArray() {
     return false;
   }
diff --git a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
index 5afb54f..f4e6a57 100644
--- a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
+++ b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
@@ -95,6 +95,15 @@
 import com.android.tools.r8.dex.code.DexIputWide;
 import com.android.tools.r8.dex.code.DexMonitorEnter;
 import com.android.tools.r8.dex.code.DexMonitorExit;
+import com.android.tools.r8.dex.code.DexMove;
+import com.android.tools.r8.dex.code.DexMove16;
+import com.android.tools.r8.dex.code.DexMoveFrom16;
+import com.android.tools.r8.dex.code.DexMoveObject;
+import com.android.tools.r8.dex.code.DexMoveObject16;
+import com.android.tools.r8.dex.code.DexMoveObjectFrom16;
+import com.android.tools.r8.dex.code.DexMoveWide;
+import com.android.tools.r8.dex.code.DexMoveWide16;
+import com.android.tools.r8.dex.code.DexMoveWideFrom16;
 import com.android.tools.r8.dex.code.DexMulDouble;
 import com.android.tools.r8.dex.code.DexMulDouble2Addr;
 import com.android.tools.r8.dex.code.DexMulFloat;
@@ -642,6 +651,19 @@
   }
 
   @Override
+  public boolean isMove() {
+    return instruction instanceof DexMove
+        || instruction instanceof DexMove16
+        || instruction instanceof DexMoveFrom16
+        || instruction instanceof DexMoveObject
+        || instruction instanceof DexMoveObject16
+        || instruction instanceof DexMoveObjectFrom16
+        || instruction instanceof DexMoveWide
+        || instruction instanceof DexMoveWide16
+        || instruction instanceof DexMoveWideFrom16;
+  }
+
+  @Override
   public boolean isFilledNewArray() {
     return instruction instanceof DexFilledNewArray
         || instruction instanceof DexFilledNewArrayRange;
diff --git a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
index 0dbe112..1852710 100644
--- a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
+++ b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
@@ -164,6 +164,8 @@
 
   boolean isMonitorExit();
 
+  boolean isMove();
+
   boolean isFilledNewArray();
 
   boolean isFilledNewArrayData();
diff --git a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1 b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
index b76801c..089244c 100644
--- a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
+++ b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
@@ -1 +1 @@
-9c8c027ae1cd5b8768574a7fb2bb0698ef09b907
\ No newline at end of file
+aa0b23115292ec22a24d4166101c1116d264e1cb
\ No newline at end of file