Merge "Revert "Disallow const instructions after throwing instructions""
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index cb93a5e..773a648 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -662,9 +662,12 @@
           }
           // After the throwing instruction only debug instructions and the final jump
           // instruction is allowed.
+          // TODO(ager): For now allow const instructions due to the way consts are pushed
+          // towards their use
           if (seenThrowing) {
             assert instruction.isDebugInstruction()
                 || instruction.isJumpInstruction()
+                || instruction.isConstInstruction()
                 || instruction.isStore()
                 || instruction.isPop();
           }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index fd968d6..7c22bbf 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -210,15 +210,7 @@
             iterator.replaceCurrentInstruction(newInvoke);
 
             if (constantReturnMaterializingInstruction != null) {
-              if (block.hasCatchHandlers()) {
-                // Split the block to ensure no instructions after throwing instructions.
-                iterator
-                    .split(code, blocks)
-                    .listIterator()
-                    .add(constantReturnMaterializingInstruction);
-              } else {
-                iterator.add(constantReturnMaterializingInstruction);
-              }
+              iterator.add(constantReturnMaterializingInstruction);
             }
 
             DexType actualReturnType = actualTarget.proto.returnType;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 99f9731..4da9f8d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -17,13 +17,11 @@
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
-import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstancePut;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionIterator;
-import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.StaticGet;
 import com.android.tools.r8.ir.code.StaticPut;
@@ -31,7 +29,6 @@
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.ProguardMemberRule;
 import com.google.common.collect.Sets;
-import java.util.ListIterator;
 import java.util.Set;
 import java.util.function.Predicate;
 
