Only rewrite android.util.Log calls to false in log optimizer

Fixes: b/234773068
Change-Id: Ic108e15e90c672303832090a8227ce9a87e7a658
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java
index 59fc490..f614d65 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java
@@ -57,8 +57,7 @@
 
   static PrimitiveFrameType primitive(DexType type) {
     assert type.isPrimitiveType();
-    char c = (char) type.getDescriptor().content[0];
-    switch (c) {
+    switch (type.getDescriptor().getFirstByteAsChar()) {
       case 'Z':
         return booleanType();
       case 'B':
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 1600e0e..e9f0446 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -752,9 +752,7 @@
 
   public BoxedPrimitiveMembers getBoxedMembersForPrimitiveOrVoidType(DexType type) {
     assert type.isPrimitiveType() || type.isVoidType();
-    char c = (char) type.getDescriptor().content[0];
-    assert c == type.toDescriptorString().charAt(0);
-    switch (c) {
+    switch (type.getDescriptor().getFirstByteAsChar()) {
       case 'B':
         return byteMembers;
       case 'C':
diff --git a/src/main/java/com/android/tools/r8/graph/DexString.java b/src/main/java/com/android/tools/r8/graph/DexString.java
index 87630f2..f6d0d19 100644
--- a/src/main/java/com/android/tools/r8/graph/DexString.java
+++ b/src/main/java/com/android/tools/r8/graph/DexString.java
@@ -35,6 +35,10 @@
     this.content = encodeToMutf8(string);
   }
 
+  public char getFirstByteAsChar() {
+    return (char) content[0];
+  }
+
   @Override
   public DexString self() {
     return this;
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index df11e7e..1efc762 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -223,7 +223,7 @@
   }
 
   public char toShorty() {
-    char c = (char) descriptor.content[0];
+    char c = descriptor.getFirstByteAsChar();
     return c == '[' ? 'L' : c;
   }
 
@@ -266,58 +266,58 @@
   }
 
   public boolean isPrimitiveType() {
-    return DescriptorUtils.isPrimitiveType((char) descriptor.content[0]);
+    return DescriptorUtils.isPrimitiveType(descriptor.getFirstByteAsChar());
   }
 
   public boolean isVoidType() {
-    return (char) descriptor.content[0] == 'V';
+    return descriptor.getFirstByteAsChar() == 'V';
   }
 
   public boolean isBooleanType() {
-    return descriptor.content[0] == 'Z';
+    return descriptor.getFirstByteAsChar() == 'Z';
   }
 
   public boolean isByteType() {
-    return descriptor.content[0] == 'B';
+    return descriptor.getFirstByteAsChar() == 'B';
   }
 
   public boolean isCharType() {
-    return descriptor.content[0] == 'C';
+    return descriptor.getFirstByteAsChar() == 'C';
   }
 
   public boolean isShortType() {
-    return descriptor.content[0] == 'S';
+    return descriptor.getFirstByteAsChar() == 'S';
   }
 
   public boolean isIntType() {
-    return descriptor.content[0] == 'I';
+    return descriptor.getFirstByteAsChar() == 'I';
   }
 
   public boolean isFloatType() {
-    return descriptor.content[0] == 'F';
+    return descriptor.getFirstByteAsChar() == 'F';
   }
 
   public boolean isLongType() {
-    return descriptor.content[0] == 'J';
+    return descriptor.getFirstByteAsChar() == 'J';
   }
 
   public boolean isDoubleType() {
-    return descriptor.content[0] == 'D';
+    return descriptor.getFirstByteAsChar() == 'D';
   }
 
   public boolean isNullValueType() {
-    boolean isNullValueType = descriptor.content[0] == 'N';
+    boolean isNullValueType = descriptor.getFirstByteAsChar() == 'N';
     assert !isNullValueType || this == DexItemFactory.nullValueType;
     return isNullValueType;
   }
 
   public boolean isArrayType() {
-    char firstChar = (char) descriptor.content[0];
+    char firstChar = descriptor.getFirstByteAsChar();
     return firstChar == '[';
   }
 
   public boolean isClassType() {
-    char firstChar = (char) descriptor.content[0];
+    char firstChar = descriptor.getFirstByteAsChar();
     return firstChar == 'L';
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
index 37ca53d..22a3425 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
@@ -110,51 +110,63 @@
       DexClassAndMethod singleTarget,
       Set<Value> affectedValues,
       Set<BasicBlock> blocksToRemove) {
+    // Replace Android logging statements like Log.w(...) and Log.IsLoggable(..., WARNING) at or
+    // below a certain logging level by false.
+    int logLevel = getLogLevel(invoke, singleTarget);
     int maxRemovedAndroidLogLevel =
         appView.options().getProguardConfiguration().getMaxRemovedAndroidLogLevel();
-    if (singleTarget.getReference() == isLoggableMethod) {
-      Value logLevelValue = invoke.arguments().get(1).getAliasedValue();
-      if (!logLevelValue.isPhi() && !logLevelValue.hasLocalInfo()) {
-        Instruction definition = logLevelValue.definition;
-        if (definition.isConstNumber()) {
-          int logLevel = definition.asConstNumber().getIntValue();
-          replaceInvokeWithConstNumber(
-              code, instructionIterator, invoke, maxRemovedAndroidLogLevel >= logLevel ? 0 : 1);
-        }
-      }
-    } else if (singleTarget.getReference() == vMethod) {
-      if (maxRemovedAndroidLogLevel >= VERBOSE) {
-        replaceInvokeWithConstNumber(code, instructionIterator, invoke, 0);
-      }
-    } else if (singleTarget.getReference() == dMethod) {
-      if (maxRemovedAndroidLogLevel >= DEBUG) {
-        replaceInvokeWithConstNumber(code, instructionIterator, invoke, 0);
-      }
-    } else if (singleTarget.getReference() == iMethod) {
-      if (maxRemovedAndroidLogLevel >= INFO) {
-        replaceInvokeWithConstNumber(code, instructionIterator, invoke, 0);
-      }
-    } else if (singleTarget.getReference() == wMethod) {
-      if (maxRemovedAndroidLogLevel >= WARN) {
-        replaceInvokeWithConstNumber(code, instructionIterator, invoke, 0);
-      }
-    } else if (singleTarget.getReference() == eMethod) {
-      if (maxRemovedAndroidLogLevel >= ERROR) {
-        replaceInvokeWithConstNumber(code, instructionIterator, invoke, 0);
-      }
-    } else if (singleTarget.getReference() == wtfMethod) {
-      if (maxRemovedAndroidLogLevel >= ASSERT) {
-        replaceInvokeWithConstNumber(code, instructionIterator, invoke, 0);
-      }
+    if (logLevel <= maxRemovedAndroidLogLevel) {
+      instructionIterator.replaceCurrentInstructionWithConstFalse(code);
     }
   }
 
-  private void replaceInvokeWithConstNumber(
-      IRCode code, InstructionListIterator instructionIterator, InvokeMethod invoke, int value) {
-    if (invoke.hasOutValue() && invoke.outValue().hasAnyUsers()) {
-      instructionIterator.replaceCurrentInstructionWithConstInt(code, value);
-    } else {
-      instructionIterator.removeOrReplaceByDebugLocalRead();
+  /**
+   * @return The log level of the given invoke if it is a call to an android.util.Log method and the
+   *     log level can be determined, otherwise returns -1.
+   */
+  private int getLogLevel(InvokeMethod invoke, DexClassAndMethod singleTarget) {
+    DexMethod singleTargetReference = singleTarget.getReference();
+    switch (singleTargetReference.getName().getFirstByteAsChar()) {
+      case 'd':
+        if (singleTargetReference == dMethod) {
+          return DEBUG;
+        }
+        break;
+      case 'e':
+        if (singleTargetReference == eMethod) {
+          return ERROR;
+        }
+        break;
+      case 'i':
+        if (singleTargetReference == iMethod) {
+          return INFO;
+        }
+        if (singleTargetReference == isLoggableMethod) {
+          Value logLevelValue = invoke.arguments().get(1).getAliasedValue();
+          if (!logLevelValue.isPhi() && !logLevelValue.hasLocalInfo()) {
+            Instruction definition = logLevelValue.getDefinition();
+            if (definition.isConstNumber()) {
+              return definition.asConstNumber().getIntValue();
+            }
+          }
+        }
+        break;
+      case 'v':
+        if (singleTargetReference == vMethod) {
+          return VERBOSE;
+        }
+        break;
+      case 'w':
+        if (singleTargetReference == wMethod) {
+          return WARN;
+        }
+        if (singleTargetReference == wtfMethod) {
+          return ASSERT;
+        }
+        break;
+      default:
+        break;
     }
+    return -1;
   }
 }