Removing lambda deserialization methods in desugaring.
Lambda deserialization methods generated by RI compiler
are not used in desugared code. Removing them.
Bug:62168701
BUG=
Change-Id: I8056cbc4e5b0f761dfa3fa0db3e93629046c6b22
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 22ce470..7aef78c 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -155,22 +155,37 @@
}
}
+ private void removeLambdaDeserializationMethods() {
+ if (lambdaRewriter != null) {
+ lambdaRewriter.removeLambdaDeserializationMethods(application.classes());
+ }
+ }
+
+ private void synthesizeLambdaClasses(Builder builder) {
+ if (lambdaRewriter != null) {
+ lambdaRewriter.adjustAccessibility(builder);
+ lambdaRewriter.synthesizeLambdaClasses(builder);
+ }
+ }
+
+ private void desugarInterfaceMethods(
+ Builder builder, InterfaceMethodRewriter.Flavor includeAllResources) {
+ if (interfaceMethodRewriter != null) {
+ interfaceMethodRewriter.desugarInterfaceMethods(builder, includeAllResources);
+ }
+ }
+
public DexApplication convertToDex() {
+ removeLambdaDeserializationMethods();
+
convertClassesToDex(application.classes());
// Build a new application with jumbo string info,
Builder builder = new Builder(application);
builder.setHighestSortingString(highestSortingString);
- // Lambda rewriter
- if (lambdaRewriter != null) {
- lambdaRewriter.adjustAccessibility(builder);
- lambdaRewriter.synthesizeLambdaClasses(builder);
- }
-
- if (interfaceMethodRewriter != null) {
- interfaceMethodRewriter.desugarInterfaceMethods(builder, ExcludeDexResources);
- }
+ synthesizeLambdaClasses(builder);
+ desugarInterfaceMethods(builder, ExcludeDexResources);
return builder.build();
}
@@ -207,6 +222,8 @@
}
public DexApplication optimize(ExecutorService executorService) throws ExecutionException {
+ removeLambdaDeserializationMethods();
+
timing.begin("Build call graph");
callGraph = CallGraph.build(application, appInfo.withSubtyping(), graphLense);
timing.end();
@@ -265,15 +282,8 @@
}
}
- // Lambda rewriter.
- if (lambdaRewriter != null) {
- lambdaRewriter.adjustAccessibility(builder);
- lambdaRewriter.synthesizeLambdaClasses(builder);
- }
-
- if (interfaceMethodRewriter != null) {
- interfaceMethodRewriter.desugarInterfaceMethods(builder, IncludeAllResources);
- }
+ synthesizeLambdaClasses(builder);
+ desugarInterfaceMethods(builder, IncludeAllResources);
if (outliner != null) {
timing.begin("IR conversion phase 2");
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
index 5644096..87241cf 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
@@ -46,9 +46,11 @@
private static final String METHODHANDLE_TYPE_DESCR = "Ljava/lang/invoke/MethodHandle;";
private static final String OBJECT_ARRAY_TYPE_DESCR = "[Ljava/lang/Object;";
private static final String SERIALIZABLE_TYPE_DESCR = "Ljava/io/Serializable;";
+ private static final String SERIALIZED_LAMBDA_TYPE_DESCR = "Ljava/lang/invoke/SerializedLambda;";
private static final String METAFACTORY_METHOD_NAME = "metafactory";
private static final String METAFACTORY_ALT_METHOD_NAME = "altMetafactory";
+ private static final String DESERIALIZE_LAMBDA_METHOD_NAME = "$deserializeLambda$";
static final String LAMBDA_CLASS_NAME_PREFIX = "-$$Lambda$";
static final String EXPECTED_LAMBDA_METHOD_PREFIX = "lambda$";
@@ -68,6 +70,9 @@
final DexString classConstructorName;
final DexString instanceFieldName;
+ final DexString deserializeLambdaMethodName;
+ final DexProto deserializeLambdaMethodProto;
+
// Maps call sites seen so far to inferred lambda descriptor. It is intended
// to help avoid re-matching call sites we already seen. Note that same call
// site may match one or several lambda classes.
@@ -116,6 +121,10 @@
this.classConstructorName = factory.createString(Constants.CLASS_INITIALIZER_NAME);
this.instanceFieldName = factory.createString(LAMBDA_INSTANCE_FIELD_NAME);
this.serializableType = factory.createType(SERIALIZABLE_TYPE_DESCR);
+
+ this.deserializeLambdaMethodName = factory.createString(DESERIALIZE_LAMBDA_METHOD_NAME);
+ this.deserializeLambdaMethodProto = factory.createProto(
+ factory.objectType, new DexType[] { factory.createType(SERIALIZED_LAMBDA_TYPE_DESCR) });
}
/**
@@ -151,6 +160,35 @@
}
}
+ /** Remove lambda deserialization methods. */
+ public void removeLambdaDeserializationMethods(Iterable<DexProgramClass> classes) {
+ for (DexProgramClass clazz : classes) {
+ // Search for a lambda deserialization method and remove it if found.
+ DexEncodedMethod[] directMethods = clazz.directMethods;
+ if (directMethods != null) {
+ int methodCount = directMethods.length;
+ for (int i = 0; i < methodCount; i++) {
+ DexEncodedMethod encoded = directMethods[i];
+ DexMethod method = encoded.method;
+ if (method.name == deserializeLambdaMethodName &&
+ method.proto == deserializeLambdaMethodProto) {
+ assert encoded.accessFlags.isStatic();
+ assert encoded.accessFlags.isPrivate();
+ assert encoded.accessFlags.isSynthetic();
+
+ DexEncodedMethod[] newMethods = new DexEncodedMethod[methodCount - 1];
+ System.arraycopy(directMethods, 0, newMethods, 0, i);
+ System.arraycopy(directMethods, i + 1, newMethods, i, methodCount - i - 1);
+ clazz.directMethods = newMethods;
+
+ // We assume there is only one such method in the class.
+ break;
+ }
+ }
+ }
+ }
+ }
+
/**
* Adjust accessibility of referenced application symbols or
* creates necessary accessors.
diff --git a/src/test/examplesAndroidO/lambdadesugaringnplus/LambdasWithStaticAndDefaultMethods.java b/src/test/examplesAndroidO/lambdadesugaringnplus/LambdasWithStaticAndDefaultMethods.java
index d2e738d..8a1119a 100644
--- a/src/test/examplesAndroidO/lambdadesugaringnplus/LambdasWithStaticAndDefaultMethods.java
+++ b/src/test/examplesAndroidO/lambdadesugaringnplus/LambdasWithStaticAndDefaultMethods.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package lambdadesugaringnplus;
+import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -296,6 +297,23 @@
}
}
+ static class B62168701 {
+ interface I extends Serializable {
+ String getValue();
+ }
+
+ interface J {
+ static void dump() {
+ I i = () -> "B62168701 -- OK";
+ System.out.println(i.getValue());
+ }
+ }
+
+ static void test() {
+ J.dump();
+ }
+ }
+
static void z(Z p) {
System.out.println(p.foo(null));
}
@@ -401,5 +419,6 @@
B38306708.test();
B38308515.test();
B38302860.test();
+ B62168701.test();
}
}
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
index 978f9de..a5e944a 100644
--- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
@@ -5,6 +5,8 @@
package com.android.tools.r8;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.errors.InternalCompilerError;
+import com.android.tools.r8.errors.Unimplemented;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -86,8 +88,10 @@
D8Command command = builder.setOutputPath(out).build();
try {
ToolHelper.runD8(command, this::combinedOptionConsumer);
+ } catch (Unimplemented | CompilationError | InternalCompilerError re) {
+ throw re;
} catch (RuntimeException re) {
- throw re instanceof CompilationError ? re : re.getCause();
+ throw re.getCause() == null ? re : re.getCause();
}
}
}
diff --git a/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
index ea94040..6f51624 100644
--- a/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
@@ -5,6 +5,8 @@
package com.android.tools.r8;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.errors.InternalCompilerError;
+import com.android.tools.r8.errors.Unimplemented;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.UnaryOperator;
@@ -32,8 +34,10 @@
D8Command command = builder.addProgramFiles(inputFile).setOutputPath(out).build();
try {
ToolHelper.runD8(command, this::combinedOptionConsumer);
+ } catch (Unimplemented | CompilationError | InternalCompilerError re) {
+ throw re;
} catch (RuntimeException re) {
- throw re instanceof CompilationError ? re : re.getCause();
+ throw re.getCause() == null ? re : re.getCause();
}
}
}