@@ -136,160 +133,151 @@
   public void rewriteWithConstantValues(
       IRCode code, DexType callingContext, Predicate<DexEncodedMethod> isProcessedConcurrently) {
     Set<Value> affectedValues = Sets.newIdentityHashSet();
-    ListIterator<BasicBlock> blocks = code.blocks.listIterator();
-    while (blocks.hasNext()) {
-      BasicBlock block = blocks.next();
-      InstructionListIterator iterator = block.listIterator();
-      while (iterator.hasNext()) {
-        Instruction current = iterator.next();
-        if (current.isInvokeMethod()) {
-          InvokeMethod invoke = current.asInvokeMethod();
-          DexMethod invokedMethod = invoke.getInvokedMethod();
-          DexType invokedHolder = invokedMethod.getHolder();
-          if (!invokedHolder.isClassType()) {
-            continue;
-          }
-          // TODO(70550443): Maybe check all methods here.
-          DexEncodedMethod definition = appInfo
-              .lookup(invoke.getType(), invokedMethod, callingContext);
+    InstructionIterator iterator = code.instructionIterator();
+    while (iterator.hasNext()) {
+      Instruction current = iterator.next();
+      if (current.isInvokeMethod()) {
+        InvokeMethod invoke = current.asInvokeMethod();
+        DexMethod invokedMethod = invoke.getInvokedMethod();
+        DexType invokedHolder = invokedMethod.getHolder();
+        if (!invokedHolder.isClassType()) {
+          continue;
+        }
+        // TODO(70550443): Maybe check all methods here.
+        DexEncodedMethod definition = appInfo
+            .lookup(invoke.getType(), invokedMethod, callingContext);
 
-          boolean invokeReplaced = false;
-          ProguardMemberRuleLookup lookup = lookupMemberRule(definition);
-          if (lookup != null) {
-            if (lookup.type == RuleType.ASSUME_NO_SIDE_EFFECTS
-                && (invoke.outValue() == null || !invoke.outValue().isUsed())) {
-              // Remove invoke if marked as having no side effects and the return value is not used.
-              iterator.remove();
-              invokeReplaced = true;
-            } else if (invoke.outValue() != null && invoke.outValue().isUsed()) {
-              // Check to see if a constant value can be assumed.
-              Instruction replacement =
-                  constantReplacementFromProguardRule(lookup.rule, code, invoke);
-              if (replacement != null) {
-                affectedValues.add(replacement.outValue());
-                replaceInstructionFromProguardRule(lookup.type, iterator, current, replacement);
-                invokeReplaced = true;
-              } else {
-                // Check to see if a value range can be assumed.
-                setValueRangeFromProguardRule(lookup.rule, current.outValue());
-              }
-            }
-          }
-
-          // If no Proguard rule could replace the instruction check for knowledge about the
-          // return value.
-          if (!invokeReplaced && invoke.outValue() != null) {
-            DexEncodedMethod target = invoke.lookupSingleTarget(appInfo, callingContext);
-            if (target != null) {
-              if (target.getOptimizationInfo().neverReturnsNull() && invoke.outValue()
-                  .canBeNull()) {
-                Value knownToBeNonNullValue = invoke.outValue();
-                knownToBeNonNullValue.markNeverNull();
-                TypeLatticeElement typeLattice = knownToBeNonNullValue.getTypeLattice();
-                assert typeLattice.isNullable() && typeLattice.isReference();
-                knownToBeNonNullValue.narrowing(appInfo, typeLattice.asNonNullable());
-                affectedValues.addAll(knownToBeNonNullValue.affectedValues());
-              }
-              if (target.getOptimizationInfo().returnsConstant()) {
-                long constant = target.getOptimizationInfo().getReturnedConstant();
-                ConstNumber replacement = createConstNumberReplacement(
-                    code, constant, invoke.outValue().getTypeLattice(), invoke.getLocalInfo());
-                affectedValues.add(replacement.outValue());
-                invoke.outValue().replaceUsers(replacement.outValue());
-                invoke.setOutValue(null);
-                replacement.setPosition(invoke.getPosition());
-                invoke.moveDebugValues(replacement);
-                if (current.getBlock().hasCatchHandlers()) {
-                  iterator.split(code, blocks).listIterator().add(replacement);
-                } else {
-                  iterator.add(replacement);
-                }
-              }
-            }
-          }
-        } else if (current.isInstancePut()) {
-          InstancePut instancePut = current.asInstancePut();
-          DexField field = instancePut.getField();
-          DexEncodedField target = appInfo.lookupInstanceTarget(field.getHolder(), field);
-          if (target != null) {
-            // Remove writes to dead (i.e. never read) fields.
-            if (!isFieldRead(target, false) && instancePut.object().isNeverNull()) {
-              iterator.remove();
-            }
-          }
-        } else if (current.isStaticGet()) {
-          StaticGet staticGet = current.asStaticGet();
-          DexField field = staticGet.getField();
-          DexEncodedField target = appInfo.lookupStaticTarget(field.getHolder(), field);
-          ProguardMemberRuleLookup lookup = null;
-          if (target != null) {
-            // Check if a this value is known const.
-            Instruction replacement = target.valueAsConstInstruction(appInfo, staticGet.dest());
-            if (replacement == null) {
-              lookup = lookupMemberRule(target);
-              if (lookup != null) {
-                replacement = constantReplacementFromProguardRule(lookup.rule, code, staticGet);
-              }
-            }
-            if (replacement == null) {
-              // If no const replacement was found, at least store the range information.
-              if (lookup != null) {
-                setValueRangeFromProguardRule(lookup.rule, staticGet.dest());
-              }
-            }
+        boolean invokeReplaced = false;
+        ProguardMemberRuleLookup lookup = lookupMemberRule(definition);
+        if (lookup != null) {
+          if (lookup.type == RuleType.ASSUME_NO_SIDE_EFFECTS
+              && (invoke.outValue() == null || !invoke.outValue().isUsed())) {
+            // Remove invoke if marked as having no side effects and the return value is not used.
+            iterator.remove();
+            invokeReplaced = true;
+          } else if (invoke.outValue() != null && invoke.outValue().isUsed()) {
+            // Check to see if a constant value can be assumed.
+            Instruction replacement =
+                constantReplacementFromProguardRule(lookup.rule, code, invoke);
             if (replacement != null) {
               affectedValues.add(replacement.outValue());
-              // Ignore assumenosideeffects for fields.
-              if (lookup != null && lookup.type == RuleType.ASSUME_VALUES) {
-                replaceInstructionFromProguardRule(lookup.type, iterator, current, replacement);
-              } else {
-                iterator.replaceCurrentInstruction(replacement);
-              }
-            } else if (staticGet.dest() != null) {
-              // In case the class holder of this static field satisfying following criteria:
-              //   -- cannot trigger other static initializer except for its own
-              //   -- is final
-              //   -- has a class initializer which is classified as trivial
-              //      (see CodeRewriter::computeClassInitializerInfo) and
-              //      initializes the field being accessed
-              //
-              // ... and the field itself is not pinned by keep rules (in which case it might
-              // be updated outside the class constructor, e.g. via reflections), it is safe
-              // to assume that the static-get instruction reads the value it initialized value
-              // in class initializer and is never null.
-              //
-              DexClass holderDefinition = appInfo.definitionFor(field.getHolder());
-              if (holderDefinition != null
-                  && holderDefinition.accessFlags.isFinal()
-                  && !appInfo.canTriggerStaticInitializer(field.getHolder(), true)) {
-                Value outValue = staticGet.dest();
-                DexEncodedMethod classInitializer = holderDefinition.getClassInitializer();
-                if (classInitializer != null && !isProcessedConcurrently.test(classInitializer)) {
-                  TrivialInitializer info =
-                      classInitializer.getOptimizationInfo().getTrivialInitializerInfo();
-                  if (info != null
-                      && ((TrivialClassInitializer) info).field == field
-                      && !appInfo.isPinned(field)
-                      && outValue.canBeNull()) {
-                    outValue.markNeverNull();
-                    TypeLatticeElement typeLattice = outValue.getTypeLattice();
-                    assert typeLattice.isNullable() && typeLattice.isReference();
-                    outValue.narrowing(appInfo, typeLattice.asNonNullable());
-                    affectedValues.addAll(outValue.affectedValues());
-                  }
+              replaceInstructionFromProguardRule(lookup.type, iterator, current, replacement);
+              invokeReplaced = true;
+            } else {
+              // Check to see if a value range can be assumed.
+              setValueRangeFromProguardRule(lookup.rule, current.outValue());
+            }
+          }
+        }
+
+        // If no Proguard rule could replace the instruction check for knowledge about the
+        // return value.
+        if (!invokeReplaced && invoke.outValue() != null) {
+          DexEncodedMethod target = invoke.lookupSingleTarget(appInfo, callingContext);
+          if (target != null) {
+            if (target.getOptimizationInfo().neverReturnsNull() && invoke.outValue().canBeNull()) {
+              Value knownToBeNonNullValue = invoke.outValue();
+              knownToBeNonNullValue.markNeverNull();
+              TypeLatticeElement typeLattice = knownToBeNonNullValue.getTypeLattice();
+              assert typeLattice.isNullable() && typeLattice.isReference();
+              knownToBeNonNullValue.narrowing(appInfo, typeLattice.asNonNullable());
+              affectedValues.addAll(knownToBeNonNullValue.affectedValues());
+            }
+            if (target.getOptimizationInfo().returnsConstant()) {
+              long constant = target.getOptimizationInfo().getReturnedConstant();
+              ConstNumber replacement = createConstNumberReplacement(
+                  code, constant, invoke.outValue().getTypeLattice(), invoke.getLocalInfo());
+              affectedValues.add(replacement.outValue());
+              invoke.outValue().replaceUsers(replacement.outValue());
+              invoke.setOutValue(null);
+              replacement.setPosition(invoke.getPosition());
+              invoke.moveDebugValues(replacement);
+              iterator.add(replacement);
+            }
+          }
+        }
+      } else if (current.isInstancePut()) {
+        InstancePut instancePut = current.asInstancePut();
+        DexField field = instancePut.getField();
+        DexEncodedField target = appInfo.lookupInstanceTarget(field.getHolder(), field);
+        if (target != null) {
+          // Remove writes to dead (i.e. never read) fields.
+          if (!isFieldRead(target, false) && instancePut.object().isNeverNull()) {
+            iterator.remove();
+          }
+        }
+      } else if (current.isStaticGet()) {
+        StaticGet staticGet = current.asStaticGet();
+        DexField field = staticGet.getField();
+        DexEncodedField target = appInfo.lookupStaticTarget(field.getHolder(), field);
+        ProguardMemberRuleLookup lookup = null;
+        if (target != null) {
+          // Check if a this value is known const.
+          Instruction replacement = target.valueAsConstInstruction(appInfo, staticGet.dest());
+          if (replacement == null) {
+            lookup = lookupMemberRule(target);
+            if (lookup != null) {
+              replacement = constantReplacementFromProguardRule(lookup.rule, code, staticGet);
+            }
+          }
+          if (replacement == null) {
+            // If no const replacement was found, at least store the range information.
+            if (lookup != null) {
+              setValueRangeFromProguardRule(lookup.rule, staticGet.dest());
+            }
+          }
+          if (replacement != null) {
+            affectedValues.add(replacement.outValue());
+            // Ignore assumenosideeffects for fields.
+            if (lookup != null && lookup.type == RuleType.ASSUME_VALUES) {
+              replaceInstructionFromProguardRule(lookup.type, iterator, current, replacement);
+            } else {
+              iterator.replaceCurrentInstruction(replacement);
+            }
+          } else if (staticGet.dest() != null) {
+            // In case the class holder of this static field satisfying following criteria:
+            //   -- cannot trigger other static initializer except for its own
+            //   -- is final
+            //   -- has a class initializer which is classified as trivial
+            //      (see CodeRewriter::computeClassInitializerInfo) and
+            //      initializes the field being accessed
+            //
+            // ... and the field itself is not pinned by keep rules (in which case it might
+            // be updated outside the class constructor, e.g. via reflections), it is safe
+            // to assume that the static-get instruction reads the value it initialized value
+            // in class initializer and is never null.
+            //
+            DexClass holderDefinition = appInfo.definitionFor(field.getHolder());
+            if (holderDefinition != null
+                && holderDefinition.accessFlags.isFinal()
+                && !appInfo.canTriggerStaticInitializer(field.getHolder(), true)) {
+              Value outValue = staticGet.dest();
+              DexEncodedMethod classInitializer = holderDefinition.getClassInitializer();
+              if (classInitializer != null && !isProcessedConcurrently.test(classInitializer)) {
+                TrivialInitializer info =
+                    classInitializer.getOptimizationInfo().getTrivialInitializerInfo();
+                if (info != null
+                    && ((TrivialClassInitializer) info).field == field
+                    && !appInfo.isPinned(field)
+                    && outValue.canBeNull()) {
+                  outValue.markNeverNull();
+                  TypeLatticeElement typeLattice = outValue.getTypeLattice();
+                  assert typeLattice.isNullable() && typeLattice.isReference();
+                  outValue.narrowing(appInfo, typeLattice.asNonNullable());
+                  affectedValues.addAll(outValue.affectedValues());
                 }
               }
             }
           }
-        } else if (current.isStaticPut()) {
-          StaticPut staticPut = current.asStaticPut();
-          DexField field = staticPut.getField();
-          DexEncodedField target = appInfo.lookupStaticTarget(field.getHolder(), field);
-          if (target != null) {
-            // Remove writes to dead (i.e. never read) fields.
-            if (!isFieldRead(target, true)) {
-              iterator.removeOrReplaceByDebugLocalRead();
-            }
+        }
+      } else if (current.isStaticPut()) {
+        StaticPut staticPut = current.asStaticPut();
+        DexField field = staticPut.getField();
+        DexEncodedField target = appInfo.lookupStaticTarget(field.getHolder(), field);
+        if (target != null) {
+          // Remove writes to dead (i.e. never read) fields.
+          if (!isFieldRead(target, true)) {
+            iterator.removeOrReplaceByDebugLocalRead();
           }
         }
       }