Fix inadequate enum unboxing reprocessing when generating class files Change-Id: I38b99999124804a06f5935ebdeebb726f3bea85f
diff --git a/src/main/java/com/android/tools/r8/graph/DexCallSite.java b/src/main/java/com/android/tools/r8/graph/DexCallSite.java index 9cb4704..3aa03da 100644 --- a/src/main/java/com/android/tools/r8/graph/DexCallSite.java +++ b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
@@ -102,6 +102,14 @@ return application.getCallSite(name, desc, bootstrapMethod, bootstrapArgs); } + public List<DexValue> getBootstrapArgs() { + return bootstrapArgs; + } + + public DexProto getMethodProto() { + return methodProto; + } + @Override public DexCallSite self() { return this;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java index a5ed9fb..2e74bb2 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -33,7 +33,9 @@ import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.DexMethodHandle; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.FieldResolutionResult; import com.android.tools.r8.graph.GraphLens; @@ -61,6 +63,7 @@ import com.android.tools.r8.ir.code.If; import com.android.tools.r8.ir.code.InstanceGet; import com.android.tools.r8.ir.code.Instruction; +import com.android.tools.r8.ir.code.InvokeCustom; import com.android.tools.r8.ir.code.InvokeMethod; import com.android.tools.r8.ir.code.InvokeStatic; import com.android.tools.r8.ir.code.InvokeVirtual; @@ -122,6 +125,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -217,6 +221,13 @@ } private DexProgramClass getEnumUnboxingCandidateOrNull(DexType type) { + if (type.isArrayType()) { + return getEnumUnboxingCandidateOrNull(type.toBaseType(appView.dexItemFactory())); + } + if (type.isPrimitiveType() || type.isVoidType()) { + return null; + } + assert type.isClassType(); return enumUnboxingCandidatesInfo.getCandidateClassOrNull(type); } @@ -253,6 +264,9 @@ case Opcodes.CHECK_CAST: analyzeCheckCast(instruction.asCheckCast(), eligibleEnums); break; + case Opcodes.INVOKE_CUSTOM: + analyzeInvokeCustom(instruction.asInvokeCustom(), eligibleEnums); + break; case INVOKE_STATIC: analyzeInvokeStatic(instruction.asInvokeStatic(), eligibleEnums, code.context()); break; @@ -289,6 +303,49 @@ } } + private void analyzeInvokeCustom(InvokeCustom invoke, Set<DexType> eligibleEnums) { + Consumer<DexType> typeReferenceConsumer = + type -> { + DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(type); + if (enumClass != null) { + eligibleEnums.add(enumClass.getType()); + } + }; + invoke.getCallSite().getMethodProto().forEachType(typeReferenceConsumer); + invoke + .getCallSite() + .getBootstrapArgs() + .forEach( + bootstrapArgument -> { + if (bootstrapArgument.isDexValueMethodHandle()) { + DexMethodHandle methodHandle = + bootstrapArgument.asDexValueMethodHandle().getValue(); + if (methodHandle.isMethodHandle()) { + DexMethod method = methodHandle.asMethod(); + DexProgramClass enumClass = + getEnumUnboxingCandidateOrNull(method.getHolderType()); + if (enumClass != null) { + markEnumAsUnboxable(Reason.INVALID_INVOKE_CUSTOM, enumClass); + } else { + method.getProto().forEachType(typeReferenceConsumer); + } + } else { + assert methodHandle.isFieldHandle(); + DexField field = methodHandle.asField(); + DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(field.getHolderType()); + if (enumClass != null) { + markEnumAsUnboxable(Reason.INVALID_INVOKE_CUSTOM, enumClass); + } else { + typeReferenceConsumer.accept(field.getType()); + } + } + } else if (bootstrapArgument.isDexValueMethodType()) { + DexProto proto = bootstrapArgument.asDexValueMethodType().getValue(); + proto.forEachType(typeReferenceConsumer); + } + }); + } + private void analyzeFieldInstruction( FieldInstruction fieldInstruction, Set<DexType> eligibleEnums, ProgramMethod context) { DexField field = fieldInstruction.getField();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java index 429bdae..bac0275 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
@@ -26,6 +26,7 @@ public static final Reason INVALID_INVOKE = new StringReason("INVALID_INVOKE"); public static final Reason INVALID_INVOKE_CLASSPATH = new StringReason("INVALID_INVOKE_CLASSPATH"); + public static final Reason INVALID_INVOKE_CUSTOM = new StringReason("INVALID_INVOKE_CUSTOM"); public static final Reason INVALID_INVOKE_ON_ARRAY = new StringReason("INVALID_INVOKE_ON_ARRAY"); public static final Reason IMPLICIT_UP_CAST_IN_RETURN = new StringReason("IMPLICIT_UP_CAST_IN_RETURN");