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;
}
}