Generalize graph lens to support non-null constant parameter replacement

Change-Id: Ibc55d32dd3f6fe47f0d6f7b1532ebef947dd2508
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
index c016016..90c504e 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.ir.code.ConstInstruction;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Position;
@@ -68,11 +69,11 @@
 
     public static class Builder {
 
-      private boolean isAlwaysNull = false;
-      private DexType type = null;
+      private SingleValue singleValue;
+      private DexType type;
 
-      public Builder setIsAlwaysNull() {
-        this.isAlwaysNull = true;
+      public Builder setSingleValue(SingleValue singleValue) {
+        this.singleValue = singleValue;
         return this;
       }
 
@@ -83,15 +84,15 @@
 
       public RemovedArgumentInfo build() {
         assert type != null;
-        return new RemovedArgumentInfo(isAlwaysNull, type);
+        return new RemovedArgumentInfo(singleValue, type);
       }
     }
 
-    private final boolean isAlwaysNull;
+    private final SingleValue singleValue;
     private final DexType type;
 
-    private RemovedArgumentInfo(boolean isAlwaysNull, DexType type) {
-      this.isAlwaysNull = isAlwaysNull;
+    private RemovedArgumentInfo(SingleValue singleValue, DexType type) {
+      this.singleValue = singleValue;
       this.type = type;
     }
 
@@ -99,16 +100,20 @@
       return new Builder();
     }
 
+    public boolean hasSingleValue() {
+      return singleValue != null;
+    }
+
+    public SingleValue getSingleValue() {
+      return singleValue;
+    }
+
     public DexType getType() {
       return type;
     }
 
-    public boolean isAlwaysNull() {
-      return isAlwaysNull;
-    }
-
     public boolean isNeverUsed() {
-      return !isAlwaysNull;
+      return !hasSingleValue();
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
index 8f4baa6..c42a3bb 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
@@ -17,8 +17,8 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.ConstClass;
-import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -64,7 +64,8 @@
   @Override
   public Instruction createMaterializingInstruction(
       AppView<? extends AppInfoWithClassHierarchy> appView,
-      IRCode code,
+      ProgramMethod context,
+      NumberGenerator valueNumberGenerator,
       TypeAndLocalInfoSupplier info) {
     TypeElement typeLattice = info.getOutType();
     DebugLocalInfo debugLocalInfo = info.getLocalInfo();
@@ -73,9 +74,12 @@
         .isSubtype(appView.dexItemFactory().classType, typeLattice.asClassType().getClassType())
         .isTrue();
     Value returnedValue =
-        code.createValue(classClassType(appView, definitelyNotNull()), debugLocalInfo);
+        new Value(
+            valueNumberGenerator.next(),
+            classClassType(appView, definitelyNotNull()),
+            debugLocalInfo);
     ConstClass instruction = new ConstClass(returnedValue, type);
-    assert !instruction.instructionMayHaveSideEffects(appView, code.context());
+    assert !instruction.instructionMayHaveSideEffects(appView, context);
     return instruction;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
index 13df457..a537863 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
@@ -15,8 +15,8 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.DexItemBasedConstString;
-import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
@@ -74,7 +74,8 @@
   @Override
   public Instruction createMaterializingInstruction(
       AppView<? extends AppInfoWithClassHierarchy> appView,
-      IRCode code,
+      ProgramMethod context,
+      NumberGenerator valueNumberGenerator,
       TypeAndLocalInfoSupplier info) {
     TypeElement typeLattice = info.getOutType();
     DebugLocalInfo debugLocalInfo = info.getLocalInfo();
@@ -83,7 +84,10 @@
         .isSubtype(appView.dexItemFactory().stringType, typeLattice.asClassType().getClassType())
         .isTrue();
     Value returnedValue =
-        code.createValue(stringClassType(appView, definitelyNotNull()), debugLocalInfo);
+        new Value(
+            valueNumberGenerator.next(),
+            stringClassType(appView, definitelyNotNull()),
+            debugLocalInfo);
     DexItemBasedConstString instruction =
         new DexItemBasedConstString(returnedValue, item, nameComputationInfo);
     assert !instruction.instructionInstanceCanThrow();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
index 911174b..8769ab2 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -17,8 +17,8 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
-import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.StaticGet;
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.code.Value;
@@ -69,11 +69,12 @@
   @Override
   public Instruction createMaterializingInstruction(
       AppView<? extends AppInfoWithClassHierarchy> appView,
-      IRCode code,
+      ProgramMethod context,
+      NumberGenerator valueNumberGenerator,
       TypeAndLocalInfoSupplier info) {
     TypeElement type = TypeElement.fromDexType(field.type, maybeNull(), appView);
     assert type.lessThanOrEqual(info.getOutType(), appView);
-    Value outValue = code.createValue(type, info.getLocalInfo());
+    Value outValue = new Value(valueNumberGenerator.next(), type, info.getLocalInfo());
     return new StaticGet(outValue, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
index d51b94a..c01133e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
@@ -11,8 +11,8 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.ConstNumber;
-import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -126,14 +126,17 @@
   @Override
   public Instruction createMaterializingInstruction(
       AppView<? extends AppInfoWithClassHierarchy> appView,
-      IRCode code,
+      ProgramMethod context,
+      NumberGenerator valueNumberGenerator,
       TypeAndLocalInfoSupplier info) {
     TypeElement typeLattice = info.getOutType();
     DebugLocalInfo debugLocalInfo = info.getLocalInfo();
     assert !typeLattice.isReferenceType() || value == 0;
     Value returnedValue =
-        code.createValue(
-            typeLattice.isReferenceType() ? TypeElement.getNull() : typeLattice, debugLocalInfo);
+        new Value(
+            valueNumberGenerator.next(),
+            typeLattice.isReferenceType() ? TypeElement.getNull() : typeLattice,
+            debugLocalInfo);
     return new ConstNumber(returnedValue, value);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
index cd0c9e9..35acae4 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
@@ -15,8 +15,8 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.ConstString;
-import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -62,7 +62,8 @@
   @Override
   public Instruction createMaterializingInstruction(
       AppView<? extends AppInfoWithClassHierarchy> appView,
-      IRCode code,
+      ProgramMethod context,
+      NumberGenerator valueNumberGenerator,
       TypeAndLocalInfoSupplier info) {
     TypeElement typeLattice = info.getOutType();
     DebugLocalInfo debugLocalInfo = info.getLocalInfo();
@@ -71,7 +72,10 @@
         .isSubtype(appView.dexItemFactory().stringType, typeLattice.asClassType().getClassType())
         .isTrue();
     Value returnedValue =
-        code.createValue(stringClassType(appView, definitelyNotNull()), debugLocalInfo);
+        new Value(
+            valueNumberGenerator.next(),
+            stringClassType(appView, definitelyNotNull()),
+            debugLocalInfo);
     ConstString instruction = new ConstString(returnedValue, string);
     assert !instruction.instructionInstanceCanThrow();
     return instruction;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
index 4a3a11c..94cd837 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -35,9 +36,17 @@
    * Note that calls to this method should generally be guarded by {@link
    * #isMaterializableInContext}.
    */
-  public abstract Instruction createMaterializingInstruction(
+  public final Instruction createMaterializingInstruction(
       AppView<? extends AppInfoWithClassHierarchy> appView,
       IRCode code,
+      TypeAndLocalInfoSupplier info) {
+    return createMaterializingInstruction(appView, code.context(), code.valueNumberGenerator, info);
+  }
+
+  public abstract Instruction createMaterializingInstruction(
+      AppView<? extends AppInfoWithClassHierarchy> appView,
+      ProgramMethod context,
+      NumberGenerator valueNumberGenerator,
       TypeAndLocalInfoSupplier info);
 
   public abstract boolean isMaterializableInContext(
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index e06df9e..90ca265 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -123,6 +123,10 @@
     public static ThrowingInfo defaultForConstString(InternalOptions options) {
       return options.isGeneratingClassFiles() ? NO_THROW : CAN_THROW;
     }
+
+    public static ThrowingInfo defaultForInstruction(Instruction instruction) {
+      return instruction.instructionTypeCanThrow() ? CAN_THROW : NO_THROW;
+    }
   }
 
   public enum EdgeType {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 3911614..b35e2ca 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -43,6 +43,7 @@
 import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.ir.code.Add;
 import com.android.tools.r8.ir.code.And;
 import com.android.tools.r8.ir.code.Argument;
@@ -110,6 +111,7 @@
 import com.android.tools.r8.ir.code.StaticPut;
 import com.android.tools.r8.ir.code.Sub;
 import com.android.tools.r8.ir.code.Throw;
+import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.code.Ushr;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.code.ValueType;
@@ -1037,13 +1039,27 @@
   private void handleConstantOrUnusedArgument(
       int register, RemovedArgumentInfo removedArgumentInfo) {
     assert removedArgumentInfo != null;
-    if (removedArgumentInfo.isAlwaysNull()) {
+    if (removedArgumentInfo.hasSingleValue()) {
       if (pendingArgumentInstructions == null) {
         pendingArgumentInstructions = new ArrayList<>();
       }
       DebugLocalInfo local = getOutgoingLocal(register);
-      Value value = writeRegister(register, getNull(), ThrowingInfo.NO_THROW, local);
-      pendingArgumentInstructions.add(new ConstNumber(value, 0));
+      SingleValue singleValue = removedArgumentInfo.getSingleValue();
+      TypeElement type =
+          removedArgumentInfo.getType().isReferenceType() && singleValue.isNull()
+              ? getNull()
+              : removedArgumentInfo.getType().toTypeElement(appView);
+      Instruction materializingInstruction =
+          singleValue.createMaterializingInstruction(
+              appView.withClassHierarchy(),
+              method,
+              valueNumberGenerator,
+              TypeAndLocalInfoSupplier.create(type, local));
+      writeRegister(
+          register,
+          materializingInstruction.outValue(),
+          ThrowingInfo.defaultForInstruction(materializingInstruction));
+      pendingArgumentInstructions.add(materializingInstruction);
     } else {
       assert removedArgumentInfo.isNeverUsed();
     }
@@ -2339,8 +2355,12 @@
   // See addDebugLocalStart and addDebugLocalEnd.
   private Value writeRegister(
       int register, TypeElement typeLattice, ThrowingInfo throwing, DebugLocalInfo local) {
+    return writeRegister(
+        register, new Value(valueNumberGenerator.next(), typeLattice, local), throwing);
+  }
+
+  private Value writeRegister(int register, Value value, ThrowingInfo throwing) {
     checkRegister(register);
-    Value value = new Value(valueNumberGenerator.next(), typeLattice, local);
     currentBlock.writeCurrentDefinition(register, value, throwing);
     return value;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
index df30aac..b2e8366 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
@@ -310,7 +310,10 @@
       DexType type = proto.parameters.values[i];
       if (type.isAlwaysNull(appView)) {
         RemovedArgumentInfo removedArg =
-            RemovedArgumentInfo.builder().setIsAlwaysNull().setType(type).build();
+            RemovedArgumentInfo.builder()
+                .setSingleValue(appView.abstractValueFactory().createNullValue())
+                .setType(type)
+                .build();
         argInfosBuilder.addArgumentInfo(i + offset, removedArg);
       }
     }
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java b/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java
index ddef0b4..b0be3f7 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
 import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
+import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
 import org.junit.Test;
 
 public class ArgumentInfoCollectionTest extends TestBase {
@@ -49,13 +50,22 @@
   @Test
   public void testCombineRemoved() {
     DexItemFactory factory = new DexItemFactory();
+    AbstractValueFactory abstractValueFactory = new AbstractValueFactory();
 
     // Arguments removed: 0 1 2 3 4 -> 0 2 4.
     ArgumentInfoCollection.Builder builder1 = ArgumentInfoCollection.builder();
     builder1.addArgumentInfo(
-        1, RemovedArgumentInfo.builder().setType(factory.intType).setIsAlwaysNull().build());
+        1,
+        RemovedArgumentInfo.builder()
+            .setType(factory.intType)
+            .setSingleValue(abstractValueFactory.createNullValue())
+            .build());
     builder1.addArgumentInfo(
-        3, RemovedArgumentInfo.builder().setType(factory.intType).setIsAlwaysNull().build());
+        3,
+        RemovedArgumentInfo.builder()
+            .setType(factory.intType)
+            .setSingleValue(abstractValueFactory.createNullValue())
+            .build());
     ArgumentInfoCollection arguments1 = builder1.build();
 
     // Arguments removed: 0 2 4 -> 0. Arguments 2 and 4 are at position 1 and 2 after first removal.
@@ -69,27 +79,36 @@
 
     RemovedArgumentInfo arg1 = combine.getArgumentInfo(1).asRemovedArgumentInfo();
     assertEquals(arg1.getType(), factory.intType);
-    assertTrue(arg1.isAlwaysNull());
+    assertTrue(arg1.hasSingleValue());
     RemovedArgumentInfo arg2 = combine.getArgumentInfo(2).asRemovedArgumentInfo();
     assertEquals(arg2.getType(), factory.doubleType);
-    assertFalse(arg2.isAlwaysNull());
+    assertFalse(arg2.hasSingleValue());
     RemovedArgumentInfo arg3 = combine.getArgumentInfo(3).asRemovedArgumentInfo();
     assertEquals(arg3.getType(), factory.intType);
-    assertTrue(arg3.isAlwaysNull());
+    assertTrue(arg3.hasSingleValue());
     RemovedArgumentInfo arg4 = combine.getArgumentInfo(4).asRemovedArgumentInfo();
     assertEquals(arg4.getType(), factory.doubleType);
-    assertFalse(arg4.isAlwaysNull());
+    assertFalse(arg4.hasSingleValue());
   }
 
   @Test
   public void testCombineRemoveRewritten() {
     DexItemFactory factory = new DexItemFactory();
+    AbstractValueFactory abstractValueFactory = new AbstractValueFactory();
 
     ArgumentInfoCollection.Builder builder1 = ArgumentInfoCollection.builder();
     builder1.addArgumentInfo(
-        1, RemovedArgumentInfo.builder().setType(factory.intType).setIsAlwaysNull().build());
+        1,
+        RemovedArgumentInfo.builder()
+            .setType(factory.intType)
+            .setSingleValue(abstractValueFactory.createNullValue())
+            .build());
     builder1.addArgumentInfo(
-        3, RemovedArgumentInfo.builder().setType(factory.intType).setIsAlwaysNull().build());
+        3,
+        RemovedArgumentInfo.builder()
+            .setType(factory.intType)
+            .setSingleValue(abstractValueFactory.createNullValue())
+            .build());
     ArgumentInfoCollection arguments1 = builder1.build();
 
     ArgumentInfoCollection.Builder builder2 = ArgumentInfoCollection.builder();
@@ -101,13 +120,13 @@
 
     RemovedArgumentInfo arg1 = combine.getArgumentInfo(1).asRemovedArgumentInfo();
     assertEquals(arg1.getType(), factory.intType);
-    assertTrue(arg1.isAlwaysNull());
+    assertTrue(arg1.hasSingleValue());
     RewrittenTypeInfo arg2 = combine.getArgumentInfo(2).asRewrittenTypeInfo();
     assertEquals(arg2.getOldType(), factory.floatType);
     assertEquals(arg2.getNewType(), factory.doubleType);
     RemovedArgumentInfo arg3 = combine.getArgumentInfo(3).asRemovedArgumentInfo();
     assertEquals(arg3.getType(), factory.intType);
-    assertTrue(arg3.isAlwaysNull());
+    assertTrue(arg3.hasSingleValue());
     RewrittenTypeInfo arg4 = combine.getArgumentInfo(4).asRewrittenTypeInfo();
     assertEquals(arg4.getOldType(), factory.floatType);
     assertEquals(arg4.getNewType(), factory.doubleType);