Merge "Do not replace assumevalue target twice."
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 3601ee9..afd923c 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -331,6 +331,10 @@
     return null;
   }
 
+  public void registerNewType(DexType newType, DexType superType) {
+    // We do not track subtyping relationships in the basic AppInfo. So do nothing.
+  }
+
   public List<DexClass> getSuperTypeClasses(DexType type) {
     List<DexClass> result = new ArrayList<>();
     do {
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index 503bc89..9c87b61 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -227,6 +227,12 @@
   }
 
   @Override
+  public void registerNewType(DexType newType, DexType superType) {
+    // Register the relationship between this type and its superType.
+    superType.addDirectSubtype(newType);
+  }
+
+  @Override
   public boolean hasSubtyping() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
index b2041d3..968e560 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
@@ -106,7 +106,7 @@
     if (current == null) {
       throw new IllegalStateException();
     }
-    assert current.outValue() == null || current.outValue().numberOfAllUsers() == 0;
+    assert current.outValue() == null || !current.outValue().isUsed();
     for (int i = 0; i < current.inValues().size(); i++) {
       Value value = current.inValues().get(i);
       value.removeUser(current);
@@ -323,7 +323,7 @@
     while (inlineeIterator.hasNext()) {
       Instruction instruction = inlineeIterator.next();
       if (instruction.isArgument()) {
-        assert instruction.outValue().numberOfAllUsers() == 0;
+        assert !instruction.outValue().isUsed();
         assert instruction.outValue() == arguments.get(index++);
         inlineeIterator.remove();
       }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index e6ba6c0..b7a18f0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -61,7 +61,7 @@
   }
 
   public void setOutValue(Value value) {
-    assert outValue == null || !outValue.hasUsersInfo() || outValue.numberOfAllUsers() == 0;
+    assert outValue == null || !outValue.hasUsersInfo() || !outValue.isUsed();
     outValue = value;
     if (outValue != null) {
       outValue.definition = this;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index e0bfdd0..035bf95 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -219,6 +219,12 @@
     return numberOfUsers() + numberOfPhiUsers() + numberOfDebugUsers();
   }
 
+  public boolean isUsed() {
+    return !users.isEmpty()
+        || !phiUsers.isEmpty()
+        || ((debugData != null) && !debugData.debugUsers.isEmpty());
+  }
+
   public void addUser(Instruction user) {
     users.add(user);
     uniqueUsers = null;
@@ -503,7 +509,7 @@
 
   public boolean isDead(InternalOptions options) {
     // Totally unused values are trivially dead.
-    return numberOfAllUsers() == 0 || isDead(new HashSet<>(), options);
+    return !isUsed() || isDead(new HashSet<>(), options);
   }
 
   protected boolean isDead(Set<Value> active, InternalOptions options) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index a4bb015..659a503 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -369,6 +369,8 @@
       count++;
       result = application.dexItemFactory.createType(DescriptorUtils.javaTypeToDescriptor(name));
     } while (application.definitionFor(result) != null);
+    // Register the newly generated type in the subtyping hierarchy, if we have one.
+    appInfo.registerNewType(result, appInfo.dexItemFactory.objectType);
     return result;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 7954ae4..0a6ea7e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -83,9 +83,7 @@
         : factory.createField(lambdaClassType, lambdaClassType, rewriter.instanceFieldName);
 
     // We have to register this new class as a subtype of object.
-    if (rewriter.appInfo.hasSubtyping()) {
-      factory.objectType.addDirectSubtype(type);
-    }
+    rewriter.appInfo.registerNewType(type, factory.objectType);
   }
 
   // Generate unique lambda class type for lambda descriptor and instantiation point context.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
index b683f3a..3a1902e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
@@ -105,7 +105,7 @@
       // Remove unused invoke results.
       if (current.isInvoke()
           && current.outValue() != null
-          && current.outValue().numberOfAllUsers() == 0) {
+          && !current.outValue().isUsed()) {
         current.setOutValue(null);
       }
       // Never remove instructions that can have side effects, except for const-class.
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 8a02435..a34c8cb 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
@@ -137,10 +137,10 @@
         ProguardMemberRuleLookup lookup = lookupMemberRule(definition);
         if (lookup != null) {
           if (lookup.type == RuleType.ASSUME_NO_SIDE_EFFECTS
-              && (invoke.outValue() == null || invoke.outValue().numberOfAllUsers() == 0)) {
+              && (invoke.outValue() == null || !invoke.outValue().isUsed())) {
             iterator.remove();
             invokeReplaced = true;
-          } else {
+          } 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);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 8cc8ec4..3857c1f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -400,7 +400,7 @@
 
       // Allow all new-instance instructions in a outline.
       if (instruction.isNewInstance()) {
-        if (instruction.outValue().numberOfAllUsers() > 0) {
+        if (instruction.outValue().isUsed()) {
           // Track the new-instance value to make sure the <init> call is part of the outline.
           pendingNewInstanceIndex = index;
         }
@@ -711,7 +711,7 @@
           }
         }
         assert m.proto.shorty.toString().length() - 1 == in.size();
-        if (returnValue != null && returnValue.numberOfAllUsers() == 0) {
+        if (returnValue != null && !returnValue.isUsed()) {
           returnValue = null;
         }
         Invoke outlineInvoke = new InvokeStatic(m, returnValue, in);
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index fae2e54..38cdb29 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -1955,7 +1955,7 @@
           // For instructions that define values which have no use create a live range covering
           // the instruction. This will typically be instructions that can have side effects even
           // if their output is not used.
-          if (definition.numberOfAllUsers() == 0) {
+          if (!definition.isUsed()) {
             addLiveRange(definition, block, instruction.getNumber() + INSTRUCTION_NUMBER_DELTA);
           }
           live.remove(definition);
diff --git a/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLitePruner.java b/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLitePruner.java
index 8b0ac9e..4610f41 100644
--- a/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLitePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLitePruner.java
@@ -196,7 +196,7 @@
           // Remove now unneeded constructor calls.
           InvokeStatic invokeStatic = insn.asInvokeStatic();
           DexMethod invokedMethod = invokeStatic.getInvokedMethod();
-          if ((invokeStatic.outValue().numberOfAllUsers() == 0)
+          if ((!invokeStatic.outValue().isUsed())
               && invokedMethod.proto.returnType.isSubtypeOf(protobufListType, appInfo)) {
             it.remove();
           }