Refactor CONSTANT_Dynamic desugaring when throwing
Bug: 178172809
Change-Id: I902a341198ca4f0046b7806b55b8eadfd95aaec5
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
index 2933e4d..492d428 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
@@ -3,8 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.desugar.constantdynamic;
+import static com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicClass.Behaviour.CACHE_CONSTANT;
+import static com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicClass.Behaviour.THROW_ICCE;
+import static com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicClass.Behaviour.THROW_NSME;
import static org.objectweb.asm.Opcodes.GETSTATIC;
-import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
import static org.objectweb.asm.Opcodes.PUTSTATIC;
@@ -24,13 +26,13 @@
import com.android.tools.r8.cf.code.CfLabel;
import com.android.tools.r8.cf.code.CfLoad;
import com.android.tools.r8.cf.code.CfMonitor;
-import com.android.tools.r8.cf.code.CfNew;
import com.android.tools.r8.cf.code.CfReturn;
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexEncodedField;
@@ -40,7 +42,6 @@
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.DexType;
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodResolutionResult;
@@ -49,24 +50,38 @@
import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.Monitor;
import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.desugar.FreshLocalProvider;
+import com.android.tools.r8.ir.desugar.LocalStackAllocator;
+import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations;
+import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.MethodSynthesizerConsumer;
+import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.UtilityMethodForCodeOptimizations;
import com.android.tools.r8.synthesis.SyntheticProgramClassBuilder;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.collections.ImmutableDeque;
import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
import com.google.common.collect.ImmutableList;
+import java.util.Collection;
import java.util.List;
+import org.objectweb.asm.Opcodes;
public class ConstantDynamicClass {
+ enum Behaviour {
+ CACHE_CONSTANT,
+ THROW_NSME,
+ THROW_ICCE
+ }
+
public static final String INITIALIZED_FIELD_NAME = "INITIALIZED";
public static final String CONST_FIELD_NAME = "CONST";
- final AppView<?> appView;
- final ConstantDynamicInstructionDesugaring desugaring;
- private final DexType accessedFrom;
- public ConstantDynamicReference reference;
+ private final AppView<?> appView;
+ private final ConstantDynamicInstructionDesugaring desugaring;
+ private final ProgramMethod context;
+ public final ConstantDynamicReference reference;
public final DexField initializedValueField;
public final DexField constantValueField;
- final DexMethod getConstMethod;
+ private final DexMethod getConstMethod;
+ private final Behaviour behaviour;
// Considered final but is set after due to circularity in allocation.
private DexProgramClass clazz = null;
@@ -75,12 +90,12 @@
SyntheticProgramClassBuilder builder,
AppView<?> appView,
ConstantDynamicInstructionDesugaring desugaring,
- ProgramMethod accessedFrom,
+ ProgramMethod context,
CfConstDynamic constantDynamic) {
DexItemFactory factory = appView.dexItemFactory();
this.appView = appView;
this.desugaring = desugaring;
- this.accessedFrom = accessedFrom.getHolderType();
+ this.context = context;
this.reference = constantDynamic.getReference();
this.constantValueField =
factory.createField(
@@ -94,7 +109,57 @@
factory.createProto(constantDynamic.getType()),
factory.createString("get"));
- synthesizeConstantDynamicClass(builder);
+ DexMethodHandle bootstrapMethodHandle = reference.getBootstrapMethod();
+ DexMethod bootstrapMethodReference = bootstrapMethodHandle.asMethod();
+ MethodResolutionResult resolution =
+ appView
+ .appInfoForDesugaring()
+ .resolveMethod(bootstrapMethodReference, bootstrapMethodHandle.isInterface);
+ if (resolution.isSingleResolution()
+ && resolution.asSingleResolution().getResolvedMethod().isStatic()) {
+ // Ensure that the bootstrap method is accessible from the generated class.
+ SingleResolutionResult result = resolution.asSingleResolution();
+ MethodAccessFlags flags = result.getResolvedMethod().getAccessFlags();
+ flags.unsetPrivate();
+ flags.setPublic();
+ behaviour = CACHE_CONSTANT;
+ synthesizeConstantDynamicClass(builder);
+ } else {
+ // Unconditionally throw as the RI.
+ behaviour = resolution.isFailedResolution() ? THROW_NSME : THROW_ICCE;
+ }
+ }
+
+ public Collection<CfInstruction> desugarConstDynamicInstruction(
+ CfConstDynamic invoke,
+ FreshLocalProvider freshLocalProvider,
+ LocalStackAllocator localStackAllocator,
+ ConstantDynamicDesugaringEventConsumer eventConsumer,
+ ProgramMethod context,
+ MethodProcessingContext methodProcessingContext) {
+ assert invoke.getReference().equals(reference);
+ if (behaviour == CACHE_CONSTANT) {
+ return ImmutableList.of(new CfInvoke(Opcodes.INVOKESTATIC, getConstMethod, false));
+ }
+ return desugarToThrow(
+ behaviour == THROW_NSME
+ ? UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod
+ : UtilityMethodsForCodeOptimizations::synthesizeThrowIncompatibleClassChangeErrorMethod,
+ eventConsumer,
+ context,
+ methodProcessingContext);
+ }
+
+ private Collection<CfInstruction> desugarToThrow(
+ MethodSynthesizerConsumer methodSynthesizerConsumer,
+ ConstantDynamicDesugaringEventConsumer eventConsumer,
+ ProgramMethod context,
+ MethodProcessingContext methodProcessingContext) {
+ UtilityMethodForCodeOptimizations throwMethod =
+ methodSynthesizerConsumer.synthesizeMethod(appView, methodProcessingContext);
+ ProgramMethod throwProgramMethod = throwMethod.uncheckedGetMethod();
+ eventConsumer.acceptThrowMethod(throwProgramMethod, context);
+ return ImmutableList.of(new CfInvoke(INVOKESTATIC, throwProgramMethod.getReference(), false));
}
/*
@@ -167,30 +232,6 @@
private CfCode generateGetterCode(SyntheticProgramClassBuilder builder) {
// TODO(b/178172809): Use MethodHandle.invokeWithArguments if supported.
- DexMethodHandle bootstrapMethodHandle = reference.getBootstrapMethod();
- DexMethod bootstrapMethodReference = bootstrapMethodHandle.asMethod();
- MethodResolutionResult resolution =
- appView
- .appInfoForDesugaring()
- .resolveMethod(bootstrapMethodReference, bootstrapMethodHandle.isInterface);
- if ((resolution.isSingleResolution()
- && resolution.asSingleResolution().getResolvedMethod().isStatic())
- || resolution.isFailedResolution()) {
- if (resolution.isSingleResolution()) {
- // Ensure that the bootstrap method is accessible from the generated class.
- SingleResolutionResult result = resolution.asSingleResolution();
- MethodAccessFlags flags = result.getResolvedMethod().getAccessFlags();
- flags.unsetPrivate();
- flags.setPublic();
- }
- return generateGetterCodeInvokingBootstrapMethod(builder);
- } else {
- // Unconditionally throw ICCE as the RI.
- return generateGetterCodeThrowingICCE(builder);
- }
- }
-
- private CfCode generateGetterCodeInvokingBootstrapMethod(SyntheticProgramClassBuilder builder) {
int maxStack = 3;
int maxLocals = 2;
ImmutableList<CfCode.LocalVariableInfo> localVariables = ImmutableList.of();
@@ -272,33 +313,6 @@
localVariables);
}
- private CfCode generateGetterCodeThrowingICCE(SyntheticProgramClassBuilder builder) {
- int maxStack = 2;
- int maxLocals = 0;
- ImmutableList<CfTryCatch> tryCatchRanges = ImmutableList.of();
- ImmutableList<CfCode.LocalVariableInfo> localVariables = ImmutableList.of();
- ImmutableList.Builder<CfInstruction> instructions = ImmutableList.builder();
- DexItemFactory factory = builder.getFactory();
- instructions.add(new CfNew(factory.icceType));
- instructions.add(new CfStackInstruction(Opcode.Dup));
- instructions.add(
- new CfInvoke(
- INVOKESPECIAL,
- factory.createMethod(
- factory.icceType,
- factory.createProto(factory.voidType),
- factory.constructorMethodName),
- false));
- instructions.add(new CfThrow());
- return new CfCode(
- builder.getType(),
- maxStack,
- maxLocals,
- instructions.build(),
- tryCatchRanges,
- localVariables);
- }
-
public final DexProgramClass getConstantDynamicProgramClass() {
assert clazz != null;
return clazz;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicDesugaringEventConsumer.java
index 3c0efd7..1d2dcf6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicDesugaringEventConsumer.java
@@ -8,4 +8,6 @@
public interface ConstantDynamicDesugaringEventConsumer {
void acceptConstantDynamicClass(ConstantDynamicClass lambdaClass, ProgramMethod context);
+
+ void acceptThrowMethod(ProgramMethod method, ProgramMethod context);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicInstructionDesugaring.java
index a01fdd2..8ef2e18 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicInstructionDesugaring.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.code.CfConstDynamic;
import com.android.tools.r8.cf.code.CfInstruction;
-import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
@@ -19,12 +18,10 @@
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.utils.Box;
-import com.google.common.collect.ImmutableList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-import org.objectweb.asm.Opcodes;
public class ConstantDynamicInstructionDesugaring implements CfInstructionDesugaring {
@@ -71,8 +68,13 @@
MethodProcessingContext methodProcessingContext) {
ConstantDynamicClass constantDynamicClass =
ensureConstantDynamicClass(invoke, context, methodProcessingContext, eventConsumer);
- return ImmutableList.of(
- new CfInvoke(Opcodes.INVOKESTATIC, constantDynamicClass.getConstMethod, false));
+ return constantDynamicClass.desugarConstDynamicInstruction(
+ invoke,
+ freshLocalProvider,
+ localStackAllocator,
+ eventConsumer,
+ context,
+ methodProcessingContext);
}
// Creates a class corresponding to the constant dynamic symbolic reference and context.
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java
index 12ee318..cdf9723 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java
@@ -88,11 +88,6 @@
.addProgramClassFileData(getTransformedClasses())
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(A.class)
- // TODO(b/198142613): There should not be a warnings on class references which are
- // desugared away.
- .applyIf(
- parameters.getApiLevel().isLessThan(AndroidApiLevel.O),
- b -> b.addDontWarn("java.lang.invoke.MethodHandles$Lookup"))
// TODO(b/198142625): Support CONSTANT_Dynamic output for class files.
.applyIf(
parameters.isCfRuntime(),