L8 Cf to Cf
- Made L8 working Cf to Cf followed
by a R8/D8 compilation to compile desugared library.
- Added a cache in the test for desugared library
since tests were taking many minutes with new design.
- Change 2 test classes to generate desugared
library with and without shrinking based on
program compilation generated keep rules.
- Fix other tests to make them work with new L8.
Change-Id: Id2d23e852f3fc85b0a8a68edbc2cc012b9f25e97
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 1088e60..23e4e09 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -153,7 +153,7 @@
final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
IRConverter converter = new IRConverter(appInfo, options, timing, printer);
- app = converter.convertToDex(app, executor);
+ app = converter.convert(app, executor);
if (options.printCfg) {
if (options.printCfgFile == null || options.printCfgFile.isEmpty()) {
@@ -225,7 +225,7 @@
final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
IRConverter converter = new IRConverter(appInfo, options, timing, printer);
- application = converter.convertToDex(application, executor);
+ application = converter.convert(application, executor);
if (options.printCfg) {
if (options.printCfgFile == null || options.printCfgFile.isEmpty()) {
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index 4bf785c..2ea9573 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -6,20 +6,19 @@
import static com.android.tools.r8.utils.ExceptionUtils.unwrapExecutionException;
import com.android.tools.r8.dex.ApplicationReader;
-import com.android.tools.r8.dex.ApplicationWriter;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.jar.CfApplicationWriter;
import com.android.tools.r8.naming.PrefixRewritingNamingLens;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
-import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -60,24 +59,24 @@
AppView<?> appView = AppView.createForL8(appInfo, options);
IRConverter converter = new IRConverter(appView, timing);
- app = converter.convertToDex(app, executor);
+
+ app = converter.convert(app, executor);
assert appView.appInfo() == appInfo;
// Close any internal archive providers now the application is fully processed.
inputApp.closeInternalArchiveProviders();
- new ApplicationWriter(
+ new CfApplicationWriter(
app,
- null,
+ appView,
options,
- ImmutableList.of(options.getMarker(Tool.L8)),
- null,
+ options.getMarker(Tool.L8),
null,
GraphLense.getIdentityLense(),
PrefixRewritingNamingLens.createPrefixRewritingNamingLens(
options, converter.getAdditionalRewritePrefix()),
null)
- .write(executor);
+ .write(options.getClassFileConsumer(), executor);
options.printWarnings();
} catch (ExecutionException e) {
throw unwrapExecutionException(e);
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 3b23ef5..944c2bd 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -72,8 +72,8 @@
} else if (!getSpecialLibraryConfiguration().equals("default")) {
reporter.error("L8 currently requires the special library configuration to be \"default\"");
}
- if (getProgramConsumer() instanceof ClassFileConsumer) {
- reporter.error("L8 does not support compiling to Java class files");
+ if (getProgramConsumer() instanceof DexIndexedConsumer) {
+ reporter.error("L8 does not support compiling to dex");
}
if (getProgramConsumer() instanceof DexFilePerClassFileConsumer) {
reporter.error("L8 does not support compiling to dex per class");
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 5912651..4b3ace9 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -40,6 +40,7 @@
public class CfCode extends Code implements CfOrJarCode {
public static class LocalVariableInfo {
+
private final int index;
private final DebugLocalInfo local;
private final CfLabel start;
@@ -207,8 +208,7 @@
for (CfInstruction instruction : instructions) {
if (instruction instanceof CfFrame
&& (classFileVersion <= 49
- || (classFileVersion == 50
- && !options.getProguardConfiguration().getKeepAttributes().stackMapTable))) {
+ || (classFileVersion == 50 && !options.shouldKeepStackMapTable()))) {
continue;
}
instruction.write(visitor, namingLens);
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 90c15c6..fc5874f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -78,6 +78,7 @@
import org.objectweb.asm.Opcodes;
public class DexEncodedMethod extends KeyedDexItem<DexMethod> implements ResolutionResult {
+
public static final String CONFIGURATION_DEBUGGING_PREFIX = "Shaking error: Missing method in ";
/**
@@ -679,6 +680,18 @@
}
}
+ public static void setDebugInfoWithFakeThisParameter(Code code, int arity, AppView<?> appView) {
+ if (code.isDexCode()) {
+ DexCode dexCode = code.asDexCode();
+ dexCode.setDebugInfo(dexCode.debugInfoWithFakeThisParameter(appView.dexItemFactory()));
+ assert (dexCode.getDebugInfo() == null)
+ || (arity == dexCode.getDebugInfo().parameters.length);
+ } else {
+ // TODO(b/134732760): Patch Cf debug info.
+ assert appView.options().coreLibraryCompilation;
+ }
+ }
+
private DexEncodedMethod toMethodThatLogsErrorDexCode(DexItemFactory itemFactory) {
checkIfObsolete();
Signature signature = MethodSignature.fromDexMethod(method);
@@ -1066,6 +1079,7 @@
}
public static class ClassInlinerEligibility {
+
public final boolean returnsReceiver;
public ClassInlinerEligibility(boolean returnsReceiver) {
@@ -1074,12 +1088,14 @@
}
public static class TrivialInitializer {
+
private TrivialInitializer() {
}
// Defines instance trivial initialized, see details in comments
// to CodeRewriter::computeInstanceInitializerInfo(...)
public static final class TrivialInstanceInitializer extends TrivialInitializer {
+
public static final TrivialInstanceInitializer INSTANCE =
new TrivialInstanceInitializer();
}
@@ -1087,6 +1103,7 @@
// Defines class trivial initialized, see details in comments
// to CodeRewriter::computeClassInitializerInfo(...)
public static final class TrivialClassInitializer extends TrivialInitializer {
+
public final DexField field;
public TrivialClassInitializer(DexField field) {
@@ -1096,6 +1113,7 @@
}
public static class DefaultMethodOptimizationInfoImpl implements MethodOptimizationInfo {
+
public static final MethodOptimizationInfo DEFAULT_INSTANCE =
new DefaultMethodOptimizationInfoImpl();
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 484a529..87c976d 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
@@ -132,6 +132,10 @@
private final GeneratedMessageLiteShrinker generatedMessageLiteShrinker;
private final LibraryMethodOverrideAnalysis libraryMethodOverrideAnalysis;
private final StringConcatRewriter stringConcatRewriter;
+ private final StringOptimizer stringOptimizer;
+ private final StringBuilderOptimizer stringBuilderOptimizer;
+ private final IdempotentFunctionCallCanonicalizer idempotentFunctionCallCanonicalizer;
+ private final List<DexString> neverMergePrefixes;
private final LambdaRewriter lambdaRewriter;
private final D8NestBasedAccessDesugaring d8NestBasedAccessDesugaring;
private final InterfaceMethodRewriter interfaceMethodRewriter;
@@ -151,13 +155,9 @@
private final IdentifierNameStringMarker identifierNameStringMarker;
private final Devirtualizer devirtualizer;
private final CovariantReturnTypeAnnotationTransformer covariantReturnTypeAnnotationTransformer;
- private final StringOptimizer stringOptimizer;
- private final StringBuilderOptimizer stringBuilderOptimizer;
private final StringSwitchRemover stringSwitchRemover;
private final UninstantiatedTypeOptimization uninstantiatedTypeOptimization;
private final TypeChecker typeChecker;
- private final IdempotentFunctionCallCanonicalizer idempotentFunctionCallCanonicalizer;
- private final List<DexString> neverMergePrefixes;
final DeadCodeRemover deadCodeRemover;
@@ -187,6 +187,46 @@
this.classInitializerDefaultsOptimization =
options.debug ? null : new ClassInitializerDefaultsOptimization(appView, this);
this.stringConcatRewriter = new StringConcatRewriter(appView);
+ this.stringOptimizer = new StringOptimizer(appView);
+ this.stringBuilderOptimizer = new StringBuilderOptimizer(appView);
+ this.deadCodeRemover = new DeadCodeRemover(appView, codeRewriter);
+ this.idempotentFunctionCallCanonicalizer = new IdempotentFunctionCallCanonicalizer(appView);
+ this.neverMergePrefixes =
+ options.neverMergePrefixes.stream()
+ .map(prefix -> "L" + DescriptorUtils.getPackageBinaryNameFromJavaType(prefix))
+ .map(options.itemFactory::createString)
+ .collect(Collectors.toList());
+ if (options.coreLibraryCompilation) {
+ // Specific L8 Settings.
+ // BackportedMethodRewriter is needed for retarget core library members and backports.
+ // InterfaceMethodRewriter is needed for emulated interfaces.
+ // LambdaRewriter is needed because if it is missing there are invoke custom on
+ // default/static interface methods, and this is not supported by the compiler.
+ // The rest is nulled out.
+ this.backportedMethodRewriter = new BackportedMethodRewriter(appView, this);
+ this.interfaceMethodRewriter = new InterfaceMethodRewriter(appView, this);
+ this.lambdaRewriter = new LambdaRewriter(appView, this);
+ this.twrCloseResourceRewriter = null;
+ this.lambdaMerger = null;
+ this.covariantReturnTypeAnnotationTransformer = null;
+ this.nonNullTracker = null;
+ this.classInliner = null;
+ this.classStaticizer = null;
+ this.dynamicTypeOptimization = null;
+ this.generatedMessageLiteShrinker = null;
+ this.libraryMethodOverrideAnalysis = null;
+ this.inliner = null;
+ this.outliner = null;
+ this.memberValuePropagation = null;
+ this.lensCodeRewriter = null;
+ this.identifierNameStringMarker = null;
+ this.devirtualizer = null;
+ this.uninstantiatedTypeOptimization = null;
+ this.typeChecker = null;
+ this.d8NestBasedAccessDesugaring = null;
+ this.stringSwitchRemover = null;
+ return;
+ }
this.lambdaRewriter = options.enableDesugaring ? new LambdaRewriter(appView, this) : null;
this.interfaceMethodRewriter =
options.isInterfaceMethodDesugaringEnabled()
@@ -205,8 +245,6 @@
options.processCovariantReturnTypeAnnotations
? new CovariantReturnTypeAnnotationTransformer(this, appView.dexItemFactory())
: null;
- this.stringOptimizer = new StringOptimizer(appView);
- this.stringBuilderOptimizer = new StringBuilderOptimizer(appView);
this.nonNullTracker = options.enableNonNullTracking ? new NonNullTracker(appView) : null;
if (appView.enableWholeProgramOptimizations()) {
assert appView.appInfo().hasLiveness();
@@ -265,17 +303,10 @@
this.d8NestBasedAccessDesugaring =
options.shouldDesugarNests() ? new D8NestBasedAccessDesugaring(appView) : null;
}
- this.deadCodeRemover = new DeadCodeRemover(appView, codeRewriter);
- this.idempotentFunctionCallCanonicalizer = new IdempotentFunctionCallCanonicalizer(appView);
this.stringSwitchRemover =
options.isStringSwitchConversionEnabled()
? new StringSwitchRemover(appView, identifierNameStringMarker)
: null;
- this.neverMergePrefixes =
- options.neverMergePrefixes.stream()
- .map(prefix -> "L" + DescriptorUtils.getPackageBinaryNameFromJavaType(prefix))
- .map(options.itemFactory::createString)
- .collect(Collectors.toList());
}
public Set<DexCallSite> getDesugaredCallSites() {
@@ -390,12 +421,12 @@
}
}
- public DexApplication convertToDex(DexApplication application, ExecutorService executor)
+ public DexApplication convert(DexApplication application, ExecutorService executor)
throws ExecutionException {
removeLambdaDeserializationMethods();
timing.begin("IR conversion");
- convertClassesToDex(application.classes(), executor);
+ convertClasses(application.classes(), executor);
// Build a new application with jumbo string info,
Builder<?> builder = application.builder();
@@ -482,22 +513,22 @@
}
}
- private void convertClassesToDex(Iterable<DexProgramClass> classes,
- ExecutorService executor) throws ExecutionException {
+ private void convertClasses(Iterable<DexProgramClass> classes, ExecutorService executor)
+ throws ExecutionException {
List<Future<?>> futures = new ArrayList<>();
for (DexProgramClass clazz : classes) {
- futures.add(executor.submit(() -> convertMethodsToDex(clazz)));
+ futures.add(executor.submit(() -> convertMethods(clazz)));
}
ThreadUtils.awaitFutures(futures);
}
- private void convertMethodsToDex(DexProgramClass clazz) {
+ private void convertMethods(DexProgramClass clazz) {
boolean isReachabilitySensitive = clazz.hasReachabilitySensitiveAnnotation(options.itemFactory);
// When converting all methods on a class always convert <clinit> first.
for (DexEncodedMethod method : clazz.directMethods()) {
if (method.isClassInitializer()) {
method.getMutableOptimizationInfo().setReachabilitySensitive(isReachabilitySensitive);
- convertMethodToDex(method);
+ convertMethod(method);
break;
}
}
@@ -505,17 +536,17 @@
method -> {
if (!method.isClassInitializer()) {
method.getMutableOptimizationInfo().setReachabilitySensitive(isReachabilitySensitive);
- convertMethodToDex(method);
+ convertMethod(method);
}
});
}
- private void convertMethodToDex(DexEncodedMethod method) {
- assert options.isGeneratingDex();
+ private void convertMethod(DexEncodedMethod method) {
if (method.getCode() != null) {
boolean matchesMethodFilter = options.methodMatchesFilter(method);
if (matchesMethodFilter) {
- if (!(options.passthroughDexCode && method.getCode().isDexCode())) {
+ if (options.isGeneratingClassFiles()
+ || !(options.passthroughDexCode && method.getCode().isDexCode())) {
// We do not process in call graph order, so anything could be a leaf.
rewriteCode(method, simpleOptimizationFeedback, x -> true, CallSiteInformation.empty(),
Outliner::noProcessing);
@@ -530,7 +561,9 @@
}
}
}
- updateHighestSortingStrings(method);
+ if (!options.isGeneratingClassFiles()) {
+ updateHighestSortingStrings(method);
+ }
}
}
}
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 d534cf6..ff771b7 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
@@ -239,8 +239,7 @@
initializeJava9MethodProviders(factory);
initializeJava11MethodProviders(factory);
- // interface method desugaring also toggles library emulation.
- if (options.isInterfaceMethodDesugaringEnabled()) {
+ if (!options.retargetCoreLibMember.isEmpty()) {
initializeRetargetCoreLibraryMembers(appView);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
index 752db0e..044b50b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -126,7 +126,7 @@
.setReceiver(clazz.type)
.setTarget(rewriter.defaultAsMethodOfCompanionClass(method))
.setInvokeType(Invoke.Type.STATIC)
- .setIsInterface(target.isInterface());
+ .setIsInterface(false); // Holder is companion class, not an interface.
return new DexEncodedMethod(
newMethod,
newFlags,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index e044477..c5f5e24 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexLibraryClass;
@@ -87,11 +86,7 @@
MethodAccessFlags newFlags = virtual.accessFlags.copy();
newFlags.unsetBridge();
newFlags.promoteToStatic();
- DexCode dexCode = code.asDexCode();
- dexCode.setDebugInfo(dexCode.debugInfoWithFakeThisParameter(rewriter.factory));
- assert (dexCode.getDebugInfo() == null)
- || (companionMethod.getArity() == dexCode.getDebugInfo().parameters.length);
-
+ DexEncodedMethod.setDebugInfoWithFakeThisParameter(code, companionMethod.getArity(), appView);
DexEncodedMethod implMethod = new DexEncodedMethod(
companionMethod, newFlags, virtual.annotations, virtual.parameterAnnotationsList, code);
virtual.setDefaultInterfaceMethodImplementation(implMethod);
@@ -143,11 +138,7 @@
throw new CompilationError("Code is missing for private instance "
+ "interface method: " + oldMethod.toSourceString(), iface.origin);
}
- DexCode dexCode = code.asDexCode();
- dexCode.setDebugInfo(dexCode.debugInfoWithFakeThisParameter(rewriter.factory));
- assert (dexCode.getDebugInfo() == null)
- || (companionMethod.getArity() == dexCode.getDebugInfo().parameters.length);
-
+ DexEncodedMethod.setDebugInfoWithFakeThisParameter(code, companionMethod.getArity(), appView);
companionMethods.add(new DexEncodedMethod(companionMethod,
newFlags, direct.annotations, direct.parameterAnnotationsList, code));
graphLensBuilder.move(oldMethod, companionMethod);
@@ -232,7 +223,7 @@
forwardSourceCodeBuilder
.setTarget(origMethod)
.setInvokeType(Type.STATIC)
- .setIsInterface(true);
+ .setIsInterface(false); // We forward to the Companion class, not an interface.
DexEncodedMethod newEncodedMethod =
new DexEncodedMethod(
newMethod,
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 5be5a81..1c7132a 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
@@ -10,7 +10,6 @@
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
@@ -39,22 +38,19 @@
import java.util.function.Supplier;
/**
- * Represents lambda class generated for a lambda descriptor in context
- * of lambda instantiation point.
+ * Represents lambda class generated for a lambda descriptor in context of lambda instantiation
+ * point.
*
- * Even though call sites, and thus lambda descriptors, are canonicalized
- * across the application, the context may require several lambda classes
- * to be generated for the same lambda descriptor.
+ * <p>Even though call sites, and thus lambda descriptors, are canonicalized across the application,
+ * the context may require several lambda classes to be generated for the same lambda descriptor.
*
- * One reason is that we always generate a lambda class in the same package
- * lambda instantiation point is located in, so if same call site is used in
- * two classes from different packages (which can happen if same public method
- * is being references via method reference expression) we generate separate
- * lambda classes in those packages.
+ * <p>One reason is that we always generate a lambda class in the same package lambda instantiation
+ * point is located in, so if same call site is used in two classes from different packages (which
+ * can happen if same public method is being references via method reference expression) we generate
+ * separate lambda classes in those packages.
*
- * Another reason is that if we generate an accessor, we generate it in the
- * class referencing the call site, and thus two such classes will require two
- * separate lambda classes.
+ * <p>Another reason is that if we generate an accessor, we generate it in the class referencing the
+ * call site, and thus two such classes will require two separate lambda classes.
*/
final class LambdaClass {
@@ -397,9 +393,11 @@
// To avoid potential conflicts on the name of the lambda method once dispatch becomes virtual
// we add the method-holder name as suffix to the lambda-method name.
return new InstanceLambdaImplTarget(
- rewriter.factory.createMethod(implMethod.holder, implMethod.proto,
- rewriter.factory.createString(
- implMethod.name.toString() + "$" + implMethod.holder.getName())));
+ rewriter.factory.createMethod(
+ implMethod.holder,
+ implMethod.proto,
+ rewriter.factory.createString(
+ implMethod.name.toString() + "$" + implMethod.holder.getName())));
}
}
@@ -510,6 +508,13 @@
DexProgramClass programDefinitionFor(DexType type) {
return rewriter.converter.appView.appInfo().app().programDefinitionFor(type);
}
+
+ boolean holderIsInterface() {
+ DexMethod implMethod = descriptor.implHandle.asMethod();
+ DexClass implMethodHolder = definitionFor(implMethod.holder);
+ assert implMethodHolder != null;
+ return implMethodHolder.isInterface();
+ }
}
// Used for targeting methods referenced directly without creating accessors.
@@ -581,10 +586,9 @@
encodedMethod.getCode());
newMethod.copyMetadata(encodedMethod);
rewriter.methodMapping.put(encodedMethod.method, callTarget);
- DexCode dexCode = newMethod.getCode().asDexCode();
- dexCode.setDebugInfo(dexCode.debugInfoWithFakeThisParameter(rewriter.factory));
- assert (dexCode.getDebugInfo() == null)
- || (callTarget.getArity() == dexCode.getDebugInfo().parameters.length);
+
+ DexEncodedMethod.setDebugInfoWithFakeThisParameter(
+ newMethod.getCode(), callTarget.getArity(), rewriter.converter.appView);
implMethodHolder.setDirectMethod(i, newMethod);
return true;
}
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 99112d7..a5cf917 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
@@ -232,7 +232,7 @@
methodToCall.proto,
argValueTypes,
argRegisters,
- false /* isInterface */));
+ target.holderIsInterface()));
// Does the method have return value?
if (enforcedReturnType.isVoidType()) {
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index 5699977..ed86c65 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -117,7 +117,7 @@
}
String markerString = marker.toString();
for (DexProgramClass clazz : application.classes()) {
- if (clazz.getSynthesizedFrom().isEmpty()) {
+ if (clazz.getSynthesizedFrom().isEmpty() || options.coreLibraryCompilation) {
writeClass(clazz, consumer, markerString);
} else {
throw new Unimplemented("No support for synthetics in the Java bytecode backend.");
@@ -205,7 +205,8 @@
if (!method.hasClassFileVersion()) {
// In this case bridges have been introduced for the Cf back-end,
// which do not have class file version.
- assert options.testing.enableForceNestBasedAccessDesugaringForTest;
+ assert options.testing.enableForceNestBasedAccessDesugaringForTest
+ || options.coreLibraryCompilation;
return 0;
}
return method.getClassFileVersion();
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index b914026..7e788e1 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -286,6 +286,10 @@
throw new UnsupportedOperationException("Cannot find internal output mode.");
}
+ public boolean shouldKeepStackMapTable() {
+ return coreLibraryCompilation || getProguardConfiguration().getKeepAttributes().stackMapTable;
+ }
+
public boolean isGeneratingDex() {
return isGeneratingDexIndexed() || isGeneratingDexFilePerClassFile();
}
diff --git a/src/test/examplesJava9/stream/TestClass.java b/src/test/examplesJava9/stream/ProgramRewritingTestClass.java
similarity index 98%
rename from src/test/examplesJava9/stream/TestClass.java
rename to src/test/examplesJava9/stream/ProgramRewritingTestClass.java
index f29a4c8..7eedeb9 100644
--- a/src/test/examplesJava9/stream/TestClass.java
+++ b/src/test/examplesJava9/stream/ProgramRewritingTestClass.java
@@ -17,7 +17,7 @@
import java.util.Set;
import java.util.stream.IntStream;
-public class TestClass {
+public class ProgramRewritingTestClass {
// Each print to the console is immediately followed by the expected result so the tests
// can assert the results by checking the lines 2 by 2.
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
index fc2e5df..ab28e74 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
@@ -10,15 +10,22 @@
import com.android.tools.r8.L8Command;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompileResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
public class CoreLibDesugarTestBase extends TestBase {
+ private static Map<CacheEntry, TestCompileResult> computedLibraryCache =
+ new ConcurrentHashMap<>();
+
protected boolean requiresCoreLibDesugaring(TestParameters parameters) {
// TODO(b/134732760): Use the two other APIS instead.
return requiresEmulatedInterfaceCoreLibDesugaring(parameters)
@@ -33,10 +40,45 @@
return parameters.getApiLevel().getLevel() < AndroidApiLevel.P.getLevel();
}
+ protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel) throws RuntimeException {
+ return buildDesugaredLibrary(apiLevel, "", false);
+ }
+
+ protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel, String keepRules)
+ throws RuntimeException {
+ return buildDesugaredLibrary(apiLevel, keepRules, true);
+ }
+
+ protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel, String keepRules, boolean shrink)
+ throws RuntimeException {
+ return buildDesugaredLibrary(apiLevel, keepRules, shrink, ImmutableList.of());
+ }
+
protected Path buildDesugaredLibrary(
- AndroidApiLevel apiLevel, List<Path> additionalProgramFiles) {
+ AndroidApiLevel apiLevel, String keepRules, boolean shrink, List<Path> additionalProgramFiles)
+ throws RuntimeException {
+ // We wrap exceptions in a RuntimeException to call this from a lambda.
try {
- Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
+ Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs_dex.zip");
+ CacheEntry cacheEntry = new CacheEntry(apiLevel, keepRules, shrink, additionalProgramFiles);
+ TestCompileResult testCompileResult =
+ computedLibraryCache.computeIfAbsent(
+ cacheEntry,
+ key -> compileDesugaredLibrary(apiLevel, keepRules, shrink, additionalProgramFiles));
+ testCompileResult.writeToZip(output);
+ return output;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private TestCompileResult compileDesugaredLibrary(
+ AndroidApiLevel apiLevel, String keepRules, boolean shrink, List<Path> additionalProgramFiles)
+ throws RuntimeException {
+ // We wrap exceptions in a RuntimeException to call this from a lambda.
+ try {
+ // TODO(b/138922694): Known performance issue here.
+ Path cfDesugaredLib = temp.newFolder().toPath().resolve("desugar_jdk_libs_cf.zip");
L8.run(
L8Command.builder()
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
@@ -44,16 +86,64 @@
.addProgramFiles(additionalProgramFiles)
.addSpecialLibraryConfiguration("default")
.setMinApiLevel(apiLevel.getLevel())
- .setOutput(output, OutputMode.DexIndexed)
+ .setOutput(cfDesugaredLib, OutputMode.ClassFile)
.build());
- return output;
+ if (shrink) {
+ return testForR8(Backend.DEX)
+ .addProgramFiles(cfDesugaredLib)
+ .noMinification()
+ .addKeepRules(keepRules)
+ // We still need P+ library files to resolve classes.
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .setMinApi(apiLevel)
+ .compile();
+ }
+ return testForD8()
+ .addProgramFiles(cfDesugaredLib)
+ .setMinApi(apiLevel)
+ // We still need P+ library files to resolve classes.
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .compile();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
- protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel) {
- return buildDesugaredLibrary(apiLevel, ImmutableList.of());
+ private static class CacheEntry {
+
+ private int apiLevel;
+ private String keepRules;
+ private boolean shrink;
+ private List<Path> additionalProgramFiles;
+
+ private CacheEntry(
+ AndroidApiLevel apiLevel,
+ String keepRules,
+ boolean shrink,
+ List<Path> additionalProgramFiles) {
+ this.apiLevel = apiLevel.getLevel();
+ this.keepRules = keepRules;
+ this.shrink = shrink;
+ this.additionalProgramFiles = additionalProgramFiles;
+ }
+
+ @Override
+ public int hashCode() {
+ // In practice there are only 2 sets of additionalProgramFiles with different sizes.
+ return Objects.hash(apiLevel, keepRules, shrink, additionalProgramFiles.size());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof CacheEntry)) {
+ return false;
+ }
+ CacheEntry other = (CacheEntry) o;
+ return apiLevel == other.apiLevel
+ && keepRules.equals(other.keepRules)
+ && shrink == other.shrink
+ && additionalProgramFiles.equals(other.additionalProgramFiles);
+ }
}
protected void assertLines2By2Correct(String stdOut) {
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/DesugaredLibraryContentTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/DesugaredLibraryContentTest.java
index 5d803bd..20d4868 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/DesugaredLibraryContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/DesugaredLibraryContentTest.java
@@ -19,6 +19,7 @@
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.google.common.collect.ImmutableSet;
import java.util.stream.Collectors;
+import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -39,6 +40,7 @@
@Test
public void test() throws Exception {
+ Assume.assumeTrue(requiresCoreLibDesugaring(parameters));
CodeInspector inspector = new CodeInspector(buildDesugaredLibrary(parameters.getApiLevel()));
assertThat(inspector.clazz("j$.util.Optional"), isPresent());
assertThat(inspector.clazz("j$.util.OptionalInt"), isPresent());
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/EmulatedInterfacesTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/EmulatedInterfacesTest.java
new file mode 100644
index 0000000..cc3a1b0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/EmulatedInterfacesTest.java
@@ -0,0 +1,94 @@
+// Copyright (c) 2019, 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.corelib;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class EmulatedInterfacesTest extends CoreLibDesugarTestBase {
+
+ private final TestParameters parameters;
+ private final boolean shrinkCoreLibrary;
+
+ @Parameters(name = "{1}, shrinkCoreLibrary: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ }
+
+ public EmulatedInterfacesTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+ this.shrinkCoreLibrary = shrinkDesugaredLibrary;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testEmulatedInterface() throws Exception {
+ Assume.assumeTrue((requiresCoreLibDesugaring(parameters)));
+ CodeInspector inspector =
+ new CodeInspector(
+ buildDesugaredLibrary(
+ parameters.getApiLevel(), "-keep class **$-EL", shrinkCoreLibrary));
+ assertEmulateInterfaceClassesPresentWithDispatchMethods(inspector);
+ assertCollectionMethodsPresentWithCorrectDispatch(inspector);
+ }
+
+ private void assertEmulateInterfaceClassesPresentWithDispatchMethods(CodeInspector inspector) {
+ List<FoundClassSubject> dispatchClasses =
+ inspector.allClasses().stream()
+ .filter(
+ clazz ->
+ clazz
+ .getOriginalName()
+ .contains(InterfaceMethodRewriter.EMULATE_LIBRARY_CLASS_NAME_SUFFIX))
+ .collect(Collectors.toList());
+ int numDispatchClasses = 9;
+ assertEquals(numDispatchClasses, dispatchClasses.size());
+ for (FoundClassSubject clazz : dispatchClasses) {
+ assertTrue(
+ clazz.allMethods().stream()
+ .allMatch(
+ method ->
+ method.isStatic()
+ && method
+ .streamInstructions()
+ .anyMatch(InstructionSubject::isInstanceOf)));
+ }
+ }
+
+ private void assertCollectionMethodsPresentWithCorrectDispatch(CodeInspector inspector) {
+ DexClass collectionDispatch = inspector.clazz("j$.util.Collection$-EL").getDexClass();
+ for (DexEncodedMethod method : collectionDispatch.methods()) {
+ int numCheckCast =
+ (int)
+ Stream.of(method.getCode().asDexCode().instructions)
+ .filter(Instruction::isCheckCast)
+ .count();
+ if (method.qualifiedName().contains("spliterator")) {
+ assertEquals(5, numCheckCast);
+ } else {
+ assertEquals(1, numCheckCast);
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/MergingJ$Test.java b/src/test/java/com/android/tools/r8/desugar/corelib/MergingJ$Test.java
index 36561cb..f4f5807 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/MergingJ$Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/MergingJ$Test.java
@@ -47,20 +47,27 @@
}
private Path buildSplitDesugaredLibraryPart1() throws Exception {
- Path output = temp.newFolder().toPath().resolve("merger-input.zip");
+ Path outputCf = temp.newFolder().toPath().resolve("merger-input-cf.zip");
+ Path outputDex = temp.newFolder().toPath().resolve("merger-input-dex.zip");
L8.run(
L8Command.builder()
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
.addProgramFiles(ToolHelper.getDesugarJDKLibs())
.addSpecialLibraryConfiguration("default")
.setMinApiLevel(AndroidApiLevel.B.getLevel())
- .setOutput(output, OutputMode.DexIndexed)
+ .setOutput(outputCf, OutputMode.ClassFile)
.build());
- return output;
+ testForD8()
+ .addProgramFiles(outputCf)
+ .setMinApi(AndroidApiLevel.B)
+ .compile()
+ .writeToZip(outputDex);
+ return outputDex;
}
private Path buildSplitDesugaredLibraryPart2() throws Exception {
- Path output = temp.newFolder().toPath().resolve("merger-input-split.zip");
+ Path outputCf = temp.newFolder().toPath().resolve("merger-input-split-cf.zip");
+ Path outputDex = temp.newFolder().toPath().resolve("merger-input-split-dex.zip");
L8.run(
L8Command.builder()
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
@@ -68,8 +75,13 @@
.addClasspathFiles(ToolHelper.getDesugarJDKLibs())
.addSpecialLibraryConfiguration("default")
.setMinApiLevel(AndroidApiLevel.B.getLevel())
- .setOutput(output, OutputMode.DexIndexed)
+ .setOutput(outputCf, OutputMode.ClassFile)
.build());
- return output;
+ testForD8()
+ .addProgramFiles(outputCf)
+ .setMinApi(AndroidApiLevel.B)
+ .compile()
+ .writeToZip(outputDex);
+ return outputDex;
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/EmulateLibraryInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java
similarity index 76%
rename from src/test/java/com/android/tools/r8/desugar/corelib/EmulateLibraryInterfaceTest.java
rename to src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java
index 19763ad..8aeddab 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/EmulateLibraryInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java
@@ -16,80 +16,111 @@
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class EmulateLibraryInterfaceTest extends CoreLibDesugarTestBase {
+public class ProgramRewritingTest extends CoreLibDesugarTestBase {
+
+ private static final String TEST_CLASS = "stream.ProgramRewritingTestClass";
private final TestParameters parameters;
+ private final boolean shrinkCoreLibrary;
- @Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ @Parameters(name = "{1}, shrinkCoreLibrary: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
}
- public EmulateLibraryInterfaceTest(TestParameters parameters) {
+ public ProgramRewritingTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+ this.shrinkCoreLibrary = shrinkDesugaredLibrary;
this.parameters = parameters;
}
@Test
- public void testDispatchClasses() throws Exception {
- CodeInspector inspector = new CodeInspector(buildDesugaredLibrary(parameters.getApiLevel()));
- List<FoundClassSubject> dispatchClasses =
- inspector.allClasses().stream()
- .filter(
- clazz ->
- clazz
- .getOriginalName()
- .contains(InterfaceMethodRewriter.EMULATE_LIBRARY_CLASS_NAME_SUFFIX))
- .collect(Collectors.toList());
- int numDispatchClasses = requiresCoreLibDesugaring(parameters) ? 9 : 0;
- assertEquals(numDispatchClasses, dispatchClasses.size());
- for (FoundClassSubject clazz : dispatchClasses) {
+ public void testProgramD8() throws Exception {
+ Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
+ Box<String> keepRulesHolder = new Box<>("");
+ D8TestRunResult d8TestRunResult =
+ testForD8()
+ .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(
+ options ->
+ options.testing.desugaredLibraryKeepRuleConsumer =
+ (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
+ .enableCoreLibraryDesugaring()
+ .compile()
+ .inspect(this::checkRewrittenInvokes)
+ .addRunClasspathFiles(
+ buildDesugaredLibrary(
+ parameters.getApiLevel(), keepRulesHolder.get(), shrinkCoreLibrary))
+ .run(parameters.getRuntime(), TEST_CLASS)
+ .assertSuccess();
+ assertLines2By2Correct(d8TestRunResult.getStdOut());
+ assertGeneratedKeepRulesAreCorrect(keepRulesHolder.get());
+ String stdErr = d8TestRunResult.getStdErr();
+ if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
+ // Flaky: There might be a missing method on lambda deserialization.
assertTrue(
- clazz.allMethods().stream()
- .allMatch(
- method ->
- method.isStatic()
- && method
- .streamInstructions()
- .anyMatch(InstructionSubject::isInstanceOf)));
+ !stdErr.contains("Could not find method")
+ || stdErr.contains("Could not find method java.lang.invoke.SerializedLambda"));
+ } else {
+ assertFalse(stdErr.contains("Could not find method"));
}
- if (requiresCoreLibDesugaring(parameters)) {
- DexClass collectionDispatch = inspector.clazz("j$.util.Collection$-EL").getDexClass();
- for (DexEncodedMethod method : collectionDispatch.methods()) {
- int numCheckCast =
- (int)
- Stream.of(method.getCode().asDexCode().instructions)
- .filter(Instruction::isCheckCast)
- .count();
- if (method.qualifiedName().contains("spliterator")) {
- assertEquals(5, numCheckCast);
- } else {
- assertEquals(1, numCheckCast);
- }
+ }
+
+ @Test
+ public void testProgramR8() throws Exception {
+ Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
+ for (Boolean minifying : BooleanUtils.values()) {
+ Box<String> keepRulesHolder = new Box<>("");
+ R8TestRunResult r8TestRunResult =
+ testForR8(parameters.getBackend())
+ .minification(minifying)
+ .addKeepMainRule(TEST_CLASS)
+ .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(
+ options ->
+ options.testing.desugaredLibraryKeepRuleConsumer =
+ (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
+ .enableCoreLibraryDesugaring()
+ .compile()
+ .inspect(this::checkRewrittenInvokes)
+ .addRunClasspathFiles(
+ buildDesugaredLibrary(
+ parameters.getApiLevel(), keepRulesHolder.get(), shrinkCoreLibrary))
+ .run(parameters.getRuntime(), TEST_CLASS)
+ .assertSuccess();
+ assertLines2By2Correct(r8TestRunResult.getStdOut());
+ assertGeneratedKeepRulesAreCorrect(keepRulesHolder.get());
+ if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
+ // Flaky: There might be a missing method on lambda deserialization.
+ r8TestRunResult.assertStderrMatches(
+ anyOf(
+ not(containsString("Could not find method")),
+ containsString("Could not find method java.lang.invoke.SerializedLambda")));
+ } else {
+ r8TestRunResult.assertStderrMatches(not(containsString("Could not find method")));
}
}
}
@@ -98,7 +129,7 @@
if (!requiresCoreLibDesugaring(parameters)) {
return;
}
- ClassSubject classSubject = inspector.clazz("stream.TestClass");
+ ClassSubject classSubject = inspector.clazz(TEST_CLASS);
assertThat(classSubject, isPresent());
List<InstructionSubject> invokes =
classSubject
@@ -140,74 +171,6 @@
assertTrue(invokes.get(i).toString().contains(s));
}
- @Test
- public void testProgramD8() throws Exception {
- Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
- Box<String> keepRulesHolder = new Box<>("");
- D8TestRunResult d8TestRunResult =
- testForD8()
- .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
- .setMinApi(parameters.getApiLevel())
- .addOptionsModification(
- options ->
- options.testing.desugaredLibraryKeepRuleConsumer =
- (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
- .enableCoreLibraryDesugaring()
- .compile()
- .inspect(this::checkRewrittenInvokes)
- .addRunClasspathFiles(buildDesugaredLibrary(parameters.getApiLevel()))
- .run(parameters.getRuntime(), "stream.TestClass")
- .assertSuccess();
- assertLines2By2Correct(d8TestRunResult.getStdOut());
- assertGeneratedKeepRulesAreCorrect(keepRulesHolder.get());
- String stdErr = d8TestRunResult.getStdErr();
- if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
- // Flaky: There might be a missing method on lambda deserialization.
- assertTrue(
- !stdErr.contains("Could not find method")
- || stdErr.contains("Could not find method java.lang.invoke.SerializedLambda"));
- } else {
- assertFalse(stdErr.contains("Could not find method"));
- }
- }
-
- @Test
- public void testProgramR8() throws Exception {
- Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
- for (Boolean minifying : BooleanUtils.values()) {
- Box<String> keepRulesHolder = new Box<>("");
- R8TestRunResult r8TestRunResult =
- testForR8(parameters.getBackend())
- .minification(minifying)
- .addKeepMainRule("stream.TestClass")
- .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
- .setMinApi(parameters.getApiLevel())
- .addOptionsModification(
- options ->
- options.testing.desugaredLibraryKeepRuleConsumer =
- (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
- .enableCoreLibraryDesugaring()
- .compile()
- .inspect(this::checkRewrittenInvokes)
- .addRunClasspathFiles(buildDesugaredLibrary(parameters.getApiLevel()))
- .run(parameters.getRuntime(), "stream.TestClass")
- .assertSuccess();
- assertLines2By2Correct(r8TestRunResult.getStdOut());
- assertGeneratedKeepRulesAreCorrect(keepRulesHolder.get());
- if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
- // Flaky: There might be a missing method on lambda deserialization.
- r8TestRunResult.assertStderrMatches(
- anyOf(
- not(containsString("Could not find method")),
- containsString("Could not find method java.lang.invoke.SerializedLambda")));
- } else {
- r8TestRunResult.assertStderrMatches(not(containsString("Could not find method")));
- }
- }
- }
-
private void assertGeneratedKeepRulesAreCorrect(String keepRules) {
String expectedResult =
StringUtils.lines(
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11CoreLibTestBase.java b/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11CoreLibTestBase.java
index f77099a..169c7f9 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11CoreLibTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11CoreLibTestBase.java
@@ -103,6 +103,6 @@
protected Path buildDesugaredLibraryWithJavaBaseExtension(AndroidApiLevel apiLevel)
throws Exception {
return buildDesugaredLibrary(
- apiLevel, ImmutableList.copyOf(JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES));
+ apiLevel, "", false, ImmutableList.copyOf(JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES));
}
}