Reland "Don't use accessors for lambdas to interface companion methods."
This reverts commit a4aa2f9bf90f60e878bc02b3a5ac67e6b1318eb0.
Change-Id: I036ef3468ff368d6c911bc502f4d6551ff4f8e73
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
index 71bc104..227270d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
@@ -28,6 +28,7 @@
INVOKE_DIRECT((short) 0x07),
INVOKE_INTERFACE((short) 0x08),
// Internal method handle needed by lambda desugaring.
+ // TODO(b/200254463): Remove this now that lambda desugaring is CF/CF.
INVOKE_SUPER((short) 0x09);
private final short value;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 9b2a145..2e9fcab 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -75,6 +75,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
if (!instruction.isInvoke()) {
return null;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BufferCovariantReturnTypeRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BufferCovariantReturnTypeRewriter.java
index ea1cd46..4d9ec0e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BufferCovariantReturnTypeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BufferCovariantReturnTypeRewriter.java
@@ -38,6 +38,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
if (!isInvokeCandidate(instruction)) {
return null;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
index 513a9d5..810812a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
@@ -40,6 +40,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory);
/**
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
index ada494f..5053f86 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.desugar;
import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
+import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ProgramMethod;
@@ -15,6 +16,7 @@
import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor;
import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
import com.android.tools.r8.utils.ThrowingConsumer;
+import java.util.Collection;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -56,6 +58,15 @@
MethodProcessingContext methodProcessingContext,
CfInstructionDesugaringEventConsumer eventConsumer);
+ /** Selective desugaring of a single invoke instruction assuming a given context. */
+ public abstract Collection<CfInstruction> desugarInstruction(
+ CfInstruction instruction,
+ FreshLocalProvider freshLocalProvider,
+ LocalStackAllocator localStackAllocator,
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ ProgramMethod context,
+ MethodProcessingContext methodProcessingContext);
+
public boolean isEmpty() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
index 027b27c..ef793c4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.desugar;
+import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
@@ -13,6 +14,7 @@
import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor;
import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
import com.android.tools.r8.utils.ThrowingConsumer;
+import java.util.Collection;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -47,6 +49,18 @@
}
@Override
+ public Collection<CfInstruction> desugarInstruction(
+ CfInstruction instruction,
+ FreshLocalProvider freshLocalProvider,
+ LocalStackAllocator localStackAllocator,
+ CfInstructionDesugaringEventConsumer eventConsumer,
+ ProgramMethod context,
+ MethodProcessingContext methodProcessingContext) {
+ // Nothing to desugar.
+ return null;
+ }
+
+ @Override
public boolean isEmpty() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InvokeToPrivateRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InvokeToPrivateRewriter.java
index 7fd31a8..65f23dc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InvokeToPrivateRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InvokeToPrivateRewriter.java
@@ -35,6 +35,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
if (!instruction.isInvokeVirtual() && !instruction.isInvokeInterface()) {
return null;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index afedd24..2c815a1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -33,6 +33,7 @@
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.desugar.lambda.ForcefullyMovedLambdaMethodConsumer;
import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring.DesugarInvoke;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.synthesis.SyntheticProgramClassBuilder;
@@ -40,6 +41,7 @@
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
+import org.objectweb.asm.Opcodes;
/**
* Represents lambda class generated for a lambda descriptor in context of lambda instantiation
@@ -81,7 +83,8 @@
AppView<?> appView,
LambdaInstructionDesugaring desugaring,
ProgramMethod accessedFrom,
- LambdaDescriptor descriptor) {
+ LambdaDescriptor descriptor,
+ DesugarInvoke desugarInvoke) {
assert desugaring != null;
assert descriptor != null;
this.type = builder.getType();
@@ -105,7 +108,7 @@
!stateless ? null : factory.createField(type, type, factory.lambdaInstanceFieldName);
// Synthesize the program class once all fields are set.
- synthesizeLambdaClass(builder);
+ synthesizeLambdaClass(builder, desugarInvoke);
}
public final DexProgramClass getLambdaProgramClass() {
@@ -124,12 +127,13 @@
this.clazz = clazz;
}
- private void synthesizeLambdaClass(SyntheticProgramClassBuilder builder) {
+ private void synthesizeLambdaClass(
+ SyntheticProgramClassBuilder builder, DesugarInvoke desugarInvoke) {
builder.setInterfaces(descriptor.interfaces);
synthesizeStaticFields(builder);
synthesizeInstanceFields(builder);
synthesizeDirectMethods(builder);
- synthesizeVirtualMethods(builder);
+ synthesizeVirtualMethods(builder, desugarInvoke);
}
final DexField getCaptureField(int index) {
@@ -146,7 +150,8 @@
}
// Synthesize virtual methods.
- private void synthesizeVirtualMethods(SyntheticProgramClassBuilder builder) {
+ private void synthesizeVirtualMethods(
+ SyntheticProgramClassBuilder builder, DesugarInvoke desugarInvoke) {
DexMethod mainMethod =
appView.dexItemFactory().createMethod(type, descriptor.erasedProto, descriptor.name);
@@ -159,7 +164,7 @@
.setAccessFlags(
MethodAccessFlags.fromSharedAccessFlags(
Constants.ACC_PUBLIC | Constants.ACC_FINAL, false))
- .setCode(LambdaMainMethodSourceCode.build(this, mainMethod))
+ .setCode(LambdaMainMethodSourceCode.build(this, mainMethod, desugarInvoke))
// The api level is computed when tracing.
.disableAndroidApiLevelCheck()
.build());
@@ -261,6 +266,21 @@
}
}
+ public static int getAsmOpcodeForInvokeType(MethodHandleType type) {
+ switch (type) {
+ case INVOKE_INTERFACE:
+ return Opcodes.INVOKEINTERFACE;
+ case INVOKE_STATIC:
+ return Opcodes.INVOKESTATIC;
+ case INVOKE_DIRECT:
+ return Opcodes.INVOKESPECIAL;
+ case INVOKE_INSTANCE:
+ return Opcodes.INVOKEVIRTUAL;
+ default:
+ throw new Unreachable("Unexpected method handle type: " + type);
+ }
+ }
+
// Creates a delegation target for this particular lambda class. Note that we
// should always be able to create targets for the lambdas we support.
private Target createTarget(ProgramMethod accessedFrom) {
@@ -287,12 +307,22 @@
}
private boolean doesNotNeedAccessor(ProgramMethod accessedFrom) {
- return canAccessModifyLambdaImplMethod() || !descriptor.needsAccessor(accessedFrom);
+ return canAccessModifyLambdaImplMethod()
+ || isPrivateOrStaticInterfaceMethodInvokeThatWillBeDesugared()
+ || !descriptor.needsAccessor(accessedFrom);
+ }
+
+ private boolean isPrivateOrStaticInterfaceMethodInvokeThatWillBeDesugared() {
+ return appView.options().isInterfaceMethodDesugaringEnabled()
+ && descriptor.implHandle.isInterface
+ && (descriptor.implHandle.type.isInvokeDirect()
+ || descriptor.implHandle.type.isInvokeStatic());
}
private boolean canAccessModifyLambdaImplMethod() {
MethodHandleType invokeType = descriptor.implHandle.type;
return appView.options().canAccessModifyLambdaImplementationMethods(appView)
+ && !isPrivateOrStaticInterfaceMethodInvokeThatWillBeDesugared()
&& (invokeType.isInvokeDirect() || invokeType.isInvokeStatic())
&& descriptor.delegatesToLambdaImplMethod(appView.dexItemFactory())
&& !desugaring.isDirectTargetedLambdaImplementationMethod(descriptor.implHandle);
@@ -328,7 +358,7 @@
assert implHandle.type.isInvokeDirect();
// If the lambda$ method is an instance-private method on an interface we convert it into a
- // public static method as it will be placed on the companion class.
+ // public static method so it is accessible.
if (appView.definitionFor(implMethod.holder).isInterface()) {
DexProto implProto = implMethod.proto;
DexType[] implParams = implProto.parameters.values;
@@ -367,7 +397,11 @@
if (doesNotNeedAccessor(accessedFrom)) {
return new NoAccessorMethodTarget(
- descriptor.implHandle.asMethod(), Type.VIRTUAL, descriptor.implHandle.isInterface);
+ descriptor.implHandle.asMethod(),
+ descriptor.implHandle.type.isInvokeDirect()
+ ? Type.DIRECT
+ : descriptor.implHandle.type.isInvokeStatic() ? Type.STATIC : Type.VIRTUAL,
+ descriptor.implHandle.isInterface);
}
// We need to generate an accessor method in `accessedFrom` class/interface
// for accessing the original instance impl-method. Note that impl-method's
@@ -523,7 +557,7 @@
}
// Used for targeting methods referenced directly without creating accessors.
- private static final class NoAccessorMethodTarget extends Target {
+ public static final class NoAccessorMethodTarget extends Target {
NoAccessorMethodTarget(DexMethod method, Type invokeType, boolean isInterface) {
super(method, invokeType, isInterface);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
index e0a9c07..acfee7b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
@@ -25,13 +25,18 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.Invoke;
+import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.desugar.LambdaClass.InvalidLambdaImplTarget;
+import com.android.tools.r8.ir.desugar.LambdaClass.NoAccessorMethodTarget;
+import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring.DesugarInvoke;
+import com.android.tools.r8.utils.IntBox;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.Lists;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import org.objectweb.asm.Opcodes;
@@ -166,7 +171,8 @@
}
}
- public static CfCode build(LambdaClass lambda, DexMethod mainMethod) {
+ public static CfCode build(
+ LambdaClass lambda, DexMethod mainMethod, DesugarInvoke desugarInvoke) {
DexItemFactory factory = lambda.appView.dexItemFactory();
LambdaClass.Target target = lambda.target;
if (target instanceof InvalidLambdaImplTarget) {
@@ -184,11 +190,13 @@
// Only constructor call should use direct invoke type since super
// and private methods require accessor methods.
- boolean constructorTarget = target.invokeType == Invoke.Type.DIRECT;
- assert !constructorTarget || methodToCall.name == factory.constructorMethodName;
+ boolean constructorTarget = methodToCall.name == factory.constructorMethodName;
+ assert !constructorTarget || target.invokeType == Type.DIRECT;
boolean targetWithReceiver =
- target.invokeType == Invoke.Type.VIRTUAL || target.invokeType == Invoke.Type.INTERFACE;
+ target.invokeType == Invoke.Type.VIRTUAL
+ || target.invokeType == Invoke.Type.INTERFACE
+ || (target.invokeType == Type.DIRECT && !constructorTarget);
List<DexType> implReceiverAndArgs = new ArrayList<>();
if (targetWithReceiver) {
implReceiverAndArgs.add(methodToCall.holder);
@@ -241,8 +249,24 @@
erasedParams[i], enforcedParams[i], expectedParamType, instructions, factory);
}
- instructions.add(
- new CfInvoke(target.invokeType.getCfOpcode(), methodToCall, target.isInterface()));
+ CfInvoke invoke =
+ new CfInvoke(target.invokeType.getCfOpcode(), methodToCall, target.isInterface());
+ if (target instanceof NoAccessorMethodTarget) {
+ IntBox locals = new IntBox();
+ IntBox stack = new IntBox();
+ Collection<CfInstruction> is =
+ desugarInvoke.desugarInvoke(invoke, locals::getAndIncrement, stack::getAndIncrement);
+ if (is != null) {
+ instructions.addAll(is);
+ maxLocals += locals.get();
+ maxStack += stack.get();
+ } else {
+ instructions.add(invoke);
+ }
+ } else {
+ instructions.add(invoke);
+ }
+
DexType methodToCallReturnType = methodToCall.getReturnType();
if (!methodToCallReturnType.isVoidType()) {
maxStack =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index da0a96a..596f4cc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -254,7 +254,8 @@
return true;
}
- private Collection<CfInstruction> desugarInstruction(
+ @Override
+ public Collection<CfInstruction> desugarInstruction(
CfInstruction instruction,
FreshLocalProvider freshLocalProvider,
LocalStackAllocator localStackAllocator,
@@ -273,6 +274,7 @@
eventConsumer,
context,
methodProcessingContext,
+ this,
appView.dexItemFactory());
if (replacement != null) {
assert desugaring.needsDesugaring(instruction, 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 8ef2e18..1d55e7e 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
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
@@ -46,6 +47,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
if (instruction.isConstDynamic()) {
return desugarConstDynamicInstruction(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
index 4634977..2b6c9d4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
@@ -30,6 +30,7 @@
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
@@ -97,6 +98,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
if (needsDesugaring(instruction, context)) {
assert instruction.isInvoke();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java
index 73d7f8f..5c6d6c1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
@@ -69,6 +70,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
InvokeRetargetingResult invokeRetargetingResult = computeNewInvokeTarget(instruction, context);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
index 28b6981..5c89290 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.DesugarDescription;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
@@ -47,6 +48,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
return computeDesugarDescription(instruction)
.desugarInstruction(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java
index dfb797c..428bdd0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
@@ -73,6 +74,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
if (instruction.isInvokeSpecial()) {
return desugarInvokeInstruction(instruction.asInvoke(), eventConsumer, context);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index 87e0d65..db52706 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -30,6 +30,7 @@
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.DesugarDescription;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
@@ -248,6 +249,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
assert !isSyntheticMethodThatShouldNotBeDoubleProcessed(context);
return computeDescription(instruction, context)
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
index 71010c3..206c276 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LambdaClass;
@@ -75,6 +76,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
if (instruction.isInvokeDynamic()) {
return desugarInvokeDynamicInstruction(
@@ -83,19 +85,36 @@
localStackAllocator,
eventConsumer,
context,
- methodProcessingContext);
+ methodProcessingContext,
+ (invoke, localProvider, stackAllocator) ->
+ desugaringCollection.desugarInstruction(
+ invoke,
+ localProvider,
+ stackAllocator,
+ eventConsumer,
+ context,
+ methodProcessingContext));
}
return null;
}
+ public interface DesugarInvoke {
+ Collection<CfInstruction> desugarInvoke(
+ CfInvoke invoke,
+ FreshLocalProvider freshLocalProvider,
+ LocalStackAllocator localStackAllocator);
+ }
+
private Collection<CfInstruction> desugarInvokeDynamicInstruction(
CfInvokeDynamic invoke,
FreshLocalProvider freshLocalProvider,
LocalStackAllocator localStackAllocator,
LambdaDesugaringEventConsumer eventConsumer,
ProgramMethod context,
- MethodProcessingContext methodProcessingContext) {
- LambdaClass lambdaClass = createLambdaClass(invoke, context, methodProcessingContext);
+ MethodProcessingContext methodProcessingContext,
+ DesugarInvoke desugarInvoke) {
+ LambdaClass lambdaClass =
+ createLambdaClass(invoke, context, methodProcessingContext, desugarInvoke);
if (lambdaClass == null) {
return null;
}
@@ -134,7 +153,8 @@
private LambdaClass createLambdaClass(
CfInvokeDynamic invoke,
ProgramMethod context,
- MethodProcessingContext methodProcessingContext) {
+ MethodProcessingContext methodProcessingContext,
+ DesugarInvoke desugarInvoke) {
LambdaDescriptor descriptor =
LambdaDescriptor.tryInfer(invoke.getCallSite(), appView.appInfoForDesugaring(), context);
if (descriptor == null) {
@@ -149,7 +169,10 @@
SyntheticNaming.SyntheticKind.LAMBDA,
methodProcessingContext.createUniqueContext(),
appView,
- builder -> box.set(new LambdaClass(builder, appView, this, context, descriptor)));
+ builder ->
+ box.set(
+ new LambdaClass(
+ builder, appView, this, context, descriptor, desugarInvoke)));
// Immediately set the actual program class on the lambda.
LambdaClass lambdaClass = box.get();
lambdaClass.setClass(clazz);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
index 87adb53..f9ca2e9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
@@ -31,6 +31,7 @@
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
@@ -268,6 +269,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
if (instruction.isFieldInstruction()) {
return desugarFieldInstruction(instruction.asFieldInstruction(), context, eventConsumer);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java
index babb6f7..f508ca6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java
@@ -40,6 +40,7 @@
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaring;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
@@ -167,6 +168,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
assert !instruction.isInitClass();
if (!needsDesugaring(instruction, context)) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/stringconcat/StringConcatInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/stringconcat/StringConcatInstructionDesugaring.java
index 607b088..065fc4c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/stringconcat/StringConcatInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/stringconcat/StringConcatInstructionDesugaring.java
@@ -29,6 +29,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
@@ -76,6 +77,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
if (instruction.isInvokeDynamic()) {
// We are interested in bootstrap methods StringConcatFactory::makeConcat
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java
index ee71bc0..716b6e2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
@@ -57,6 +58,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
+ CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
if (!instruction.isInvoke()) {
return null;
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaPrivateInstanceInterfaceMethodWithNonLambdaCallSiteTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaPrivateInstanceInterfaceMethodWithNonLambdaCallSiteTest.java
index 7d0b2fa..6961fe9 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaPrivateInstanceInterfaceMethodWithNonLambdaCallSiteTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaPrivateInstanceInterfaceMethodWithNonLambdaCallSiteTest.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.lambdas;
+import static org.junit.Assert.assertFalse;
+
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -41,7 +43,21 @@
.addProgramClasses(Main.class, A.class, FunctionalInterface.class)
.addProgramClassFileData(getProgramClassFileData())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("Hello world!", "Hello world!");
+ .assertSuccessWithOutputLines("Hello world!", "Hello world!")
+ .inspect(
+ inspector -> {
+ if (parameters.isDexRuntime()
+ && !parameters.canUseDefaultAndStaticInterfaceMethods()) {
+ inspector
+ .clazz(I.class)
+ .toCompanionClass()
+ .forAllMethods(
+ m ->
+ // We don't expect any synthetic accessors to be needed for the private
+ // interface method.
+ assertFalse("Unexpected synthetic method: " + m, m.isSynthetic()));
+ }
+ });
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaWithPrivateInterfaceInvokeTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaWithPrivateInterfaceInvokeTest.java
new file mode 100644
index 0000000..d66b1d2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaWithPrivateInterfaceInvokeTest.java
@@ -0,0 +1,114 @@
+// Copyright (c) 2021, 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.desugar.lambdas;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class LambdaWithPrivateInterfaceInvokeTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("Hello world");
+
+ private final TestParameters parameters;
+ private final boolean useInvokeSpecial;
+
+ @Parameterized.Parameters(name = "{0}, invokespecial:{1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
+ }
+
+ public LambdaWithPrivateInterfaceInvokeTest(TestParameters parameters, boolean useInvokeSpecial) {
+ this.parameters = parameters;
+ this.useInvokeSpecial = useInvokeSpecial;
+ }
+
+ @Test
+ public void testReference() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(TestClass.class, MyFun.class, A.class)
+ .addProgramClassFileData(getTransformForI())
+ .run(parameters.getRuntime(), TestClass.class)
+ // On JDK 8 and 9 the VM will fail if not targeting with invoke special.
+ .applyIf(
+ !useInvokeSpecial
+ && parameters.isCfRuntime()
+ && parameters.asCfRuntime().isOlderThan(CfVm.JDK11),
+ r -> r.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class),
+ r -> r.assertSuccessWithOutput(EXPECTED));
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(TestClass.class, MyFun.class, A.class)
+ .addProgramClassFileData(getTransformForI())
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ private byte[] getTransformForI() throws Exception {
+ return transformer(I.class)
+ .setPrivate(I.class.getDeclaredMethod("bar"))
+ .transformMethodInsnInMethod(
+ "lambda$foo$0",
+ (opcode, owner, name, descriptor, isInterface, visitor) -> {
+ if (name.equals("bar")) {
+ assertEquals(Opcodes.INVOKEINTERFACE, opcode);
+ visitor.visitMethodInsn(
+ useInvokeSpecial ? Opcodes.INVOKESPECIAL : Opcodes.INVOKEINTERFACE,
+ owner,
+ name,
+ descriptor,
+ isInterface);
+ } else {
+ visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+ })
+ .transform();
+ }
+
+ interface I {
+ /* private */ default String bar() {
+ return "Hello world";
+ }
+
+ default void foo() {
+ TestClass.run(
+ () -> {
+ System.out.println(bar());
+ });
+ }
+ }
+
+ interface MyFun {
+ void run();
+ }
+
+ static class A implements I {}
+
+ static class TestClass {
+
+ public static void run(MyFun fn) {
+ fn.run();
+ }
+
+ public static void main(String[] args) {
+ new A().foo();
+ }
+ }
+}