Filter out common uses of const-class values from lock candidate set
Change-Id: If413ecc4104f5bdbb722cf0f88d0ed7093014d6b
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
index 4661e68..7af534e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -66,7 +67,8 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerCheckCast(type);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index 51f34fc..9d4ffa0 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
@@ -97,8 +98,9 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
- registry.registerConstClass(type);
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
+ registry.registerConstClass(type, iterator);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
index 259a711..37d0ff4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
public class CfConstMethodHandle extends CfInstruction {
@@ -68,7 +69,8 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerMethodHandle(handle, MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
index 70417f6..b6a560f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
@@ -66,7 +67,8 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerProto(type);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
index e9f11a8..b42194f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -23,6 +23,7 @@
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
public class CfDexItemBasedConstString extends CfInstruction {
@@ -89,7 +90,8 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
if (nameComputationInfo.needsToRegisterReference()) {
assert item.isDexType();
registry.registerTypeReference(item.asDexType());
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index 7c28eff..9b463fd 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import java.util.Comparator;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -94,7 +95,8 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
switch (opcode) {
case Opcodes.GETFIELD:
registry.registerInstanceFieldRead(field);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
index e9c06e0..2c81fce 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
public class CfInitClass extends CfInstruction {
@@ -77,7 +78,8 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerInitClass(clazz);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index 1300458..899ef31 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -75,7 +76,8 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerInstanceOf(type);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index b8874e8..3c36d33 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.code.CfOrDexInstruction;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.ClasspathMethod;
@@ -21,9 +22,10 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
-public abstract class CfInstruction {
+public abstract class CfInstruction implements CfOrDexInstruction {
public abstract void write(
AppView<?> appView,
@@ -72,15 +74,18 @@
return printer.toString();
}
- public void registerUse(UseRegistry registry, ProgramMethod context) {
- internalRegisterUse(registry, context);
+ public void registerUse(
+ UseRegistry registry, ProgramMethod context, ListIterator<CfInstruction> iterator) {
+ internalRegisterUse(registry, context, iterator);
}
- public void registerUseForDesugaring(UseRegistry registry, ClasspathMethod context) {
- internalRegisterUse(registry, context);
+ public void registerUseForDesugaring(
+ UseRegistry registry, ClasspathMethod context, ListIterator<CfInstruction> iterator) {
+ internalRegisterUse(registry, context, iterator);
}
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
// Intentionally empty.
}
@@ -88,6 +93,16 @@
return null;
}
+ @Override
+ public CfInstruction asCfInstruction() {
+ return this;
+ }
+
+ @Override
+ public boolean isCfInstruction() {
+ return true;
+ }
+
public CfConstString asConstString() {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index 4765be5..4f5159b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -34,6 +34,7 @@
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import java.util.Arrays;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -111,7 +112,8 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
Type invokeType = getInvokeType(context);
switch (invokeType) {
case DIRECT:
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
index add492c..92384c8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.naming.NamingLens;
import java.util.ArrayList;
import java.util.List;
+import java.util.ListIterator;
import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -112,7 +113,8 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerCallSite(callSite);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
index 5f405d3..d52e429 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.InternalOptions;
import java.util.Comparator;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -75,7 +76,8 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerTypeReference(type);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
index 60da1b2..a4be181 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -66,7 +67,8 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerNewInstance(type);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
index 30671bd..794227e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -23,6 +23,7 @@
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.DescriptorUtils;
+import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -112,7 +113,8 @@
}
@Override
- void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
+ void internalRegisterUse(
+ UseRegistry registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
if (!type.isPrimitiveArrayType()) {
registry.registerTypeReference(type);
}
diff --git a/src/main/java/com/android/tools/r8/code/CfOrDexInstruction.java b/src/main/java/com/android/tools/r8/code/CfOrDexInstruction.java
new file mode 100644
index 0000000..e85c75c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/code/CfOrDexInstruction.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.code;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+
+public interface CfOrDexInstruction {
+
+ CfInstruction asCfInstruction();
+
+ boolean isCfInstruction();
+}
diff --git a/src/main/java/com/android/tools/r8/code/ConstClass.java b/src/main/java/com/android/tools/r8/code/ConstClass.java
index 3c6d03e..5562a69 100644
--- a/src/main/java/com/android/tools/r8/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/code/ConstClass.java
@@ -72,7 +72,7 @@
@Override
public void registerUse(UseRegistry registry) {
- registry.registerConstClass(getType());
+ registry.registerConstClass(getType(), null);
}
public DexType getType() {
diff --git a/src/main/java/com/android/tools/r8/code/Instruction.java b/src/main/java/com/android/tools/r8/code/Instruction.java
index 4ff81dc..52aa90d 100644
--- a/src/main/java/com/android/tools/r8/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
+import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.graph.DexCallSite;
@@ -21,7 +22,7 @@
import java.nio.ShortBuffer;
import java.util.function.BiPredicate;
-public abstract class Instruction implements Comparable<Instruction> {
+public abstract class Instruction implements CfOrDexInstruction, Comparable<Instruction> {
public static final Instruction[] EMPTY_ARRAY = {};
public final static int[] NO_TARGETS = null;
@@ -134,6 +135,16 @@
this.offset = offset;
}
+ @Override
+ public CfInstruction asCfInstruction() {
+ return null;
+ }
+
+ @Override
+ public boolean isCfInstruction() {
+ return false;
+ }
+
public CheckCast asCheckCast() {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index dbefe85..d6ae59f 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -56,6 +56,7 @@
import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.BiPredicate;
@@ -511,16 +512,20 @@
@Override
public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
- for (CfInstruction instruction : instructions) {
- instruction.registerUse(registry, method);
+ ListIterator<CfInstruction> iterator = instructions.listIterator();
+ while (iterator.hasNext()) {
+ CfInstruction instruction = iterator.next();
+ instruction.registerUse(registry, method, iterator);
}
tryCatchRanges.forEach(tryCatch -> tryCatch.internalRegisterUse(registry, method));
}
@Override
public void registerCodeReferencesForDesugaring(ClasspathMethod method, UseRegistry registry) {
- for (CfInstruction instruction : instructions) {
- instruction.registerUseForDesugaring(registry, method);
+ ListIterator<CfInstruction> iterator = instructions.listIterator();
+ while (iterator.hasNext()) {
+ CfInstruction instruction = iterator.next();
+ instruction.registerUseForDesugaring(registry, method, iterator);
}
tryCatchRanges.forEach(tryCatch -> tryCatch.guards.forEach(registry::registerTypeReference));
}
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 13c4ac4..44314e5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -29,6 +29,7 @@
import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaring;
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.utils.ArrayUtils;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.LRUCacheTable;
import com.google.common.base.Strings;
import com.google.common.collect.BiMap;
@@ -343,6 +344,7 @@
createStaticallyKnownType(referenceFieldUpdaterDescriptor);
public final DexType classType = createStaticallyKnownType(classDescriptor);
+ public final DexType packageType = createStaticallyKnownType(Package.class);
public final DexType classLoaderType = createStaticallyKnownType(classLoaderDescriptor);
public final DexType fieldType = createStaticallyKnownType(fieldDescriptor);
public final DexType methodType = createStaticallyKnownType(methodDescriptor);
@@ -1160,6 +1162,8 @@
public final DexMethod desiredAssertionStatus;
public final DexMethod forName;
public final DexMethod forName3;
+ public final DexMethod getClassLoader =
+ createMethod(classType, createProto(classLoaderType), "getClassLoader");
public final DexMethod getName;
public final DexMethod getCanonicalName;
public final DexMethod getSimpleName;
@@ -1169,6 +1173,8 @@
public final DexMethod getDeclaredField;
public final DexMethod getMethod;
public final DexMethod getDeclaredMethod;
+ public final DexMethod getPackage =
+ createMethod(classType, createProto(packageType), "getPackage");
public final DexMethod newInstance;
private final Set<DexMethod> getMembers;
public final Set<DexMethod> getNames;
@@ -1926,6 +1932,11 @@
return createStaticallyKnownType(createString(descriptor));
}
+ private DexType createStaticallyKnownType(Class<?> clazz) {
+ return createStaticallyKnownType(
+ createString(DescriptorUtils.javaTypeToDescriptor(clazz.getTypeName())));
+ }
+
private DexType createStaticallyKnownType(DexString descriptor) {
DexType type = internalCreateType(descriptor);
// Conservatively add all statically known types to "compiler synthesized types set".
diff --git a/src/main/java/com/android/tools/r8/graph/UseRegistry.java b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
index 4a3327a..8f64090 100644
--- a/src/main/java/com/android/tools/r8/graph/UseRegistry.java
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.code.CfOrDexInstruction;
+import java.util.ListIterator;
public abstract class UseRegistry {
@@ -67,7 +69,8 @@
public abstract void registerInstanceOf(DexType type);
- public void registerConstClass(DexType type) {
+ public void registerConstClass(
+ DexType type, ListIterator<? extends CfOrDexInstruction> iterator) {
registerTypeReference(type);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnqueuerUseRegistry.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnqueuerUseRegistry.java
index 2ef11c9..7dca039 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnqueuerUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnqueuerUseRegistry.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.analysis.proto;
+import com.android.tools.r8.code.CfOrDexInstruction;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexType;
@@ -12,6 +13,7 @@
import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerUseRegistryFactory;
+import java.util.ListIterator;
public class ProtoEnqueuerUseRegistry extends DefaultEnqueuerUseRegistry {
@@ -30,19 +32,20 @@
}
/**
- * Unlike {@link DefaultEnqueuerUseRegistry#registerConstClass(DexType)}, this method does not
- * trace any const-class instructions in every implementation of dynamicMethod().
+ * Unlike {@link DefaultEnqueuerUseRegistry#registerConstClass(DexType, ListIterator)}, this
+ * method does not trace any const-class instructions in every implementation of dynamicMethod().
*
* <p>The const-class instructions that remain after the proto schema has been optimized will be
* traced manually by {@link ProtoEnqueuerExtension#tracePendingInstructionsInDynamicMethods}.
*/
@Override
- public void registerConstClass(DexType type) {
+ public void registerConstClass(
+ DexType type, ListIterator<? extends CfOrDexInstruction> iterator) {
if (references.isDynamicMethod(getContextMethod())) {
enqueuer.addDeadProtoTypeCandidate(type);
return;
}
- super.registerConstClass(type);
+ super.registerConstClass(type, iterator);
}
/**
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index a81b5dc..3a716e3 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -165,8 +165,10 @@
private final Set<DexType> noHorizontalClassMerging;
private final Set<DexType> noStaticClassMerging;
- /** Set of const-class references. */
- public final Set<DexType> constClassReferences;
+ /**
+ * Set of lock candidates (i.e., types whose class reference may flow to a monitor instruction).
+ */
+ public final Set<DexType> lockCandidates;
/**
* A map from seen init-class references to the minimum required visibility of the corresponding
* static field.
@@ -234,7 +236,7 @@
Set<DexType> prunedTypes,
Map<DexField, Int2ReferenceMap<DexField>> switchMaps,
EnumValueInfoMapCollection enumValueInfoMaps,
- Set<DexType> constClassReferences,
+ Set<DexType> lockCandidates,
Map<DexType, Visibility> initClassReferences) {
super(syntheticItems, classToFeatureSplitMap, mainDexClasses);
this.deadProtoTypes = deadProtoTypes;
@@ -273,7 +275,7 @@
this.prunedTypes = prunedTypes;
this.switchMaps = switchMaps;
this.enumValueInfoMaps = enumValueInfoMaps;
- this.constClassReferences = constClassReferences;
+ this.lockCandidates = lockCandidates;
this.initClassReferences = initClassReferences;
}
@@ -315,7 +317,7 @@
Set<DexType> prunedTypes,
Map<DexField, Int2ReferenceMap<DexField>> switchMaps,
EnumValueInfoMapCollection enumValueInfoMaps,
- Set<DexType> constClassReferences,
+ Set<DexType> lockCandidates,
Map<DexType, Visibility> initClassReferences) {
super(
appInfoWithClassHierarchy.getSyntheticItems().commit(appInfoWithClassHierarchy.app()),
@@ -357,7 +359,7 @@
this.prunedTypes = prunedTypes;
this.switchMaps = switchMaps;
this.enumValueInfoMaps = enumValueInfoMaps;
- this.constClassReferences = constClassReferences;
+ this.lockCandidates = lockCandidates;
this.initClassReferences = initClassReferences;
}
@@ -404,7 +406,7 @@
previous.prunedTypes,
previous.switchMaps,
previous.enumValueInfoMaps,
- previous.constClassReferences,
+ previous.lockCandidates,
previous.initClassReferences);
}
@@ -457,7 +459,7 @@
: CollectionUtils.mergeSets(previous.prunedTypes, removedClasses),
previous.switchMaps,
previous.enumValueInfoMaps,
- previous.constClassReferences,
+ previous.lockCandidates,
previous.initClassReferences);
assert keepInfo.verifyNoneArePinned(removedClasses, previous);
}
@@ -543,7 +545,7 @@
this.prunedTypes = previous.prunedTypes;
this.switchMaps = switchMaps;
this.enumValueInfoMaps = enumValueInfoMaps;
- this.constClassReferences = previous.constClassReferences;
+ this.lockCandidates = previous.lockCandidates;
this.initClassReferences = previous.initClassReferences;
previous.markObsolete();
}
@@ -700,7 +702,7 @@
* merge any const-class classes. More info at b/142438687.
*/
public boolean isLockCandidate(DexType type) {
- return constClassReferences.contains(type);
+ return lockCandidates.contains(type);
}
public Set<DexType> getDeadProtoTypes() {
@@ -1042,7 +1044,7 @@
prunedTypes,
lens.rewriteFieldKeys(switchMaps),
enumValueInfoMaps.rewrittenWithLens(lens),
- lens.rewriteTypes(constClassReferences),
+ lens.rewriteTypes(lockCandidates),
lens.rewriteTypeKeys(initClassReferences));
}
diff --git a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
index b67d90d..18ae137 100644
--- a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.shaking;
+import com.android.tools.r8.code.CfOrDexInstruction;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -14,6 +15,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
+import java.util.ListIterator;
public class DefaultEnqueuerUseRegistry extends UseRegistry {
@@ -114,8 +116,9 @@
}
@Override
- public void registerConstClass(DexType type) {
- enqueuer.traceConstClass(type, context);
+ public void registerConstClass(
+ DexType type, ListIterator<? extends CfOrDexInstruction> iterator) {
+ enqueuer.traceConstClass(type, context, iterator);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 7a2969e..b96a14f 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -10,6 +10,9 @@
import static com.android.tools.r8.shaking.AnnotationRemover.shouldKeepAnnotation;
import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.code.CfOrDexInstruction;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
@@ -31,6 +34,7 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexItemFactory.ClassMethods;
import com.android.tools.r8.graph.DexLibraryClass;
import com.android.tools.r8.graph.DexMember;
import com.android.tools.r8.graph.DexMethod;
@@ -101,6 +105,7 @@
import com.android.tools.r8.utils.DequeUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
+import com.android.tools.r8.utils.IteratorUtils;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.Pair;
@@ -131,6 +136,7 @@
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -314,10 +320,10 @@
private final MutableKeepInfoCollection keepInfo = new MutableKeepInfoCollection();
/**
- * A set of seen const-class references that both serve as an initial lock-candidate set and will
- * prevent statically merging the classes referenced.
+ * A set of seen const-class references that serve as an initial lock-candidate set and will
+ * prevent class merging.
*/
- private final Set<DexType> constClassReferences = Sets.newIdentityHashSet();
+ private final Set<DexType> lockCandidates = Sets.newIdentityHashSet();
/**
* A map from seen init-class references to the minimum required visibility of the corresponding
@@ -926,17 +932,63 @@
traceConstClassOrCheckCast(type, currentMethod);
}
- void traceConstClass(DexType type, ProgramMethod currentMethod) {
+ void traceConstClass(
+ DexType type,
+ ProgramMethod currentMethod,
+ ListIterator<? extends CfOrDexInstruction> iterator) {
+ handleLockCandidate(type, currentMethod, iterator);
+ traceConstClassOrCheckCast(type, currentMethod);
+ }
+
+ private void handleLockCandidate(
+ DexType type,
+ ProgramMethod currentMethod,
+ ListIterator<? extends CfOrDexInstruction> iterator) {
// We conservatively group T.class and T[].class to ensure that we do not merge T with S if
// potential locks on T[].class and S[].class exists.
DexType baseType = type.toBaseType(appView.dexItemFactory());
if (baseType.isClassType()) {
DexProgramClass baseClass = getProgramClassOrNull(baseType);
- if (baseClass != null) {
- constClassReferences.add(baseType);
+ if (baseClass != null && isConstClassMaybeUsedAsLock(currentMethod, iterator)) {
+ lockCandidates.add(baseType);
}
}
- traceConstClassOrCheckCast(type, currentMethod);
+ }
+
+ /**
+ * Returns true if the const-class value may flow into a monitor instruction.
+ *
+ * <p>Some common usages of const-class values are handled, such as calls to Class.get*Name().
+ */
+ private boolean isConstClassMaybeUsedAsLock(
+ ProgramMethod currentMethod, ListIterator<? extends CfOrDexInstruction> iterator) {
+ if (iterator == null) {
+ return true;
+ }
+ boolean result = true;
+ if (currentMethod.getDefinition().getCode().isCfCode()) {
+ CfInstruction nextInstruction =
+ IteratorUtils.nextUntil(
+ iterator,
+ instruction ->
+ !instruction.asCfInstruction().isLabel()
+ && !instruction.asCfInstruction().isPosition())
+ .asCfInstruction();
+ assert nextInstruction != null;
+ if (nextInstruction.isInvoke()) {
+ CfInvoke invoke = nextInstruction.asInvoke();
+ DexMethod invokedMethod = invoke.getMethod();
+ ClassMethods classMethods = appView.dexItemFactory().classMethods;
+ if (classMethods.isReflectiveNameLookup(invokedMethod)
+ || invokedMethod == classMethods.desiredAssertionStatus
+ || invokedMethod == classMethods.getClassLoader
+ || invokedMethod == classMethods.getPackage) {
+ result = false;
+ }
+ }
+ iterator.previous();
+ }
+ return result;
}
private void traceConstClassOrCheckCast(DexType type, ProgramMethod currentMethod) {
@@ -3137,7 +3189,7 @@
Collections.emptySet(),
Collections.emptyMap(),
EnumValueInfoMapCollection.empty(),
- constClassReferences,
+ lockCandidates,
initClassReferences);
appInfo.markObsolete();
return appInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
index 2bc8459..c368c21 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
@@ -176,7 +176,7 @@
@Override
public void run(Enqueuer enqueuer) {
- enqueuer.traceConstClass(type, context);
+ enqueuer.traceConstClass(type, context, null);
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
index 974fdb1..fe5a13a 100644
--- a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
@@ -337,7 +337,7 @@
// We are not allowed to merge synchronized classes with synchronized methods.
return;
}
- if (appView.appInfo().constClassReferences.contains(clazz.type)) {
+ if (appView.appInfo().lockCandidates.contains(clazz.type)) {
// Since the type is const-class referenced (and the static merger does not create a lens
// to map the merged type) the class will likely remain and there is no gain from merging.
return;
diff --git a/src/main/java/com/android/tools/r8/utils/IteratorUtils.java b/src/main/java/com/android/tools/r8/utils/IteratorUtils.java
index f38c02a..b12de07 100644
--- a/src/main/java/com/android/tools/r8/utils/IteratorUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/IteratorUtils.java
@@ -50,6 +50,16 @@
};
}
+ public static <T> T nextUntil(Iterator<T> iterator, Predicate<T> predicate) {
+ while (iterator.hasNext()) {
+ T element = iterator.next();
+ if (predicate.test(element)) {
+ return element;
+ }
+ }
+ return null;
+ }
+
public static <T> T peekPrevious(ListIterator<T> iterator) {
T previous = iterator.previous();
T next = iterator.next();
diff --git a/src/test/java/com/android/tools/r8/TestRunResult.java b/src/test/java/com/android/tools/r8/TestRunResult.java
index 85214af..e4640ec 100644
--- a/src/test/java/com/android/tools/r8/TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -13,7 +13,6 @@
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
-import java.util.function.Consumer;
import java.util.function.Function;
import org.hamcrest.Matcher;
@@ -40,7 +39,7 @@
public abstract RR disassemble() throws IOException, ExecutionException;
- public RR apply(Consumer<RR> fn) {
+ public <E extends Throwable> RR apply(ThrowingConsumer<RR, E> fn) throws E {
fn.accept(self());
return self();
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithGetNameTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithGetNameTest.java
new file mode 100644
index 0000000..df89c21
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithGetNameTest.java
@@ -0,0 +1,77 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.classmerging.vertical;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class VerticalClassMergingWithGetNameTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public VerticalClassMergingWithGetNameTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addVerticallyMergedClassesInspector(
+ inspector -> inspector.assertMergedIntoSubtype(A.class))
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .apply(
+ runResult -> {
+ ClassSubject bClassSubject = runResult.inspector().clazz(B.class);
+ assertThat(bClassSubject, isPresent());
+ runResult.assertSuccessWithOutputLines(
+ bClassSubject.getFinalName(), bClassSubject.getFinalName());
+ });
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ new B().print();
+ }
+ }
+
+ static class A {
+
+ @NeverInline
+ public void print() {
+ System.out.println(A.class.getName());
+ }
+ }
+
+ static class B extends A {
+
+ @NeverInline
+ public void print() {
+ super.print();
+ System.out.println(B.class.getName());
+ }
+ }
+}