Lens rewrite const-method handles and types.
Fixes: b/235810300
Change-Id: I79832258f0ee78bdf765e49c12f2977a4f8422ff
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 285ebe5..8cc10c2 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
@@ -111,12 +111,25 @@
LensCodeRewriterUtils rewriter,
MethodVisitor visitor) {
Invoke.Type invokeType = Invoke.Type.fromCfOpcode(opcode, method, context, appView);
- MethodLookupResult lookup = graphLens.lookupMethod(method, context.getReference(), invokeType);
- DexMethod rewrittenMethod = lookup.getReference();
+ Invoke.Type rewrittenType;
+ DexMethod rewrittenMethod;
+ if (invokeType == Type.POLYMORPHIC) {
+ // The method is one of the java.lang.MethodHandle invokes.
+ // Only the argument signature (getProto()) is to be type rewritten.
+ rewrittenType = Type.POLYMORPHIC;
+ DexProto rewrittenProto = rewriter.rewriteProto(method.getProto());
+ rewrittenMethod =
+ dexItemFactory.createMethod(method.getHolderType(), rewrittenProto, method.getName());
+ } else {
+ MethodLookupResult lookup =
+ graphLens.lookupMethod(method, context.getReference(), invokeType);
+ rewrittenType = lookup.getType();
+ rewrittenMethod = lookup.getReference();
+ }
String owner = namingLens.lookupInternalName(rewrittenMethod.holder);
String name = namingLens.lookupName(rewrittenMethod).toString();
String desc = rewrittenMethod.proto.toDescriptorString(namingLens);
- visitor.visitMethodInsn(lookup.getType().getCfOpcode(), owner, name, desc, itf);
+ visitor.visitMethodInsn(rewrittenType.getCfOpcode(), owner, name, desc, itf);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
index e658265..8e9a2b0 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
@@ -124,7 +124,10 @@
LensCodeRewriterUtils rewriter) {
MethodLookupResult lookup =
graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC);
+ // The method is one of the java.lang.MethodHandle invokes.
+ // Only the argument (getProto()) signature is to be type rewritten.
assert lookup.getType() == Type.POLYMORPHIC;
+ assert getMethod() == lookup.getReference();
writeFirst(A, G, dest);
write16BitReference(lookup.getReference(), dest, mapping);
write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest);
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
index ace2725..94b043a 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
@@ -61,7 +61,10 @@
LensCodeRewriterUtils rewriter) {
MethodLookupResult lookup =
graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC);
+ // The method is one of the java.lang.MethodHandle invokes.
+ // Only the argument (getProto()) signature is to be type rewritten.
assert lookup.getType() == Type.POLYMORPHIC;
+ assert getMethod() == lookup.getReference();
writeFirst(AA, dest);
write16BitReference(lookup.getReference(), dest, mapping);
write16BitValue(CCCC, dest);
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 8859c3c..610a0c8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
@@ -326,10 +326,6 @@
.withNullableItem(m -> m.rewrittenTarget);
}
- public Handle toAsmHandle() {
- return toAsmHandle(NamingLens.getIdentityLens());
- }
-
public Handle toAsmHandle(NamingLens lens) {
String owner;
String name;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 2154c8c..207da48 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -10,6 +10,7 @@
import static com.android.tools.r8.ir.code.Opcodes.CHECK_CAST;
import static com.android.tools.r8.ir.code.Opcodes.CONST_CLASS;
import static com.android.tools.r8.ir.code.Opcodes.CONST_METHOD_HANDLE;
+import static com.android.tools.r8.ir.code.Opcodes.CONST_METHOD_TYPE;
import static com.android.tools.r8.ir.code.Opcodes.INIT_CLASS;
import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_GET;
import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_OF;
@@ -46,6 +47,7 @@
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.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.FieldLookupResult;
@@ -70,6 +72,7 @@
import com.android.tools.r8.ir.code.CheckCast;
import com.android.tools.r8.ir.code.ConstClass;
import com.android.tools.r8.ir.code.ConstMethodHandle;
+import com.android.tools.r8.ir.code.ConstMethodType;
import com.android.tools.r8.ir.code.FieldInstruction;
import com.android.tools.r8.ir.code.FieldPut;
import com.android.tools.r8.ir.code.IRCode;
@@ -85,6 +88,7 @@
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeMultiNewArray;
import com.android.tools.r8.ir.code.InvokeNewArray;
+import com.android.tools.r8.ir.code.InvokePolymorphic;
import com.android.tools.r8.ir.code.MoveException;
import com.android.tools.r8.ir.code.NewArrayEmpty;
import com.android.tools.r8.ir.code.NewInstance;
@@ -277,11 +281,18 @@
.computeIfAbsent()
.rewriteDexMethodHandle(handle, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, method);
if (newHandle != handle) {
- Value newOutValue = makeOutValue(current, code, graphLens, codeLens);
- iterator.replaceCurrentInstruction(new ConstMethodHandle(newOutValue, newHandle));
- if (newOutValue != null && newOutValue.getType() != current.getOutType()) {
- affectedPhis.addAll(newOutValue.uniquePhiUsers());
- }
+ iterator.replaceCurrentInstruction(
+ new ConstMethodHandle(current.outValue(), newHandle));
+ }
+ }
+ break;
+ case CONST_METHOD_TYPE:
+ {
+ ConstMethodType constType = current.asConstMethodType();
+ DexProto rewrittenProto = helper.computeIfAbsent().rewriteProto(constType.getValue());
+ if (constType.getValue() != rewrittenProto) {
+ iterator.replaceCurrentInstruction(
+ new ConstMethodType(constType.outValue(), rewrittenProto));
}
}
break;
@@ -298,9 +309,25 @@
}
break;
+ case INVOKE_POLYMORPHIC:
+ {
+ InvokePolymorphic invoke = current.asInvokePolymorphic();
+ // The invoked method is on java.lang.invoke.MethodHandle and always remains as is.
+ assert factory.polymorphicMethods.isPolymorphicInvoke(invoke.getInvokedMethod());
+ // Rewrite the signature of the handles actual target.
+ DexProto rewrittenProto = helper.computeIfAbsent().rewriteProto(invoke.getProto());
+ if (invoke.getProto() != rewrittenProto) {
+ iterator.replaceCurrentInstruction(
+ new InvokePolymorphic(
+ invoke.getInvokedMethod(),
+ rewrittenProto,
+ invoke.outValue(),
+ invoke.arguments()));
+ }
+ }
+ break;
case INVOKE_DIRECT:
case INVOKE_INTERFACE:
- case INVOKE_POLYMORPHIC:
case INVOKE_STATIC:
case INVOKE_SUPER:
case INVOKE_VIRTUAL:
diff --git a/src/test/java/com/android/tools/r8/cf/methodhandles/MethodHandleTest.java b/src/test/java/com/android/tools/r8/cf/methodhandles/MethodHandleTest.java
index 497e19f..423ffcd 100644
--- a/src/test/java/com/android/tools/r8/cf/methodhandles/MethodHandleTest.java
+++ b/src/test/java/com/android/tools/r8/cf/methodhandles/MethodHandleTest.java
@@ -126,8 +126,8 @@
divicMethod().invoke(i, 15, 'x');
assertEquals(42L, (long) dijicMethod().invoke(i, 16, 'x'));
constructorMethod().invoke(21);
- System.out.println(veType().parameterType(0).getName().lastIndexOf('.'));
- System.out.println(fType().returnType().getName().lastIndexOf('.'));
+ System.out.println(veType().parameterType(0).equals(E.class));
+ System.out.println(fType().returnType().equals(F.class));
} catch (Throwable e) {
throw new RuntimeException(e);
}
diff --git a/src/test/java/com/android/tools/r8/cf/methodhandles/MethodHandleTestRunner.java b/src/test/java/com/android/tools/r8/cf/methodhandles/MethodHandleTestRunner.java
index 1812854..4760c61 100644
--- a/src/test/java/com/android/tools/r8/cf/methodhandles/MethodHandleTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/methodhandles/MethodHandleTestRunner.java
@@ -5,10 +5,8 @@
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertThrows;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessages;
@@ -49,8 +47,8 @@
private String getExpected() {
return StringUtils.lines(
"C 42", "svi 1", "sji 2", "svic 3", "sjic 4", "vvi 5", "vji 6", "vvic 7", "vjic 8", "svi 9",
- "sji 10", "svic 11", "sjic 12", "dvi 13", "dji 14", "dvic 15", "djic 16", "C 21", "37",
- "37");
+ "sji 10", "svic 11", "sjic 12", "dvi 13", "dji 14", "dvic 15", "djic 16", "C 21", "true",
+ "true");
}
private final TestParameters parameters;
@@ -118,28 +116,34 @@
.addProgramClassFileData(getTransformedClasses())
.addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
.addNoVerticalClassMergingAnnotations();
+ // TODO(b/237750295): The CONSTANT case should not need rules as they are not reflective uses.
if (minifyMode == MinifyMode.MINIFY) {
builder
.enableProguardTestOptions()
.addKeepMainRule(MethodHandleTest.class)
.addKeepRules(
- // Prevent the second argument of C.svic(), C.sjic(), I.sjic() and I.svic() from
- // being removed although they are never used unused. This is needed since these
- // methods are accessed reflectively.
"-keep,allowobfuscation public class " + typeName(C.class) + " {",
+ " void <init>(int);",
+ " static void svi(int);",
+ " static long sji(int);",
" static void svic(int, char);",
" static long sjic(int, char);",
+ " void vvi(int);",
+ " long vji(int);",
+ " void vvic(int, char);",
+ " long vjic(int, char);",
"}",
"-keep,allowobfuscation public interface " + typeName(I.class) + " {",
- " static long sjic(int, char);",
+ " static void svi(int);",
+ " static long sji(int);",
" static void svic(int, char);",
+ " static long sjic(int, char);",
+ " void dvi(int);",
+ " long dji(int);",
+ " void dvic(int, char);",
+ " long djic(int, char);",
"}");
- // TODO(b/235810300): The compiler fails with assertion in AppInfoWithLiveness.
- if (lookupType == LookupType.CONSTANT && hasConstMethodCompileSupport()) {
- builder.allowDiagnosticMessages();
- assertThrows(CompilationFailedException.class, builder::compile);
- return;
- }
+
} else {
builder.noTreeShaking();
builder.noMinification();