Merge commit 'c152f9cd43434984e548705d2457d89ac2d34dc1' into dev-release
diff --git a/build.gradle b/build.gradle
index 9800595..1fd0955 100644
--- a/build.gradle
+++ b/build.gradle
@@ -125,6 +125,11 @@
srcDirs = ['src/test/examplesJava9']
}
}
+ examplesJava10 {
+ java {
+ srcDirs = ['src/test/examplesJava10']
+ }
+ }
examplesJava11 {
java {
srcDirs = ['src/test/examplesJava11']
@@ -504,7 +509,7 @@
} else {
def javaHomeOut = new StringBuilder()
def javaHomeErr = new StringBuilder()
- def javaHomeProc = './tools/jdk.py'.execute()
+ def javaHomeProc = './tools/jdk.py'.execute([], projectDir)
javaHomeProc.waitForProcessOutput(javaHomeOut, javaHomeErr)
def jdkHome = new File(javaHomeOut.toString().trim())
if (!jdkHome.exists()) {
@@ -550,7 +555,7 @@
targetCompatibility = JavaVersion.VERSION_1_9
}
-def setJava11Compilation(sourceSet) {
+def setJdk11CompilationWithCompatibility(String sourceSet, JavaVersion compatibility) {
tasks.named(sourceSet).get().configure {
def jdkDir = 'third_party/openjdk/jdk-11/'
options.fork = true
@@ -562,14 +567,15 @@
} else {
options.forkOptions.javaHome = file(jdkDir + 'Windows')
}
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+ sourceCompatibility = compatibility
+ targetCompatibility = compatibility
}
}
-setJava11Compilation(sourceSets.examplesJava11.compileJavaTaskName)
-setJava11Compilation(sourceSets.examplesTestNGRunner.compileJavaTaskName)
-setJava11Compilation(sourceSets.jdk11TimeTests.compileJavaTaskName)
+setJdk11CompilationWithCompatibility(sourceSets.examplesJava10.compileJavaTaskName, JavaVersion.VERSION_1_10)
+setJdk11CompilationWithCompatibility(sourceSets.examplesJava11.compileJavaTaskName, JavaVersion.VERSION_11)
+setJdk11CompilationWithCompatibility(sourceSets.examplesTestNGRunner.compileJavaTaskName, JavaVersion.VERSION_11)
+setJdk11CompilationWithCompatibility(sourceSets.jdk11TimeTests.compileJavaTaskName, JavaVersion.VERSION_11)
task compileMainWithJava11 (type: JavaCompile) {
dependsOn downloadDeps
@@ -1434,6 +1440,22 @@
}
}
+task buildExampleJava10Jars {
+ def examplesDir = file("src/test/examplesJava10")
+ examplesDir.eachDir { dir ->
+ def name = dir.getName();
+ def exampleOutputDir = file("build/test/examplesJava10");
+ def jarName = "${name}.jar"
+ dependsOn "jar_examplesJava10_${name}"
+ task "jar_examplesJava10_${name}"(type: Jar) {
+ archiveName = jarName
+ destinationDir = exampleOutputDir
+ from sourceSets.examplesJava10.output
+ include "**/" + name + "/**/*.class"
+ }
+ }
+}
+
task buildExampleJava11Jars {
def examplesDir = file("src/test/examplesJava11")
examplesDir.eachDir { dir ->
@@ -1566,6 +1588,7 @@
dependsOn buildExampleAndroidOJars
dependsOn buildExampleAndroidPJars
dependsOn buildExampleJava9Jars
+ dependsOn buildExampleJava10Jars
dependsOn buildExampleJava11Jars
dependsOn buildExampleAndroidApi
def examplesDir = file("src/test/examples")
diff --git a/src/main/java/com/android/tools/r8/graph/AccessFlags.java b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
index 64135fd..98760b6 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
@@ -101,7 +101,7 @@
return visibilityOrdinal() >= other.visibilityOrdinal();
}
- public boolean isSameVisiblity(AccessFlags other) {
+ public boolean isSameVisibility(AccessFlags other) {
return visibilityOrdinal() == other.visibilityOrdinal();
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 2390bc6..cc8af52 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -215,13 +215,20 @@
*/
public DexEncodedMethod lookupSuperTarget(DexMethod method, DexType invocationContext) {
assert checkIfObsolete();
+ assert invocationContext.isClassType();
+ DexClass context = definitionFor(invocationContext);
+ return context == null ? null : lookupSuperTarget(method, context);
+ }
+
+ public DexEncodedMethod lookupSuperTarget(DexMethod method, DexClass invocationContext) {
+ assert checkIfObsolete();
return resolveMethod(method.holder, method).lookupInvokeSuperTarget(invocationContext, this);
}
/**
* Lookup direct method following the super chain from the holder of {@code method}.
- * <p>
- * This method will lookup private and constructor methods.
+ *
+ * <p>This method will lookup private and constructor methods.
*
* @param method the method to lookup
* @return The actual target for {@code method} or {@code null} if none found.
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index 0998136..a24212f 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -354,7 +354,7 @@
assert potentialHolder.isInterface();
for (DexEncodedMethod virtualMethod : potentialHolder.virtualMethods) {
if (virtualMethod.method.hasSameProtoAndName(method.method)
- && virtualMethod.accessFlags.isSameVisiblity(method.accessFlags)) {
+ && virtualMethod.accessFlags.isSameVisibility(method.accessFlags)) {
return true;
}
}
@@ -468,6 +468,12 @@
return !getTypeInfo(type).directSubtypes.isEmpty();
}
+ public boolean isRelatedBySubtyping(DexType type, DexType other) {
+ assert type.isClassType();
+ assert other.isClassType();
+ return isSubtype(type, other) || isSubtype(other, type);
+ }
+
@Override
public boolean isSubtype(DexType subtype, DexType supertype) {
if (subtype == supertype || isStrictSubtypeOf(subtype, supertype)) {
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 91994d1..ac4e4eb 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -247,6 +247,13 @@
}
}
+ public void withGeneratedMessageLiteBuilderShrinker(
+ Consumer<GeneratedMessageLiteBuilderShrinker> consumer) {
+ if (protoShrinker != null && protoShrinker.generatedMessageLiteBuilderShrinker != null) {
+ consumer.accept(protoShrinker.generatedMessageLiteBuilderShrinker);
+ }
+ }
+
public <U> U withGeneratedMessageLiteShrinker(
Function<GeneratedMessageLiteShrinker, U> fn, U defaultValue) {
if (protoShrinker != null && protoShrinker.generatedMessageLiteShrinker != null) {
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 97da896..7fe4555 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1007,6 +1007,31 @@
return builder.build();
}
+ public static DexEncodedMethod createDesugaringForwardingMethod(
+ DexEncodedMethod target, DexClass clazz, DexMethod forwardMethod, DexItemFactory factory) {
+ DexMethod method = target.method;
+ assert forwardMethod != null;
+ // New method will have the same name, proto, and also all the flags of the
+ // default method, including bridge flag.
+ DexMethod newMethod = factory.createMethod(clazz.type, method.proto, method.name);
+ MethodAccessFlags newFlags = target.accessFlags.copy();
+ // Some debuggers (like IntelliJ) automatically skip synthetic methods on single step.
+ newFlags.setSynthetic();
+ ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
+ ForwardMethodSourceCode.builder(newMethod);
+ forwardSourceCodeBuilder
+ .setReceiver(clazz.type)
+ .setTarget(forwardMethod)
+ .setInvokeType(Invoke.Type.STATIC)
+ .setIsInterface(false); // Holder is companion class, or retarget method, not an interface.
+ return new DexEncodedMethod(
+ newMethod,
+ newFlags,
+ target.annotations,
+ target.parameterAnnotationsList,
+ new SynthesizedCode(forwardSourceCodeBuilder::build));
+ }
+
public DexEncodedMethod toStaticMethodWithoutThis() {
checkIfObsolete();
assert !accessFlags.isStatic();
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index faad0e6..5d85611 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -230,6 +230,9 @@
public final DexString consumerDescriptor = createString("Ljava/util/function/Consumer;");
public final DexString runnableDescriptor = createString("Ljava/lang/Runnable;");
public final DexString optionalDescriptor = createString("Ljava/util/Optional;");
+ public final DexString optionalDoubleDescriptor = createString("Ljava/util/OptionalDouble;");
+ public final DexString optionalIntDescriptor = createString("Ljava/util/OptionalInt;");
+ public final DexString optionalLongDescriptor = createString("Ljava/util/OptionalLong;");
public final DexString streamDescriptor = createString("Ljava/util/stream/Stream;");
public final DexString arraysDescriptor = createString("Ljava/util/Arrays;");
@@ -328,6 +331,9 @@
public final DexType consumerType = createType(consumerDescriptor);
public final DexType runnableType = createType(runnableDescriptor);
public final DexType optionalType = createType(optionalDescriptor);
+ public final DexType optionalDoubleType = createType(optionalDoubleDescriptor);
+ public final DexType optionalIntType = createType(optionalIntDescriptor);
+ public final DexType optionalLongType = createType(optionalLongDescriptor);
public final DexType streamType = createType(streamDescriptor);
public final DexType runtimeExceptionType = createType(runtimeExceptionDescriptor);
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index 8c5dd71..1fc834d 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -345,8 +345,8 @@
protected final Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>();
protected final Map<DexField, DexField> fieldMap = new IdentityHashMap<>();
- private final BiMap<DexField, DexField> originalFieldSignatures = HashBiMap.create();
- private final BiMap<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create();
+ protected final BiMap<DexField, DexField> originalFieldSignatures = HashBiMap.create();
+ protected final BiMap<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create();
public void map(DexType from, DexType to) {
if (from == to) {
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
new file mode 100644
index 0000000..1e33e66
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -0,0 +1,28 @@
+// 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.graph;
+
+import com.android.tools.r8.errors.Unreachable;
+
+/** Type representing a method definition in the programs compilation unit and its holder. */
+public class ProgramMethod {
+ public final DexProgramClass holder;
+ public final DexEncodedMethod method;
+
+ public ProgramMethod(DexProgramClass holder, DexEncodedMethod method) {
+ assert holder.type == method.method.holder;
+ this.holder = holder;
+ this.method = method;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ throw new Unreachable("Unsupported attempt at comparing ProgramMethod");
+ }
+
+ @Override
+ public int hashCode() {
+ throw new Unreachable("Unsupported attempt at computing the hashcode of ProgramMethod");
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
index bdea265..65a2c7c 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.SetUtils;
import com.google.common.collect.Sets;
@@ -61,8 +60,16 @@
public abstract boolean isValidVirtualTargetForDynamicDispatch();
+ /** Lookup the single target of an invoke-special on this resolution result if possible. */
+ public abstract DexEncodedMethod lookupInvokeSpecialTarget(
+ DexProgramClass context, AppInfoWithSubtyping appInfo);
+
/** Lookup the single target of an invoke-super on this resolution result if possible. */
- public abstract DexEncodedMethod lookupInvokeSuperTarget(DexType context, AppInfo appInfo);
+ public abstract DexEncodedMethod lookupInvokeSuperTarget(
+ DexProgramClass context, AppInfoWithSubtyping appInfo);
+
+ @Deprecated
+ public abstract DexEncodedMethod lookupInvokeSuperTarget(DexClass context, AppInfo appInfo);
public final Set<DexEncodedMethod> lookupVirtualDispatchTargets(
boolean isInterface, AppInfoWithSubtyping appInfo) {
@@ -143,6 +150,96 @@
}
/**
+ * This is intended to model the actual behavior of invoke-special on a JVM.
+ *
+ * <p>See https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html#jvms-6.5.invokespecial
+ * and comments below for deviations due to diverging behavior on actual JVMs.
+ */
+ @Override
+ public DexEncodedMethod lookupInvokeSpecialTarget(
+ DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ // If the resolution is non-accessible then no target exists.
+ if (!isAccessibleFrom(context, appInfo)) {
+ return null;
+ }
+
+ // Statics cannot be targeted by invoke-special.
+ if (getResolvedMethod().isStatic()) {
+ return null;
+ }
+
+ // The symbolic reference is the holder type that resolution was initiated at.
+ DexClass symbolicReference = initialResolutionHolder;
+
+ // First part of the spec is to determine the starting point for lookup for invoke special.
+ // Notice that the specification indicates that the immediate super type should
+ // be used when three items hold, the second being:
+ // is-class(sym-ref) => is-super(sym-ref, context)
+ // in the case of an interface that is trivially satisfied, which would lead the initial type
+ // to be java.lang.Object. However in practice the lookup appears to start at the symbolic
+ // reference in the case of interfaces, so the second condition should likely be interpreted:
+ // is-class(sym-ref) *and* is-super(sym-ref, context).
+ final DexClass initialType;
+ if (!resolvedMethod.isInstanceInitializer()
+ && !symbolicReference.isInterface()
+ && isSuperclass(symbolicReference, context, appInfo)) {
+ // If reference is a super type of the context then search starts at the immediate super.
+ initialType = appInfo.definitionFor(context.superType);
+ } else {
+ // Otherwise it starts at the reference itself.
+ initialType = symbolicReference;
+ }
+ // Abort if for some reason the starting point could not be found.
+ if (initialType == null) {
+ return null;
+ }
+ // 1-3. Search the initial class and its supers in order for a matching instance method.
+ DexMethod method = getResolvedMethod().method;
+ DexEncodedMethod target = null;
+ DexClass current = initialType;
+ while (current != null) {
+ target = current.lookupMethod(method);
+ if (target != null) {
+ break;
+ }
+ current = current.superType == null ? null : appInfo.definitionFor(current.superType);
+ }
+ // 4. Otherwise, it is the single maximally specific method:
+ if (target == null) {
+ target = appInfo.resolveMaximallySpecificMethods(initialType, method).getSingleTarget();
+ }
+ if (target == null) {
+ return null;
+ }
+ // Linking exceptions:
+ // A non-instance method throws IncompatibleClassChangeError.
+ if (target.isStatic()) {
+ return null;
+ }
+ // An instance initializer that is not to the symbolic reference throws NoSuchMethodError.
+ // It appears as if this check is also in place for non-initializer methods too.
+ // See NestInvokeSpecialMethodAccessWithIntermediateTest.
+ if ((target.isInstanceInitializer() || target.isPrivateMethod())
+ && target.method.holder != symbolicReference.type) {
+ return null;
+ }
+ // Runtime exceptions:
+ // An abstract method throws AbstractMethodError.
+ if (target.isAbstract()) {
+ return null;
+ }
+ // Should we check access control again?
+ if (!AccessControl.isMethodAccessible(target, initialType, context, appInfo)) {
+ return null;
+ }
+ return target;
+ }
+
+ private static boolean isSuperclass(DexClass sup, DexClass sub, AppInfoWithSubtyping appInfo) {
+ return sup != sub && appInfo.isSubtype(sub.type, sup.type);
+ }
+
+ /**
* Lookup super method following the super chain from the holder of {@code method}.
*
* <p>This method will resolve the method on the holder of {@code method} and only return a
@@ -164,17 +261,26 @@
* @return The actual target for the invoke-super or {@code null} if none found.
*/
@Override
- public DexEncodedMethod lookupInvokeSuperTarget(DexType context, AppInfo appInfo) {
+ public DexEncodedMethod lookupInvokeSuperTarget(
+ DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ if (!isAccessibleFrom(context, appInfo)) {
+ return null;
+ }
+ return lookupInvokeSuperTarget(context.asDexClass(), appInfo);
+ }
+
+ @Override
+ public DexEncodedMethod lookupInvokeSuperTarget(DexClass context, AppInfo appInfo) {
+ assert context != null;
DexMethod method = resolvedMethod.method;
// TODO(b/145775365): Check the requirements for an invoke-special to a protected method.
// See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokespecial
if (appInfo.hasSubtyping()
- && !appInfo.withSubtyping().isSubtype(context, initialResolutionHolder.type)) {
- DexClass contextClass = appInfo.definitionFor(context);
+ && !appInfo.withSubtyping().isSubtype(context.type, initialResolutionHolder.type)) {
throw new CompilationError(
"Illegal invoke-super to " + method.toSourceString() + " from class " + context,
- contextClass != null ? contextClass.getOrigin() : Origin.unknown());
+ context.getOrigin());
}
// According to
@@ -189,12 +295,11 @@
return appInfo.resolveMethodOnInterface(initialResolutionHolder, method).getSingleTarget();
}
// Then, resume on the search, but this time, starting from the holder of the caller.
- DexClass contextClass = appInfo.definitionFor(context);
- if (contextClass == null || contextClass.superType == null) {
+ if (context.superType == null) {
return null;
}
SingleResolutionResult resolution =
- appInfo.resolveMethodOnClass(contextClass.superType, method).asSingleResolution();
+ appInfo.resolveMethodOnClass(context.superType, method).asSingleResolution();
return resolution != null && !resolution.resolvedMethod.isStatic()
? resolution.resolvedMethod
: null;
@@ -305,7 +410,19 @@
abstract static class EmptyResult extends ResolutionResult {
@Override
- public final DexEncodedMethod lookupInvokeSuperTarget(DexType context, AppInfo appInfo) {
+ public final DexEncodedMethod lookupInvokeSpecialTarget(
+ DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ return null;
+ }
+
+ @Override
+ public DexEncodedMethod lookupInvokeSuperTarget(
+ DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ return null;
+ }
+
+ @Override
+ public final DexEncodedMethod lookupInvokeSuperTarget(DexClass context, AppInfo appInfo) {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
index 0e8da38..d1cf2e5 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
@@ -11,6 +11,10 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.conversion.CallGraph.Node;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.function.BooleanSupplier;
@@ -41,6 +45,21 @@
new RootSetExtension(appView, alwaysInline, neverInline, bypassClinitforInlining).extend();
}
+ public void preprocessCallGraphBeforeCycleElimination(Map<DexMethod, Node> nodes) {
+ Node node = nodes.get(references.generatedMessageLiteBuilderMethods.constructorMethod);
+ if (node != null) {
+ List<Node> calleesToBeRemoved = new ArrayList<>();
+ for (Node callee : node.getCalleesWithDeterministicOrder()) {
+ if (references.isDynamicMethodBridge(callee.method)) {
+ calleesToBeRemoved.add(callee);
+ }
+ }
+ for (Node callee : calleesToBeRemoved) {
+ callee.removeCaller(node);
+ }
+ }
+ }
+
private static class RootSetExtension {
private final AppView<? extends AppInfoWithSubtyping> appView;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
index cedb6ed..c90eaf2 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
@@ -99,6 +99,14 @@
return isDynamicMethod(encodedMethod.method);
}
+ public boolean isDynamicMethodBridge(DexMethod method) {
+ return method == generatedMessageLiteMethods.dynamicMethodBridgeMethod;
+ }
+
+ public boolean isDynamicMethodBridge(DexEncodedMethod method) {
+ return isDynamicMethodBridge(method.method);
+ }
+
public boolean isFindLiteExtensionByNumberMethod(DexMethod method) {
return method.proto == findLiteExtensionByNumberProto
&& method.name.startsWith(findLiteExtensionByNumberName);
@@ -115,6 +123,7 @@
class GeneratedMessageLiteMethods {
public final DexMethod createBuilderMethod;
+ public final DexMethod dynamicMethodBridgeMethod;
public final DexMethod isInitializedMethod;
private GeneratedMessageLiteMethods(DexItemFactory dexItemFactory) {
@@ -123,6 +132,11 @@
generatedMessageLiteType,
dexItemFactory.createProto(generatedMessageLiteBuilderType),
"createBuilder");
+ dynamicMethodBridgeMethod =
+ dexItemFactory.createMethod(
+ generatedMessageLiteType,
+ dexItemFactory.createProto(dexItemFactory.objectType, methodToInvokeType),
+ "dynamicMethod");
isInitializedMethod =
dexItemFactory.createMethod(
generatedMessageLiteType,
@@ -134,6 +148,7 @@
class GeneratedMessageLiteBuilderMethods {
public final DexMethod buildPartialMethod;
+ public final DexMethod constructorMethod;
private GeneratedMessageLiteBuilderMethods(DexItemFactory dexItemFactory) {
buildPartialMethod =
@@ -141,6 +156,11 @@
generatedMessageLiteBuilderType,
dexItemFactory.createProto(generatedMessageLiteType),
"buildPartial");
+ constructorMethod =
+ dexItemFactory.createMethod(
+ generatedMessageLiteBuilderType,
+ dexItemFactory.createProto(dexItemFactory.voidType, generatedMessageLiteType),
+ dexItemFactory.constructorMethodName);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
index 189bb92..c7939b5 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
@@ -56,6 +56,9 @@
process(executorService);
assert verifyAllMethodsWithCodeExists();
+ appView.withGeneratedMessageLiteBuilderShrinker(
+ shrinker -> shrinker.preprocessCallGraphBeforeCycleElimination(nodes));
+
timing.begin("Cycle elimination");
// Sort the nodes for deterministic cycle elimination.
Set<Node> nodesWithDeterministicOrder = Sets.newTreeSet(nodes.values());
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 7ef6cd5..6233a57 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -470,6 +470,10 @@
return true;
}
+ public DexEncodedMethod getMethod() {
+ return method;
+ }
+
public boolean isDebugMode() {
return appView.options().debug || method.getOptimizationInfo().isReachabilitySensitive();
}
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 939d33a..bdc98f0 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
@@ -29,7 +29,6 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.conversion.IRConverter;
@@ -41,8 +40,7 @@
import com.android.tools.r8.ir.desugar.backports.LongMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.NumericMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.ObjectsMethodRewrites;
-import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
-import com.android.tools.r8.ir.synthetic.SynthesizedCode;
+import com.android.tools.r8.ir.desugar.backports.OptionalMethodRewrites;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
@@ -134,16 +132,12 @@
.appInfo()
.lookupSuperTarget(invoke.getInvokedMethod(), code.method.method.holder);
if (!dexEncodedMethod.isFinal()) { // Final methods can be rewritten as a normal invoke.
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
- appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
- Map<DexType, DexType> typeMap = retargetCoreLibMember.get(dexEncodedMethod.method.name);
- if (typeMap != null && typeMap.containsKey(dexEncodedMethod.method.holder)) {
- DexMethod retargetMethod =
- factory.createMethod(
- typeMap.get(dexEncodedMethod.method.holder),
- factory.prependTypeToProto(
- dexEncodedMethod.method.holder, dexEncodedMethod.method.proto),
- dexEncodedMethod.method.name);
+ DexMethod retargetMethod =
+ appView
+ .options()
+ .desugaredLibraryConfiguration
+ .retargetMethod(dexEncodedMethod.method, appView);
+ if (retargetMethod != null) {
iterator.replaceCurrentInstruction(
new InvokeStatic(retargetMethod, invoke.outValue(), invoke.arguments()));
}
@@ -217,32 +211,17 @@
DexEncodedMethod dexEncodedMethod =
new DexEncodedMethod(
method, flags, DexAnnotationSet.empty(), ParameterAnnotationsList.empty(), code);
- DexProgramClass utilityClass =
- new DexProgramClass(
- method.holder,
- null,
- new SynthesizedOrigin("java8 methods utility class", getClass()),
- classAccessFlags,
- factory.objectType,
- DexTypeList.empty(),
- null,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- new DexEncodedMethod[] {dexEncodedMethod},
- DexEncodedMethod.EMPTY_ARRAY,
- factory.getSkipNameValidationForTesting(),
- getChecksumSupplier(dexEncodedMethod),
- referencingClasses);
boolean addToMainDexList =
referencingClasses.stream()
.anyMatch(clazz -> appView.appInfo().isInMainDexList(clazz.type));
- appView.appInfo().addSynthesizedClass(utilityClass);
- builder.addSynthesizedClass(utilityClass, addToMainDexList);
+ DexProgramClass utilityClass =
+ synthesizeClassWithUniqueMethod(
+ builder,
+ classAccessFlags,
+ method.holder,
+ dexEncodedMethod,
+ "java8 methods utility class",
+ addToMainDexList);
// The following may add elements to methodsProviders.
converter.optimizeSynthesizedClass(utilityClass, executorService);
}
@@ -318,27 +297,11 @@
// NOTE: Never add a forwarding method to methods of classes unknown or coming from android.jar
// even if this results in invalid code, these classes are never desugared.
// In desugared library, emulated interface methods can be overridden by retarget lib members.
- DexMethod forwardMethod = ClassProcessor.retargetMethod(appView, target);
- // New method will have the same name, proto, and also all the flags of the
- // default method, including bridge flag.
- DexMethod newMethod =
- appView.dexItemFactory().createMethod(clazz.type, target.proto, target.name);
- DexEncodedMethod dexEncodedMethod = appView.definitionFor(target);
- MethodAccessFlags newFlags = dexEncodedMethod.accessFlags.copy();
- newFlags.setSynthetic();
- ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
- ForwardMethodSourceCode.builder(newMethod);
- forwardSourceCodeBuilder
- .setReceiver(clazz.type)
- .setTarget(forwardMethod)
- .setInvokeType(Invoke.Type.STATIC)
- .setIsInterface(false);
- return new DexEncodedMethod(
- newMethod,
- newFlags,
- dexEncodedMethod.annotations,
- dexEncodedMethod.parameterAnnotationsList,
- new SynthesizedCode(forwardSourceCodeBuilder::build));
+ DexMethod forwardMethod =
+ appView.options().desugaredLibraryConfiguration.retargetMethod(target, appView);
+ assert forwardMethod != null && forwardMethod != target;
+ return DexEncodedMethod.createDesugaringForwardingMethod(
+ appView.definitionFor(target), clazz, forwardMethod, appView.dexItemFactory());
}
private void synthesizeEmulatedDispatchMethods(Builder<?> builder) {
@@ -359,57 +322,63 @@
DexType interfaceType = dispatchInterfaceTypeFor(appView, emulatedDispatchMethod);
DexEncodedMethod itfMethod =
generateInterfaceDispatchMethod(emulatedDispatchMethod, interfaceType);
- DexProgramClass dispatchInterface =
- new DexProgramClass(
- interfaceType,
- null,
- new SynthesizedOrigin("desugared library interface dispatch", getClass()),
- itfAccessFlags,
- factory.objectType,
- DexTypeList.empty(),
- null,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedMethod.EMPTY_ARRAY,
- new DexEncodedMethod[] {itfMethod},
- factory.getSkipNameValidationForTesting(),
- getChecksumSupplier(itfMethod));
- appView.appInfo().addSynthesizedClass(dispatchInterface);
- builder.addSynthesizedClass(dispatchInterface, false);
+ synthesizeClassWithUniqueMethod(
+ builder,
+ itfAccessFlags,
+ interfaceType,
+ itfMethod,
+ "desugared library dispatch interface",
+ false);
// Dispatch holder.
DexType holderType = dispatchHolderTypeFor(appView, emulatedDispatchMethod);
DexEncodedMethod dispatchMethod =
generateHolderDispatchMethod(emulatedDispatchMethod, holderType, itfMethod.method);
- DexProgramClass dispatchHolder =
- new DexProgramClass(
- holderType,
- null,
- new SynthesizedOrigin("desugared library dispatch holder class", getClass()),
- holderAccessFlags,
- factory.objectType,
- DexTypeList.empty(),
- null,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- new DexEncodedMethod[] {dispatchMethod},
- DexEncodedMethod.EMPTY_ARRAY,
- factory.getSkipNameValidationForTesting(),
- getChecksumSupplier(dispatchMethod));
- appView.appInfo().addSynthesizedClass(dispatchHolder);
- builder.addSynthesizedClass(dispatchHolder, false);
+ synthesizeClassWithUniqueMethod(
+ builder,
+ holderAccessFlags,
+ holderType,
+ dispatchMethod,
+ "desugared library dispatch class",
+ false);
}
}
+ private DexProgramClass synthesizeClassWithUniqueMethod(
+ Builder<?> builder,
+ ClassAccessFlags accessFlags,
+ DexType type,
+ DexEncodedMethod uniqueMethod,
+ String origin,
+ boolean addToMainDexList) {
+ DexProgramClass newClass =
+ new DexProgramClass(
+ type,
+ null,
+ new SynthesizedOrigin(origin, getClass()),
+ accessFlags,
+ factory.objectType,
+ DexTypeList.empty(),
+ null,
+ null,
+ Collections.emptyList(),
+ null,
+ Collections.emptyList(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ uniqueMethod.isStatic()
+ ? new DexEncodedMethod[] {uniqueMethod}
+ : DexEncodedMethod.EMPTY_ARRAY,
+ uniqueMethod.isStatic()
+ ? DexEncodedMethod.EMPTY_ARRAY
+ : new DexEncodedMethod[] {uniqueMethod},
+ factory.getSkipNameValidationForTesting(),
+ getChecksumSupplier(uniqueMethod));
+ appView.appInfo().addSynthesizedClass(newClass);
+ builder.addSynthesizedClass(newClass, addToMainDexList);
+ return newClass;
+ }
+
private DexEncodedMethod generateInterfaceDispatchMethod(
DexMethod emulatedDispatchMethod, DexType interfaceType) {
MethodAccessFlags flags =
@@ -433,20 +402,16 @@
// }
// We do not deal with complex cases (multiple retargeting of the same signature in the
// same inheritance tree, etc., since they do not happen in the most common desugared library.
- DexItemFactory factory = appView.dexItemFactory();
- DexProto newProto =
- factory.prependTypeToProto(emulatedDispatchMethod.holder, emulatedDispatchMethod.proto);
- DexMethod newMethod =
- factory.createMethod(dispatchHolder, newProto, emulatedDispatchMethod.name);
- DexType desugarType =
+ DexMethod desugarMethod =
appView
.options()
.desugaredLibraryConfiguration
- .getRetargetCoreLibMember()
- .get(emulatedDispatchMethod.name)
- .get(emulatedDispatchMethod.holder);
- DexMethod desugarMethod =
- factory.createMethod(desugarType, newProto, emulatedDispatchMethod.name);
+ .retargetMethod(emulatedDispatchMethod, appView);
+ assert desugarMethod != null; // This method is reached only for retarget core lib members.
+ DexMethod newMethod =
+ appView
+ .dexItemFactory()
+ .createMethod(dispatchHolder, desugarMethod.proto, emulatedDispatchMethod.name);
return DexEncodedMethod.toEmulateDispatchLibraryMethod(
emulatedDispatchMethod.holder,
newMethod,
@@ -540,7 +505,9 @@
// we do not desugar to avoid confusion in error messages.
if (appView.rewritePrefix.hasRewrittenType(factory.optionalType)
|| options.minApiLevel >= AndroidApiLevel.N.getLevel()) {
- initializeOptionalMethodProviders(factory);
+ initializeJava9OptionalMethodProviders(factory);
+ initializeJava10OptionalMethodProviders(factory);
+ initializeJava11OptionalMethodProviders(factory);
}
if (appView.rewritePrefix.hasRewrittenType(factory.streamType)
|| options.minApiLevel >= AndroidApiLevel.N.getLevel()) {
@@ -549,6 +516,7 @@
// These are currently not implemented at any API level in Android.
initializeJava9MethodProviders(factory);
+ initializeJava10MethodProviders(factory);
initializeJava11MethodProviders(factory);
if (!options.desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) {
@@ -1241,6 +1209,24 @@
BackportedMethods::MathMethods_multiplyExactLongInt,
"multiplyExactLongInt"));
+ // long {Math,StrictMath}.multiplyFull(int, int)
+ name = factory.createString("multiplyFull");
+ proto = factory.createProto(factory.longType, factory.intType, factory.intType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method,
+ BackportedMethods::MathMethods_multiplyFull));
+
+ // long {Math,StrictMath}.multiplyHigh(long, long)
+ name = factory.createString("multiplyHigh");
+ proto = factory.createProto(factory.longType, factory.longType, factory.longType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method,
+ BackportedMethods::MathMethods_multiplyHigh));
+
// long {Math,StrictMath}.floorDiv(long, int)
name = factory.createString("floorDiv");
proto = factory.createProto(factory.longType, factory.longType, factory.intType);
@@ -1385,6 +1371,41 @@
addProvider(new MethodGenerator(method, BackportedMethods::CollectionMethods_mapEntry));
}
+ private void initializeJava10MethodProviders(DexItemFactory factory) {
+ // List
+ DexType type = factory.listType;
+
+ // List List.copyOf(Collection)
+ DexString name = factory.createString("copyOf");
+ DexProto proto = factory.createProto(factory.listType, factory.collectionType);
+ DexMethod method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method, BackportedMethods::CollectionsMethods_copyOfList, "copyOfList"));
+
+ // Set
+ type = factory.setType;
+
+ // Set Set.copyOf(Collection)
+ name = factory.createString("copyOf");
+ proto = factory.createProto(factory.setType, factory.collectionType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method, BackportedMethods::CollectionsMethods_copyOfSet, "copyOfSet"));
+
+ // Set
+ type = factory.mapType;
+
+ // Map Map.copyOf(Map)
+ name = factory.createString("copyOf");
+ proto = factory.createProto(factory.mapType, factory.mapType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method, BackportedMethods::CollectionsMethods_copyOfMap, "copyOfMap"));
+ }
+
private void initializeJava11MethodProviders(DexItemFactory factory) {
// Character
DexType type = factory.boxedCharType;
@@ -1398,7 +1419,7 @@
method, BackportedMethods::CharacterMethods_toStringCodepoint, "toStringCodepoint"));
}
- private void initializeOptionalMethodProviders(DexItemFactory factory) {
+ private void initializeJava9OptionalMethodProviders(DexItemFactory factory) {
// Optional
DexType optionalType = factory.optionalType;
@@ -1410,22 +1431,40 @@
new StatifyingMethodGenerator(
method, BackportedMethods::OptionalMethods_or, "or", optionalType));
- // Optional.stream()
+ // Optional{void,Int,Long,Double}.stream()
+ DexType[] optionalTypes =
+ new DexType[] {
+ optionalType,
+ factory.optionalDoubleType,
+ factory.optionalLongType,
+ factory.optionalIntType,
+ };
+ DexType[] streamReturnTypes =
+ new DexType[] {
+ factory.streamType,
+ factory.createType(factory.createString("Ljava/util/stream/DoubleStream;")),
+ factory.createType(factory.createString("Ljava/util/stream/LongStream;")),
+ factory.createType(factory.createString("Ljava/util/stream/IntStream;")),
+ };
+ TemplateMethodFactory[] streamMethodFactories =
+ new TemplateMethodFactory[] {
+ BackportedMethods::OptionalMethods_stream,
+ BackportedMethods::OptionalMethods_streamDouble,
+ BackportedMethods::OptionalMethods_streamLong,
+ BackportedMethods::OptionalMethods_streamInt,
+ };
name = factory.createString("stream");
- proto = factory.createProto(factory.streamType);
- method = factory.createMethod(optionalType, proto, name);
- addProvider(
- new StatifyingMethodGenerator(
- method, BackportedMethods::OptionalMethods_stream, "stream", optionalType));
+ for (int i = 0; i < optionalTypes.length; i++) {
+ DexType optional = optionalTypes[i];
+ DexType streamReturnType = streamReturnTypes[i];
+ proto = factory.createProto(streamReturnType);
+ method = factory.createMethod(optional, proto, name);
+ addProvider(
+ new StatifyingMethodGenerator(
+ method, streamMethodFactories[i], "stream", optional));
+ }
// Optional{void,Int,Long,Double}.ifPresentOrElse(consumer,runnable)
- DexType[] optionalTypes =
- new DexType[]{
- optionalType,
- factory.createType(factory.createString("Ljava/util/OptionalDouble;")),
- factory.createType(factory.createString("Ljava/util/OptionalLong;")),
- factory.createType(factory.createString("Ljava/util/OptionalInt;"))
- };
DexType[] consumerTypes =
new DexType[]{
factory.consumerType,
@@ -1451,6 +1490,63 @@
}
}
+ private void initializeJava10OptionalMethodProviders(DexItemFactory factory) {
+ // Optional{void,Int,Long,Double}.orElseThrow()
+ DexType[] optionalTypes =
+ new DexType[] {
+ factory.optionalType,
+ factory.optionalDoubleType,
+ factory.optionalLongType,
+ factory.optionalIntType,
+ };
+ DexType[] returnTypes =
+ new DexType[] {
+ factory.objectType,
+ factory.doubleType,
+ factory.longType,
+ factory.intType,
+ };
+ MethodInvokeRewriter[] rewriters =
+ new MethodInvokeRewriter[] {
+ OptionalMethodRewrites::rewriteOrElseGet,
+ OptionalMethodRewrites::rewriteDoubleOrElseGet,
+ OptionalMethodRewrites::rewriteLongOrElseGet,
+ OptionalMethodRewrites::rewriteIntOrElseGet,
+ };
+ DexString name = factory.createString("orElseThrow");
+ for (int i = 0; i < optionalTypes.length; i++) {
+ DexProto proto = factory.createProto(returnTypes[i]);
+ DexMethod method = factory.createMethod(optionalTypes[i], proto, name);
+ addProvider(new InvokeRewriter(method, rewriters[i]));
+ }
+ }
+
+ private void initializeJava11OptionalMethodProviders(DexItemFactory factory) {
+ // Optional{void,Int,Long,Double}.isEmpty()
+ DexType[] optionalTypes =
+ new DexType[] {
+ factory.optionalType,
+ factory.optionalDoubleType,
+ factory.optionalLongType,
+ factory.optionalIntType,
+ };
+ TemplateMethodFactory[] methodFactories =
+ new TemplateMethodFactory[]{
+ BackportedMethods::OptionalMethods_isEmpty,
+ BackportedMethods::OptionalMethods_isEmptyDouble,
+ BackportedMethods::OptionalMethods_isEmptyLong,
+ BackportedMethods::OptionalMethods_isEmptyInt
+ };
+ DexString name = factory.createString("isEmpty");
+ for (int i = 0; i < optionalTypes.length; i++) {
+ DexType optionalType = optionalTypes[i];
+ DexProto proto = factory.createProto(factory.booleanType);
+ DexMethod method = factory.createMethod(optionalType, proto, name);
+ addProvider(
+ new StatifyingMethodGenerator(method, methodFactories[i], "isEmpty", optionalType));
+ }
+ }
+
private void initializeStreamMethodProviders(DexItemFactory factory) {
// Stream
DexType streamType = factory.streamType;
@@ -1461,7 +1557,7 @@
DexMethod method = factory.createMethod(streamType, proto, name);
addProvider(
new MethodGenerator(
- method, BackportedMethods::StreamMethods_ofNullable, "ofNullable") {});
+ method, BackportedMethods::StreamMethods_ofNullable, "ofNullable"));
}
private void warnMissingRetargetCoreLibraryMember(DexType type, AppView<?> 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 c2f5ae9..f4fbdde 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
@@ -12,15 +12,12 @@
import com.android.tools.r8.graph.DexLibraryClass;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.graph.ResolutionResult.IncompatibleClassResult;
-import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.synthetic.ExceptionThrowingSourceCode;
-import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.google.common.base.Equivalence.Wrapper;
@@ -50,6 +47,7 @@
// Collection for method signatures that may cause forwarding methods to be created.
private static class MethodSignatures {
+
static final MethodSignatures EMPTY = new MethodSignatures(Collections.emptySet());
static MethodSignatures create(Set<Wrapper<DexMethod>> signatures) {
@@ -125,6 +123,7 @@
// Helper to keep track of the direct active subclass and nearest program subclass for reporting.
private static class ReportingContext {
+
final DexClass directSubClass;
final DexProgramClass closestProgramSubClass;
@@ -156,6 +155,7 @@
// Specialized context to disable reporting when traversing the library strucure.
private static class LibraryReportingContext extends ReportingContext {
+
static final LibraryReportingContext LIBRARY_CONTEXT = new LibraryReportingContext();
LibraryReportingContext() {
@@ -340,13 +340,8 @@
if (method.isFinal()) {
return false;
}
- Map<DexType, DexType> typeMap =
- appView
- .options()
- .desugaredLibraryConfiguration
- .getRetargetCoreLibMember()
- .get(method.method.name);
- return typeMap != null && typeMap.containsKey(holder.type);
+ return appView.options().desugaredLibraryConfiguration.retargetMethod(method.method, appView)
+ != null;
}
private boolean dontRewrite(DexClass clazz, DexEncodedMethod method) {
@@ -391,42 +386,11 @@
DexMethod forwardMethod =
targetHolder.isInterface()
? rewriter.defaultAsMethodOfCompanionClass(method)
- : retargetMethod(appView, method);
- // New method will have the same name, proto, and also all the flags of the
- // default method, including bridge flag.
- DexMethod newMethod = dexItemFactory.createMethod(clazz.type, method.proto, method.name);
- MethodAccessFlags newFlags = target.accessFlags.copy();
- // Some debuggers (like IntelliJ) automatically skip synthetic methods on single step.
- newFlags.setSynthetic();
- ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
- ForwardMethodSourceCode.builder(newMethod);
- forwardSourceCodeBuilder
- .setReceiver(clazz.type)
- .setTarget(forwardMethod)
- .setInvokeType(Invoke.Type.STATIC)
- .setIsInterface(false); // Holder is companion class, not an interface.
- DexEncodedMethod newEncodedMethod =
- new DexEncodedMethod(
- newMethod,
- newFlags,
- target.annotations,
- target.parameterAnnotationsList,
- new SynthesizedCode(forwardSourceCodeBuilder::build));
- addSyntheticMethod(clazz.asProgramClass(), newEncodedMethod);
- }
-
- static DexMethod retargetMethod(AppView<?> appView, DexMethod method) {
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
- appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
- Map<DexType, DexType> typeMap = retargetCoreLibMember.get(method.name);
- assert typeMap != null;
- assert typeMap.get(method.holder) != null;
- return appView
- .dexItemFactory()
- .createMethod(
- typeMap.get(method.holder),
- appView.dexItemFactory().prependTypeToProto(method.holder, method.proto),
- method.name);
+ : appView.options().desugaredLibraryConfiguration.retargetMethod(method, appView);
+ DexEncodedMethod desugaringForwardingMethod =
+ DexEncodedMethod.createDesugaringForwardingMethod(
+ target, clazz, forwardMethod, dexItemFactory);
+ addSyntheticMethod(clazz.asProgramClass(), desugaringForwardingMethod);
}
// Topological order traversal and its helpers.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
index 68a8bd4..e4af36c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
@@ -62,7 +62,7 @@
InstructionListIterator instructions = block.listIterator(code);
while (instructions.hasNext()) {
Instruction instruction = instructions.next();
- if (instruction.isInvokeMethod() && !instruction.isInvokeSuper()) {
+ if (instruction.isInvokeMethod()) {
InvokeMethod invokeMethod = instruction.asInvokeMethod();
DexMethod methodCalled = invokeMethod.getInvokedMethod();
DexEncodedMethod encodedMethodCalled =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
index fd954e5..3d0a59c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.DesugarPrefixRewritingMapper;
@@ -126,6 +127,20 @@
return emulateLibraryInterface;
}
+ // If the method is retargeted, answers the retargeted method, else null.
+ public DexMethod retargetMethod(DexMethod method, AppView<?> appView) {
+ Map<DexType, DexType> typeMap = retargetCoreLibMember.get(method.name);
+ if (typeMap != null && typeMap.containsKey(method.holder)) {
+ return appView
+ .dexItemFactory()
+ .createMethod(
+ typeMap.get(method.holder),
+ appView.dexItemFactory().prependTypeToProto(method.holder, method.proto),
+ method.name);
+ }
+ return null;
+ }
+
public Map<DexString, Map<DexType, DexType>> getRetargetCoreLibMember() {
return retargetCoreLibMember;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
index c9bd364..e3e7ab0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
@@ -395,6 +395,8 @@
MethodAccessFlags newFlags = template.accessFlags.copy();
assert newFlags.isPublic();
newFlags.unsetAbstract();
+ // TODO(b/146114533): Fix inlining in synthetic methods and remove unsetBridge.
+ newFlags.unsetBridge();
newFlags.setSynthetic();
return new DexEncodedMethod(
methodToInstall,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 679f927..a43d321 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -25,7 +25,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.ir.code.BasicBlock;
@@ -38,6 +37,7 @@
import com.android.tools.r8.ir.code.InvokeSuper;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.desugar.DefaultMethodsHelper.Collection;
+import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLense;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.position.MethodPosition;
@@ -288,11 +288,10 @@
// Rewriting is required because the super invoke resolves into a missing
// method (method is on desugared library). Find out if it needs to be
// retarget or if it just calls a companion class method and rewrite.
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
- options.desugaredLibraryConfiguration.getRetargetCoreLibMember();
- Map<DexType, DexType> typeMap =
- retargetCoreLibMember.get(dexEncodedMethod.method.name);
- if (typeMap == null || !typeMap.containsKey(dexEncodedMethod.method.holder)) {
+ DexMethod retargetMethod =
+ options.desugaredLibraryConfiguration.retargetMethod(
+ dexEncodedMethod.method, appView);
+ if (retargetMethod == null) {
DexMethod originalCompanionMethod =
instanceAsMethodOfCompanionClass(
dexEncodedMethod.method, DEFAULT_METHOD_PREFIX, factory);
@@ -306,12 +305,6 @@
new InvokeStatic(
companionMethod, invokeSuper.outValue(), invokeSuper.arguments()));
} else {
- DexMethod retargetMethod =
- factory.createMethod(
- typeMap.get(dexEncodedMethod.method.holder),
- factory.prependTypeToProto(
- dexEncodedMethod.method.holder, dexEncodedMethod.method.proto),
- dexEncodedMethod.method.name);
instructions.replaceCurrentInstruction(
new InvokeStatic(
retargetMethod, invokeSuper.outValue(), invokeSuper.arguments()));
@@ -964,7 +957,7 @@
}
private Map<DexType, DexProgramClass> processInterfaces(Builder<?> builder, Flavor flavour) {
- NestedGraphLense.Builder graphLensBuilder = GraphLense.builder();
+ NestedGraphLense.Builder graphLensBuilder = InterfaceProcessorNestedGraphLense.builder();
InterfaceProcessor processor = new InterfaceProcessor(appView, this);
for (DexProgramClass clazz : builder.getProgramClasses()) {
if (shouldProcess(clazz, flavour, true)) {
@@ -1058,6 +1051,7 @@
// they are in the desugared library.
if (appView.rewritePrefix.hasRewrittenType(missing)
|| DesugaredLibraryWrapperSynthesizer.isSynthesizedWrapper(missing)
+ || isCompanionClassType(missing)
|| appView
.options()
.desugaredLibraryConfiguration
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 1c20983..787fbe1 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
@@ -18,12 +18,15 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexLibraryClass;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProgramClass.ChecksumSupplier;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
@@ -31,6 +34,7 @@
import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
import com.android.tools.r8.origin.SynthesizedOrigin;
+import com.google.common.collect.BiMap;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
@@ -341,4 +345,53 @@
}
return method.accessFlags.isStatic() && !rewriter.factory.isClassConstructor(method.method);
}
+
+ // Specific lens which remaps invocation types to static since all rewrites performed here
+ // are to static companion methods.
+ public static class InterfaceProcessorNestedGraphLense extends NestedGraphLense {
+
+ public InterfaceProcessorNestedGraphLense(
+ Map<DexType, DexType> typeMap,
+ Map<DexMethod, DexMethod> methodMap,
+ Map<DexField, DexField> fieldMap,
+ BiMap<DexField, DexField> originalFieldSignatures,
+ BiMap<DexMethod, DexMethod> originalMethodSignatures,
+ GraphLense previousLense,
+ DexItemFactory dexItemFactory) {
+ super(
+ typeMap,
+ methodMap,
+ fieldMap,
+ originalFieldSignatures,
+ originalMethodSignatures,
+ previousLense,
+ dexItemFactory);
+ }
+
+ @Override
+ protected Type mapInvocationType(DexMethod newMethod, DexMethod originalMethod, Type type) {
+ return Type.STATIC;
+ }
+
+ public static GraphLense.Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder extends NestedGraphLense.Builder {
+ @Override
+ public GraphLense build(DexItemFactory dexItemFactory, GraphLense previousLense) {
+ if (originalFieldSignatures.isEmpty() && originalMethodSignatures.isEmpty()) {
+ return previousLense;
+ }
+ return new InterfaceProcessorNestedGraphLense(
+ typeMap,
+ methodMap,
+ fieldMap,
+ originalFieldSignatures,
+ originalMethodSignatures,
+ previousLense,
+ dexItemFactory);
+ }
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
index ff95053..30edf6a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
@@ -385,8 +385,7 @@
@Override
public boolean registerInvokeSuper(DexMethod method) {
- // Cannot target private method.
- return false;
+ return registerInvoke(method, Invoke.Type.SUPER);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
index ddfb1c5..8440fc2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -958,6 +958,363 @@
ImmutableList.of());
}
+ public static CfCode CollectionsMethods_copyOfList(InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ CfLabel label4 = new CfLabel();
+ CfLabel label5 = new CfLabel();
+ CfLabel label6 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 3,
+ 4,
+ ImmutableList.of(
+ label0,
+ new CfNew(options.itemFactory.createType("Ljava/util/ArrayList;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Collection;"),
+ options.itemFactory.createProto(options.itemFactory.createType("I")),
+ options.itemFactory.createString("size")),
+ true),
+ new CfInvoke(
+ 183,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/ArrayList;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("V"), options.itemFactory.createType("I")),
+ options.itemFactory.createString("<init>")),
+ false),
+ new CfStore(ValueType.OBJECT, 1),
+ label1,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Collection;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/Iterator;")),
+ options.itemFactory.createString("iterator")),
+ true),
+ new CfStore(ValueType.OBJECT, 2),
+ label2,
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Iterator;"),
+ options.itemFactory.createProto(options.itemFactory.createType("Z")),
+ options.itemFactory.createString("hasNext")),
+ true),
+ new CfIf(If.Type.EQ, ValueType.INT, label5),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Iterator;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("next")),
+ true),
+ new CfStore(ValueType.OBJECT, 3),
+ label3,
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfLoad(ValueType.OBJECT, 3),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Objects;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/Object;"),
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("requireNonNull")),
+ false),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/ArrayList;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Z"),
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("add")),
+ false),
+ new CfStackInstruction(CfStackInstruction.Opcode.Pop),
+ label4,
+ new CfGoto(label2),
+ label5,
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Collections;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/List;"),
+ options.itemFactory.createType("Ljava/util/List;")),
+ options.itemFactory.createString("unmodifiableList")),
+ false),
+ new CfReturn(ValueType.OBJECT),
+ label6),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode CollectionsMethods_copyOfMap(InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ CfLabel label4 = new CfLabel();
+ CfLabel label5 = new CfLabel();
+ CfLabel label6 = new CfLabel();
+ CfLabel label7 = new CfLabel();
+ CfLabel label8 = new CfLabel();
+ CfLabel label9 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 3,
+ 4,
+ ImmutableList.of(
+ label0,
+ new CfNew(options.itemFactory.createType("Ljava/util/HashMap;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Map;"),
+ options.itemFactory.createProto(options.itemFactory.createType("I")),
+ options.itemFactory.createString("size")),
+ true),
+ new CfInvoke(
+ 183,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/HashMap;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("V"), options.itemFactory.createType("I")),
+ options.itemFactory.createString("<init>")),
+ false),
+ new CfStore(ValueType.OBJECT, 1),
+ label1,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Map;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/Set;")),
+ options.itemFactory.createString("entrySet")),
+ true),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Set;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/Iterator;")),
+ options.itemFactory.createString("iterator")),
+ true),
+ new CfStore(ValueType.OBJECT, 2),
+ label2,
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Iterator;"),
+ options.itemFactory.createProto(options.itemFactory.createType("Z")),
+ options.itemFactory.createString("hasNext")),
+ true),
+ new CfIf(If.Type.EQ, ValueType.INT, label8),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Iterator;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("next")),
+ true),
+ new CfCheckCast(options.itemFactory.createType("Ljava/util/Map$Entry;")),
+ new CfStore(ValueType.OBJECT, 3),
+ label3,
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfLoad(ValueType.OBJECT, 3),
+ label4,
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Map$Entry;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("getKey")),
+ true),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Objects;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/Object;"),
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("requireNonNull")),
+ false),
+ new CfLoad(ValueType.OBJECT, 3),
+ label5,
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Map$Entry;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("getValue")),
+ true),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Objects;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/Object;"),
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("requireNonNull")),
+ false),
+ label6,
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/HashMap;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/Object;"),
+ options.itemFactory.createType("Ljava/lang/Object;"),
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("put")),
+ false),
+ new CfStackInstruction(CfStackInstruction.Opcode.Pop),
+ label7,
+ new CfGoto(label2),
+ label8,
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Collections;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/Map;"),
+ options.itemFactory.createType("Ljava/util/Map;")),
+ options.itemFactory.createString("unmodifiableMap")),
+ false),
+ new CfReturn(ValueType.OBJECT),
+ label9),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode CollectionsMethods_copyOfSet(InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ CfLabel label4 = new CfLabel();
+ CfLabel label5 = new CfLabel();
+ CfLabel label6 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 3,
+ 4,
+ ImmutableList.of(
+ label0,
+ new CfNew(options.itemFactory.createType("Ljava/util/HashSet;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Collection;"),
+ options.itemFactory.createProto(options.itemFactory.createType("I")),
+ options.itemFactory.createString("size")),
+ true),
+ new CfInvoke(
+ 183,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/HashSet;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("V"), options.itemFactory.createType("I")),
+ options.itemFactory.createString("<init>")),
+ false),
+ new CfStore(ValueType.OBJECT, 1),
+ label1,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Collection;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/Iterator;")),
+ options.itemFactory.createString("iterator")),
+ true),
+ new CfStore(ValueType.OBJECT, 2),
+ label2,
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Iterator;"),
+ options.itemFactory.createProto(options.itemFactory.createType("Z")),
+ options.itemFactory.createString("hasNext")),
+ true),
+ new CfIf(If.Type.EQ, ValueType.INT, label5),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Iterator;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("next")),
+ true),
+ new CfStore(ValueType.OBJECT, 3),
+ label3,
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfLoad(ValueType.OBJECT, 3),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Objects;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/lang/Object;"),
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("requireNonNull")),
+ false),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/HashSet;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Z"),
+ options.itemFactory.createType("Ljava/lang/Object;")),
+ options.itemFactory.createString("add")),
+ false),
+ new CfStackInstruction(CfStackInstruction.Opcode.Pop),
+ label4,
+ new CfGoto(label2),
+ label5,
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Collections;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/Set;"),
+ options.itemFactory.createType("Ljava/util/Set;")),
+ options.itemFactory.createString("unmodifiableSet")),
+ false),
+ new CfReturn(ValueType.OBJECT),
+ label6),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode CollectionsMethods_emptyEnumeration(
InternalOptions options, DexMethod method) {
CfLabel label0 = new CfLabel();
@@ -3155,6 +3512,130 @@
ImmutableList.of());
}
+ public static CfCode MathMethods_multiplyFull(InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 4,
+ 2,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.INT, 0),
+ new CfNumberConversion(NumericType.INT, NumericType.LONG),
+ new CfLoad(ValueType.INT, 1),
+ new CfNumberConversion(NumericType.INT, NumericType.LONG),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+ new CfReturn(ValueType.LONG),
+ label1),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode MathMethods_multiplyHigh(InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ CfLabel label4 = new CfLabel();
+ CfLabel label5 = new CfLabel();
+ CfLabel label6 = new CfLabel();
+ CfLabel label7 = new CfLabel();
+ CfLabel label8 = new CfLabel();
+ CfLabel label9 = new CfLabel();
+ CfLabel label10 = new CfLabel();
+ CfLabel label11 = new CfLabel();
+ CfLabel label12 = new CfLabel();
+ CfLabel label13 = new CfLabel();
+ CfLabel label14 = new CfLabel();
+ CfLabel label15 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 4,
+ 32,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.LONG, 0),
+ new CfConstNumber(4294967295L, ValueType.LONG),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.LONG),
+ new CfStore(ValueType.LONG, 4),
+ label1,
+ new CfLoad(ValueType.LONG, 0),
+ new CfConstNumber(32, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+ new CfStore(ValueType.LONG, 6),
+ label2,
+ new CfLoad(ValueType.LONG, 2),
+ new CfConstNumber(4294967295L, ValueType.LONG),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.LONG),
+ new CfStore(ValueType.LONG, 8),
+ label3,
+ new CfLoad(ValueType.LONG, 2),
+ new CfConstNumber(32, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+ new CfStore(ValueType.LONG, 10),
+ label4,
+ new CfLoad(ValueType.LONG, 4),
+ new CfLoad(ValueType.LONG, 8),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+ new CfStore(ValueType.LONG, 12),
+ label5,
+ new CfLoad(ValueType.LONG, 12),
+ new CfConstNumber(32, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Ushr, NumericType.LONG),
+ new CfStore(ValueType.LONG, 14),
+ label6,
+ new CfLoad(ValueType.LONG, 6),
+ new CfLoad(ValueType.LONG, 8),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+ new CfStore(ValueType.LONG, 16),
+ label7,
+ new CfLoad(ValueType.LONG, 16),
+ new CfLoad(ValueType.LONG, 14),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+ new CfStore(ValueType.LONG, 18),
+ label8,
+ new CfLoad(ValueType.LONG, 18),
+ new CfConstNumber(4294967295L, ValueType.LONG),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.LONG),
+ new CfStore(ValueType.LONG, 20),
+ label9,
+ new CfLoad(ValueType.LONG, 18),
+ new CfConstNumber(32, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+ new CfStore(ValueType.LONG, 22),
+ label10,
+ new CfLoad(ValueType.LONG, 4),
+ new CfLoad(ValueType.LONG, 10),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+ new CfStore(ValueType.LONG, 24),
+ label11,
+ new CfLoad(ValueType.LONG, 24),
+ new CfLoad(ValueType.LONG, 20),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+ new CfStore(ValueType.LONG, 26),
+ label12,
+ new CfLoad(ValueType.LONG, 26),
+ new CfConstNumber(32, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+ new CfStore(ValueType.LONG, 28),
+ label13,
+ new CfLoad(ValueType.LONG, 6),
+ new CfLoad(ValueType.LONG, 10),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+ new CfStore(ValueType.LONG, 30),
+ label14,
+ new CfLoad(ValueType.LONG, 30),
+ new CfLoad(ValueType.LONG, 22),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+ new CfLoad(ValueType.LONG, 28),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+ new CfReturn(ValueType.LONG),
+ label15),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode MathMethods_negateExactInt(InternalOptions options, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
@@ -4689,6 +5170,130 @@
ImmutableList.of());
}
+ public static CfCode OptionalMethods_isEmpty(InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 1,
+ 1,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/Optional;"),
+ options.itemFactory.createProto(options.itemFactory.createType("Z")),
+ options.itemFactory.createString("isPresent")),
+ false),
+ new CfIf(If.Type.NE, ValueType.INT, label1),
+ new CfConstNumber(1, ValueType.INT),
+ new CfGoto(label2),
+ label1,
+ new CfConstNumber(0, ValueType.INT),
+ label2,
+ new CfReturn(ValueType.INT),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode OptionalMethods_isEmptyDouble(InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 1,
+ 1,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/OptionalDouble;"),
+ options.itemFactory.createProto(options.itemFactory.createType("Z")),
+ options.itemFactory.createString("isPresent")),
+ false),
+ new CfIf(If.Type.NE, ValueType.INT, label1),
+ new CfConstNumber(1, ValueType.INT),
+ new CfGoto(label2),
+ label1,
+ new CfConstNumber(0, ValueType.INT),
+ label2,
+ new CfReturn(ValueType.INT),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode OptionalMethods_isEmptyInt(InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 1,
+ 1,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/OptionalInt;"),
+ options.itemFactory.createProto(options.itemFactory.createType("Z")),
+ options.itemFactory.createString("isPresent")),
+ false),
+ new CfIf(If.Type.NE, ValueType.INT, label1),
+ new CfConstNumber(1, ValueType.INT),
+ new CfGoto(label2),
+ label1,
+ new CfConstNumber(0, ValueType.INT),
+ label2,
+ new CfReturn(ValueType.INT),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode OptionalMethods_isEmptyLong(InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 1,
+ 1,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/OptionalLong;"),
+ options.itemFactory.createProto(options.itemFactory.createType("Z")),
+ options.itemFactory.createString("isPresent")),
+ false),
+ new CfIf(If.Type.NE, ValueType.INT, label1),
+ new CfConstNumber(1, ValueType.INT),
+ new CfGoto(label2),
+ label1,
+ new CfConstNumber(0, ValueType.INT),
+ label2,
+ new CfReturn(ValueType.INT),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode OptionalMethods_or(InternalOptions options, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
@@ -4811,6 +5416,168 @@
ImmutableList.of());
}
+ public static CfCode OptionalMethods_streamDouble(InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 2,
+ 1,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/OptionalDouble;"),
+ options.itemFactory.createProto(options.itemFactory.createType("Z")),
+ options.itemFactory.createString("isPresent")),
+ false),
+ new CfIf(If.Type.EQ, ValueType.INT, label2),
+ label1,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/OptionalDouble;"),
+ options.itemFactory.createProto(options.itemFactory.createType("D")),
+ options.itemFactory.createString("getAsDouble")),
+ false),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/stream/DoubleStream;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/stream/DoubleStream;"),
+ options.itemFactory.createType("D")),
+ options.itemFactory.createString("of")),
+ true),
+ new CfReturn(ValueType.OBJECT),
+ label2,
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/stream/DoubleStream;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/stream/DoubleStream;")),
+ options.itemFactory.createString("empty")),
+ true),
+ new CfReturn(ValueType.OBJECT),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode OptionalMethods_streamInt(InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 1,
+ 1,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/OptionalInt;"),
+ options.itemFactory.createProto(options.itemFactory.createType("Z")),
+ options.itemFactory.createString("isPresent")),
+ false),
+ new CfIf(If.Type.EQ, ValueType.INT, label2),
+ label1,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/OptionalInt;"),
+ options.itemFactory.createProto(options.itemFactory.createType("I")),
+ options.itemFactory.createString("getAsInt")),
+ false),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/stream/IntStream;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/stream/IntStream;"),
+ options.itemFactory.createType("I")),
+ options.itemFactory.createString("of")),
+ true),
+ new CfReturn(ValueType.OBJECT),
+ label2,
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/stream/IntStream;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/stream/IntStream;")),
+ options.itemFactory.createString("empty")),
+ true),
+ new CfReturn(ValueType.OBJECT),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode OptionalMethods_streamLong(InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 2,
+ 1,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/OptionalLong;"),
+ options.itemFactory.createProto(options.itemFactory.createType("Z")),
+ options.itemFactory.createString("isPresent")),
+ false),
+ new CfIf(If.Type.EQ, ValueType.INT, label2),
+ label1,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/OptionalLong;"),
+ options.itemFactory.createProto(options.itemFactory.createType("J")),
+ options.itemFactory.createString("getAsLong")),
+ false),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/stream/LongStream;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/stream/LongStream;"),
+ options.itemFactory.createType("J")),
+ options.itemFactory.createString("of")),
+ true),
+ new CfReturn(ValueType.OBJECT),
+ label2,
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/stream/LongStream;"),
+ options.itemFactory.createProto(
+ options.itemFactory.createType("Ljava/util/stream/LongStream;")),
+ options.itemFactory.createString("empty")),
+ true),
+ new CfReturn(ValueType.OBJECT),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode ShortMethods_compare(InternalOptions options, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/OptionalMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/OptionalMethodRewrites.java
new file mode 100644
index 0000000..7965b0b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/OptionalMethodRewrites.java
@@ -0,0 +1,47 @@
+// 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.ir.desugar.backports;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeVirtual;
+
+public final class OptionalMethodRewrites {
+
+ private OptionalMethodRewrites() {}
+
+ public static void rewriteOrElseGet(
+ InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+ InvokeVirtual getInvoke = new InvokeVirtual(
+ factory.createMethod(factory.optionalType, invoke.getInvokedMethod().proto,
+ "get"), invoke.outValue(), invoke.inValues());
+ iterator.replaceCurrentInstruction(getInvoke);
+ }
+
+ public static void rewriteDoubleOrElseGet(
+ InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+ InvokeVirtual getInvoke = new InvokeVirtual(
+ factory.createMethod(factory.optionalDoubleType, invoke.getInvokedMethod().proto,
+ "getAsDouble"), invoke.outValue(), invoke.inValues());
+ iterator.replaceCurrentInstruction(getInvoke);
+ }
+
+ public static void rewriteIntOrElseGet(
+ InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+ InvokeVirtual getInvoke = new InvokeVirtual(
+ factory.createMethod(factory.optionalIntType, invoke.getInvokedMethod().proto,
+ "getAsInt"), invoke.outValue(), invoke.inValues());
+ iterator.replaceCurrentInstruction(getInvoke);
+ }
+
+ public static void rewriteLongOrElseGet(
+ InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+ InvokeVirtual getInvoke = new InvokeVirtual(
+ factory.createMethod(factory.optionalLongType, invoke.getInvokedMethod().proto,
+ "getAsLong"), invoke.outValue(), invoke.inValues());
+ iterator.replaceCurrentInstruction(getInvoke);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index d26e953..6de35d0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -971,6 +971,7 @@
classInitializationAnalysis.notifyCodeHasChanged();
strategy.updateTypeInformationIfNeeded(inlinee.code, blockIterator, block);
+ // TODO(b/146114533): Fix inlining in synthetic methods.
// If we inlined the invoke from a bridge method, it is no longer a bridge method.
if (context.accessFlags.isBridge()) {
context.accessFlags.unsetSynthetic();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index 18c56e6..36fd914 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -231,7 +231,10 @@
new ClassInlinerCostAnalysis(
appView, inliningIRProvider, processor.getReceivers().getDefiniteReceiverAliases());
if (costAnalysis.willExceedInstructionBudget(
- code, processor.getDirectInlinees(), processor.getIndirectInlinees())) {
+ code,
+ processor.getEligibleClass(),
+ processor.getDirectInlinees(),
+ processor.getIndirectInlinees())) {
// This root is unlikely to be inlined in the future.
rootsIterator.remove();
continue;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java
index 9b9670e..da76b7b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java
@@ -11,11 +11,13 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.optimize.inliner.InliningIRProvider;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.google.common.collect.Sets;
import java.util.List;
import java.util.Map;
@@ -24,14 +26,14 @@
/** Analysis that estimates the cost of class inlining an object allocation. */
class ClassInlinerCostAnalysis {
- private final AppView<?> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final InliningIRProvider inliningIRProvider;
private final Set<Value> definiteReceiverAliases;
private int estimatedCost = 0;
ClassInlinerCostAnalysis(
- AppView<?> appView,
+ AppView<AppInfoWithLiveness> appView,
InliningIRProvider inliningIRProvider,
Set<Value> definiteReceiverAliases) {
this.appView = appView;
@@ -41,8 +43,13 @@
boolean willExceedInstructionBudget(
IRCode code,
+ DexProgramClass eligibleClass,
Map<InvokeMethod, DexEncodedMethod> directInlinees,
List<DexEncodedMethod> indirectInlinees) {
+ if (appView.appInfo().alwaysClassInline.contains(eligibleClass.type)) {
+ return false;
+ }
+
for (DexEncodedMethod inlinee : indirectInlinees) {
// We do not have the corresponding invoke instruction for the inlinees that are not called
// directly from `code` (these are called indirectly from one of the methods in
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java
index a80a9ec..bf06bc1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java
@@ -4,10 +4,16 @@
package com.android.tools.r8.ir.optimize.classinliner;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.utils.OptionalBool;
+import com.android.tools.r8.utils.Pair;
+import java.util.List;
public class ClassInlinerEligibilityInfo {
+ final List<Pair<Invoke.Type, DexMethod>> callsReceiver;
+
/**
* Set to {@link OptionalBool#TRUE} if the method is guaranteed to return the receiver, {@link
* OptionalBool#FALSE} if the method is guaranteed not to return the receiver, and {@link
@@ -15,7 +21,9 @@
*/
final OptionalBool returnsReceiver;
- public ClassInlinerEligibilityInfo(OptionalBool returnsReceiver) {
+ public ClassInlinerEligibilityInfo(
+ List<Pair<Invoke.Type, DexMethod>> callsReceiver, OptionalBool returnsReceiver) {
+ this.callsReceiver = callsReceiver;
this.returnsReceiver = returnsReceiver;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 9afba98..c522ff3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.optimize.classinliner;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
@@ -13,6 +14,7 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
@@ -85,7 +87,7 @@
private Value eligibleInstance;
private DexType eligibleClass;
- private DexClass eligibleClassDefinition;
+ private DexProgramClass eligibleClassDefinition;
private boolean isDesugaredLambda;
private final Map<InvokeMethodWithReceiver, InliningInfo> methodCallsOnInstance =
@@ -120,6 +122,10 @@
this.receivers = new ClassInlinerReceiverSet(root.outValue());
}
+ DexProgramClass getEligibleClass() {
+ return eligibleClassDefinition;
+ }
+
Map<InvokeMethod, DexEncodedMethod> getDirectInlinees() {
return directInlinees;
}
@@ -165,7 +171,7 @@
isDesugaredLambda = eligibleClassDefinition != null;
}
if (eligibleClassDefinition == null) {
- eligibleClassDefinition = appView.definitionFor(eligibleClass);
+ eligibleClassDefinition = asProgramClassOrNull(appView.definitionFor(eligibleClass));
}
if (eligibleClassDefinition != null) {
return EligibilityStatus.ELIGIBLE;
@@ -328,8 +334,7 @@
&& !invoke.inValues().isEmpty()
&& root.outValue() == invoke.getReceiver();
if (isCorrespondingConstructorCall) {
- InliningInfo inliningInfo =
- isEligibleConstructorCall(invoke, singleTarget, defaultOracle);
+ InliningInfo inliningInfo = isEligibleConstructorCall(invoke, singleTarget);
if (inliningInfo != null) {
methodCallsOnInstance.put(invoke, inliningInfo);
continue;
@@ -670,7 +675,7 @@
}
private InliningInfo isEligibleConstructorCall(
- InvokeDirect invoke, DexEncodedMethod singleTarget, Supplier<InliningOracle> defaultOracle) {
+ InvokeDirect invoke, DexEncodedMethod singleTarget) {
assert appView.dexItemFactory().isConstructor(invoke.getInvokedMethod());
assert isEligibleSingleTarget(singleTarget);
@@ -696,8 +701,9 @@
}
// Check that the `eligibleInstance` does not escape via the constructor.
- ParameterUsage parameterUsage = singleTarget.getOptimizationInfo().getParameterUsages(0);
- if (!isEligibleParameterUsage(parameterUsage, invoke, defaultOracle)) {
+ InstanceInitializerInfo instanceInitializerInfo =
+ singleTarget.getOptimizationInfo().getInstanceInitializerInfo();
+ if (instanceInitializerInfo.receiverMayEscapeOutsideConstructorChain()) {
return null;
}
@@ -709,7 +715,7 @@
// Check that the entire constructor chain can be inlined into the current context.
DexItemFactory dexItemFactory = appView.dexItemFactory();
- DexMethod parent = singleTarget.getOptimizationInfo().getInstanceInitializerInfo().getParent();
+ DexMethod parent = instanceInitializerInfo.getParent();
while (parent != dexItemFactory.objectMethods.constructor) {
if (parent == null) {
return null;
@@ -728,9 +734,7 @@
parent = encodedParent.getOptimizationInfo().getInstanceInitializerInfo().getParent();
}
- return singleTarget.getOptimizationInfo().getClassInlinerEligibility() != null
- ? new InliningInfo(singleTarget, eligibleClass)
- : null;
+ return new InliningInfo(singleTarget, eligibleClass);
}
// An invoke is eligible for inlining in the following cases:
@@ -870,7 +874,7 @@
MethodOptimizationInfo optimizationInfo = singleTarget.getOptimizationInfo();
ClassInlinerEligibilityInfo eligibility = optimizationInfo.getClassInlinerEligibility();
- if (eligibility == null) {
+ if (eligibility == null || !eligibility.callsReceiver.isEmpty()) {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 614258b..1fb2e0c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -5,13 +5,18 @@
import static com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query.DIRECTLY;
import static com.android.tools.r8.ir.code.DominatorTree.Assumption.MAY_HAVE_UNREACHABLE_BLOCKS;
+import static com.android.tools.r8.ir.code.Opcodes.ADD;
+import static com.android.tools.r8.ir.code.Opcodes.AND;
import static com.android.tools.r8.ir.code.Opcodes.ARGUMENT;
+import static com.android.tools.r8.ir.code.Opcodes.ARRAY_LENGTH;
import static com.android.tools.r8.ir.code.Opcodes.ASSUME;
import static com.android.tools.r8.ir.code.Opcodes.CHECK_CAST;
+import static com.android.tools.r8.ir.code.Opcodes.CMP;
import static com.android.tools.r8.ir.code.Opcodes.CONST_CLASS;
import static com.android.tools.r8.ir.code.Opcodes.CONST_NUMBER;
import static com.android.tools.r8.ir.code.Opcodes.CONST_STRING;
import static com.android.tools.r8.ir.code.Opcodes.DEX_ITEM_BASED_CONST_STRING;
+import static com.android.tools.r8.ir.code.Opcodes.DIV;
import static com.android.tools.r8.ir.code.Opcodes.GOTO;
import static com.android.tools.r8.ir.code.Opcodes.IF;
import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_GET;
@@ -19,12 +24,22 @@
import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_PUT;
import static com.android.tools.r8.ir.code.Opcodes.INVOKE_DIRECT;
import static com.android.tools.r8.ir.code.Opcodes.INVOKE_INTERFACE;
+import static com.android.tools.r8.ir.code.Opcodes.INVOKE_NEW_ARRAY;
import static com.android.tools.r8.ir.code.Opcodes.INVOKE_STATIC;
import static com.android.tools.r8.ir.code.Opcodes.INVOKE_VIRTUAL;
+import static com.android.tools.r8.ir.code.Opcodes.MUL;
+import static com.android.tools.r8.ir.code.Opcodes.NEW_ARRAY_EMPTY;
import static com.android.tools.r8.ir.code.Opcodes.NEW_INSTANCE;
+import static com.android.tools.r8.ir.code.Opcodes.OR;
+import static com.android.tools.r8.ir.code.Opcodes.REM;
import static com.android.tools.r8.ir.code.Opcodes.RETURN;
+import static com.android.tools.r8.ir.code.Opcodes.SHL;
+import static com.android.tools.r8.ir.code.Opcodes.SHR;
import static com.android.tools.r8.ir.code.Opcodes.STATIC_GET;
+import static com.android.tools.r8.ir.code.Opcodes.SUB;
import static com.android.tools.r8.ir.code.Opcodes.THROW;
+import static com.android.tools.r8.ir.code.Opcodes.USHR;
+import static com.android.tools.r8.ir.code.Opcodes.XOR;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
@@ -52,8 +67,11 @@
import com.android.tools.r8.ir.code.InstancePut;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionIterator;
+import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeNewArray;
+import com.android.tools.r8.ir.code.InvokeVirtual;
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Value;
@@ -70,6 +88,7 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
+import com.android.tools.r8.utils.Pair;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
@@ -145,6 +164,7 @@
return;
}
+ List<Pair<Invoke.Type, DexMethod>> callsReceiver = new ArrayList<>();
boolean seenSuperInitCall = false;
for (Instruction insn : receiver.aliasedUsers()) {
if (insn.isAssume()) {
@@ -192,6 +212,27 @@
return;
}
+ if (insn.isInvokeVirtual()) {
+ InvokeVirtual invoke = insn.asInvokeVirtual();
+ if (invoke.getReceiver().getAliasedValue() != receiver) {
+ return; // Not allowed.
+ }
+ for (int i = 1; i < invoke.arguments().size(); i++) {
+ Value argument = invoke.arguments().get(i);
+ if (argument.getAliasedValue() == receiver) {
+ return; // Not allowed.
+ }
+ }
+ DexMethod invokedMethod = invoke.getInvokedMethod();
+ DexType returnType = invokedMethod.proto.returnType;
+ if (returnType.isClassType()
+ && appView.appInfo().isRelatedBySubtyping(returnType, method.method.holder)) {
+ return; // Not allowed, could introduce an alias of the receiver.
+ }
+ callsReceiver.add(new Pair<>(Invoke.Type.VIRTUAL, invokedMethod));
+ continue;
+ }
+
if (insn.isReturn()) {
continue;
}
@@ -208,6 +249,7 @@
feedback.setClassInlinerEligibility(
method,
new ClassInlinerEligibilityInfo(
+ callsReceiver,
new ClassInlinerReceiverAnalysis(appView, method, code).computeReturnsReceiver()));
}
@@ -357,12 +399,26 @@
builder.setInstanceFieldInitializationMayDependOnEnvironment();
break;
+ case ADD:
+ case AND:
+ case ARRAY_LENGTH:
case CHECK_CAST:
+ case CMP:
case CONST_CLASS:
case CONST_STRING:
case DEX_ITEM_BASED_CONST_STRING:
+ case DIV:
case INSTANCE_OF:
+ case MUL:
+ case NEW_ARRAY_EMPTY:
+ case OR:
+ case REM:
+ case SHL:
+ case SHR:
+ case SUB:
case THROW:
+ case USHR:
+ case XOR:
// These instructions types may raise an exception, which is a side effect. None of the
// instructions can trigger class initialization side effects, hence it is not necessary
// to mark all fields as potentially being read. Also, none of the instruction types
@@ -463,15 +519,34 @@
}
break;
+ case INVOKE_NEW_ARRAY:
+ {
+ InvokeNewArray invoke = instruction.asInvokeNewArray();
+ if (invoke.instructionMayHaveSideEffects(appView, clazz.type)) {
+ builder.setMayHaveOtherSideEffectsThanInstanceFieldAssignments();
+ }
+ for (Value argument : invoke.arguments()) {
+ if (argument.getAliasedValue() == receiver) {
+ builder.setReceiverMayEscapeOutsideConstructorChain();
+ break;
+ }
+ }
+ }
+ break;
+
case INVOKE_INTERFACE:
case INVOKE_STATIC:
case INVOKE_VIRTUAL:
- InvokeMethod invoke = instruction.asInvokeMethod();
- builder.markAllFieldsAsRead().setMayHaveOtherSideEffectsThanInstanceFieldAssignments();
- for (Value inValue : invoke.inValues()) {
- if (inValue.getAliasedValue() == receiver) {
- builder.setReceiverMayEscapeOutsideConstructorChain();
- break;
+ {
+ InvokeMethod invoke = instruction.asInvokeMethod();
+ builder
+ .markAllFieldsAsRead()
+ .setMayHaveOtherSideEffectsThanInstanceFieldAssignments();
+ for (Value argument : invoke.arguments()) {
+ if (argument.getAliasedValue() == receiver) {
+ builder.setReceiverMayEscapeOutsideConstructorChain();
+ break;
+ }
}
}
break;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
index d599a38..def162e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
@@ -14,24 +14,16 @@
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
import com.android.tools.r8.ir.optimize.info.initializer.DefaultInstanceInitializerInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
+import com.android.tools.r8.utils.BooleanUtils;
import java.util.BitSet;
import java.util.Set;
import java.util.function.Function;
public class UpdatableMethodOptimizationInfo implements MethodOptimizationInfo {
- private boolean cannotBeKept = false;
- private boolean classInitializerMayBePostponed = false;
- private boolean hasBeenInlinedIntoSingleCallSite = false;
private Set<DexType> initializedClassesOnNormalExit =
DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZED_CLASSES_ON_NORMAL_EXIT;
private int returnedArgument = DefaultMethodOptimizationInfo.UNKNOWN_RETURNED_ARGUMENT;
- private boolean mayHaveSideEffects = DefaultMethodOptimizationInfo.UNKNOWN_MAY_HAVE_SIDE_EFFECTS;
- private boolean returnValueOnlyDependsOnArguments =
- DefaultMethodOptimizationInfo.UNKNOWN_RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS;
- private boolean neverReturnsNull = DefaultMethodOptimizationInfo.UNKNOWN_NEVER_RETURNS_NULL;
- private boolean neverReturnsNormally =
- DefaultMethodOptimizationInfo.UNKNOWN_NEVER_RETURNS_NORMALLY;
private AbstractValue abstractReturnValue =
DefaultMethodOptimizationInfo.UNKNOWN_ABSTRACT_RETURN_VALUE;
private TypeLatticeElement returnsObjectWithUpperBoundType =
@@ -39,20 +31,12 @@
private ClassTypeLatticeElement returnsObjectWithLowerBoundType =
DefaultMethodOptimizationInfo.UNKNOWN_CLASS_TYPE;
private InlinePreference inlining = InlinePreference.Default;
- private boolean useIdentifierNameString =
- DefaultMethodOptimizationInfo.DOES_NOT_USE_IDENTIFIER_NAME_STRING;
- private boolean checksNullReceiverBeforeAnySideEffect =
- DefaultMethodOptimizationInfo.UNKNOWN_CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT;
- private boolean triggersClassInitBeforeAnySideEffect =
- DefaultMethodOptimizationInfo.UNKNOWN_TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT;
// Stores information about instance methods and constructors for
// class inliner, null value indicates that the method is not eligible.
private ClassInlinerEligibilityInfo classInlinerEligibility =
DefaultMethodOptimizationInfo.UNKNOWN_CLASS_INLINER_ELIGIBILITY;
private InstanceInitializerInfo instanceInitializerInfo =
DefaultInstanceInitializerInfo.getInstance();
- private boolean initializerEnablingJavaAssertions =
- DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZER_ENABLING_JAVA_ASSERTIONS;
private ParameterUsagesInfo parametersUsages =
DefaultMethodOptimizationInfo.UNKNOWN_PARAMETER_USAGE_INFO;
// Stores information about nullability hint per parameter. If set, that means, the method
@@ -73,8 +57,69 @@
// Note that this bit set takes into account the receiver for instance methods.
private BitSet nonNullParamOnNormalExits =
DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS;
- private boolean reachabilitySensitive = false;
- private boolean returnValueHasBeenPropagated = false;
+
+ // To reduce the memory footprint of UpdatableMethodOptimizationInfo, all the boolean fields are
+ // merged into a flag int field. The various static final FLAG fields indicate which bit is
+ // used by each boolean. DEFAULT_FLAGS encodes the default value for efficient instantiation and
+ // is computed during class initialization from the default method optimization info. The
+ // methods setFlag, clearFlag and isFlagSet are used to access the booleans.
+ private static final int CANNOT_BE_KEPT_FLAG = 0x1;
+ private static final int CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG = 0x2;
+ private static final int HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG = 0x4;
+ private static final int MAY_HAVE_SIDE_EFFECT_FLAG = 0x8;
+ private static final int RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG = 0x10;
+ private static final int NEVER_RETURNS_NULL_FLAG = 0x20;
+ private static final int NEVER_RETURNS_NORMALLY_FLAG = 0x40;
+ private static final int USE_IDENTIFIER_NAME_STRING_FLAG = 0x80;
+ private static final int CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT_FLAG = 0x100;
+ private static final int TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG = 0x200;
+ private static final int INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG = 0x400;
+ private static final int REACHABILITY_SENSITIVE_FLAG = 0x800;
+ private static final int RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG = 0x1000;
+
+ private static final int DEFAULT_FLAGS;
+
+ static {
+ int defaultFlags = 0;
+ MethodOptimizationInfo defaultOptInfo = DefaultMethodOptimizationInfo.DEFAULT_INSTANCE;
+ defaultFlags |= BooleanUtils.intValue(defaultOptInfo.cannotBeKept()) * CANNOT_BE_KEPT_FLAG;
+ defaultFlags |=
+ BooleanUtils.intValue(defaultOptInfo.classInitializerMayBePostponed())
+ * CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG;
+ defaultFlags |=
+ BooleanUtils.intValue(defaultOptInfo.hasBeenInlinedIntoSingleCallSite())
+ * HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG;
+ defaultFlags |=
+ BooleanUtils.intValue(defaultOptInfo.mayHaveSideEffects()) * MAY_HAVE_SIDE_EFFECT_FLAG;
+ defaultFlags |=
+ BooleanUtils.intValue(defaultOptInfo.returnValueOnlyDependsOnArguments())
+ * RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG;
+ defaultFlags |=
+ BooleanUtils.intValue(defaultOptInfo.neverReturnsNull()) * NEVER_RETURNS_NULL_FLAG;
+ defaultFlags |=
+ BooleanUtils.intValue(defaultOptInfo.neverReturnsNormally()) * NEVER_RETURNS_NORMALLY_FLAG;
+ defaultFlags |=
+ BooleanUtils.intValue(defaultOptInfo.useIdentifierNameString())
+ * USE_IDENTIFIER_NAME_STRING_FLAG;
+ defaultFlags |=
+ BooleanUtils.intValue(defaultOptInfo.checksNullReceiverBeforeAnySideEffect())
+ * CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT_FLAG;
+ defaultFlags |=
+ BooleanUtils.intValue(defaultOptInfo.triggersClassInitBeforeAnySideEffect())
+ * TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG;
+ defaultFlags |=
+ BooleanUtils.intValue(defaultOptInfo.isInitializerEnablingJavaAssertions())
+ * INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG;
+ defaultFlags |=
+ BooleanUtils.intValue(defaultOptInfo.isReachabilitySensitive())
+ * REACHABILITY_SENSITIVE_FLAG;
+ defaultFlags |=
+ BooleanUtils.intValue(defaultOptInfo.returnValueHasBeenPropagated())
+ * RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG;
+ DEFAULT_FLAGS = defaultFlags;
+ }
+
+ private int flags = DEFAULT_FLAGS;
UpdatableMethodOptimizationInfo() {
// Intentionally left empty, just use the default values.
@@ -83,30 +128,18 @@
// Copy constructor used to create a mutable copy. Do not forget to copy from template when a new
// field is added.
private UpdatableMethodOptimizationInfo(UpdatableMethodOptimizationInfo template) {
- cannotBeKept = template.cannotBeKept;
- classInitializerMayBePostponed = template.classInitializerMayBePostponed;
- hasBeenInlinedIntoSingleCallSite = template.hasBeenInlinedIntoSingleCallSite;
+ flags = template.flags;
initializedClassesOnNormalExit = template.initializedClassesOnNormalExit;
returnedArgument = template.returnedArgument;
- mayHaveSideEffects = template.mayHaveSideEffects;
- returnValueOnlyDependsOnArguments = template.returnValueOnlyDependsOnArguments;
- neverReturnsNull = template.neverReturnsNull;
- neverReturnsNormally = template.neverReturnsNormally;
abstractReturnValue = template.abstractReturnValue;
returnsObjectWithUpperBoundType = template.returnsObjectWithUpperBoundType;
returnsObjectWithLowerBoundType = template.returnsObjectWithLowerBoundType;
inlining = template.inlining;
- useIdentifierNameString = template.useIdentifierNameString;
- checksNullReceiverBeforeAnySideEffect = template.checksNullReceiverBeforeAnySideEffect;
- triggersClassInitBeforeAnySideEffect = template.triggersClassInitBeforeAnySideEffect;
classInlinerEligibility = template.classInlinerEligibility;
instanceInitializerInfo = template.instanceInitializerInfo;
- initializerEnablingJavaAssertions = template.initializerEnablingJavaAssertions;
parametersUsages = template.parametersUsages;
nonNullParamOrThrow = template.nonNullParamOrThrow;
nonNullParamOnNormalExits = template.nonNullParamOnNormalExits;
- reachabilitySensitive = template.reachabilitySensitive;
- returnValueHasBeenPropagated = template.returnValueHasBeenPropagated;
}
public void fixupClassTypeReferences(
@@ -121,6 +154,26 @@
}
}
+ private void setFlag(int flag, boolean value) {
+ if (value) {
+ setFlag(flag);
+ } else {
+ clearFlag(flag);
+ }
+ }
+
+ private void setFlag(int flag) {
+ flags |= flag;
+ }
+
+ private void clearFlag(int flag) {
+ flags &= ~flag;
+ }
+
+ private boolean isFlagSet(int flag) {
+ return (flags & flag) != 0;
+ }
+
@Override
public boolean isDefaultMethodOptimizationInfo() {
return false;
@@ -138,21 +191,21 @@
@Override
public boolean cannotBeKept() {
- return cannotBeKept;
+ return isFlagSet(CANNOT_BE_KEPT_FLAG);
}
// TODO(b/140214568): Should be package-private.
public void markCannotBeKept() {
- cannotBeKept = true;
+ setFlag(CANNOT_BE_KEPT_FLAG);
}
@Override
public boolean classInitializerMayBePostponed() {
- return classInitializerMayBePostponed;
+ return isFlagSet(CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG);
}
void markClassInitializerMayBePostponed() {
- classInitializerMayBePostponed = true;
+ setFlag(CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG);
}
@Override
@@ -192,16 +245,16 @@
@Override
public boolean hasBeenInlinedIntoSingleCallSite() {
- return hasBeenInlinedIntoSingleCallSite;
+ return isFlagSet(HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG);
}
void markInlinedIntoSingleCallSite() {
- hasBeenInlinedIntoSingleCallSite = true;
+ setFlag(HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG);
}
@Override
public boolean isReachabilitySensitive() {
- return reachabilitySensitive;
+ return isFlagSet(REACHABILITY_SENSITIVE_FLAG);
}
@Override
@@ -217,12 +270,12 @@
@Override
public boolean neverReturnsNull() {
- return neverReturnsNull;
+ return isFlagSet(NEVER_RETURNS_NULL_FLAG);
}
@Override
public boolean neverReturnsNormally() {
- return neverReturnsNormally;
+ return isFlagSet(NEVER_RETURNS_NORMALLY_FLAG);
}
@Override
@@ -237,12 +290,12 @@
@Override
public boolean isInitializerEnablingJavaAssertions() {
- return initializerEnablingJavaAssertions;
+ return isFlagSet(INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG);
}
@Override
public boolean useIdentifierNameString() {
- return useIdentifierNameString;
+ return isFlagSet(USE_IDENTIFIER_NAME_STRING_FLAG);
}
@Override
@@ -257,22 +310,22 @@
@Override
public boolean checksNullReceiverBeforeAnySideEffect() {
- return checksNullReceiverBeforeAnySideEffect;
+ return isFlagSet(CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT_FLAG);
}
@Override
public boolean triggersClassInitBeforeAnySideEffect() {
- return triggersClassInitBeforeAnySideEffect;
+ return isFlagSet(TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG);
}
@Override
public boolean mayHaveSideEffects() {
- return mayHaveSideEffects;
+ return isFlagSet(MAY_HAVE_SIDE_EFFECT_FLAG);
}
@Override
public boolean returnValueOnlyDependsOnArguments() {
- return returnValueOnlyDependsOnArguments;
+ return isFlagSet(RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG);
}
void setParameterUsages(ParameterUsagesInfo parametersUsages) {
@@ -288,7 +341,7 @@
}
public void setReachabilitySensitive(boolean reachabilitySensitive) {
- this.reachabilitySensitive = reachabilitySensitive;
+ setFlag(REACHABILITY_SENSITIVE_FLAG, reachabilitySensitive);
}
void setClassInlinerEligibility(ClassInlinerEligibilityInfo eligibility) {
@@ -300,7 +353,7 @@
}
void setInitializerEnablingJavaAssertions() {
- this.initializerEnablingJavaAssertions = true;
+ setFlag(INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG);
}
void markInitializesClassesOnNormalExit(Set<DexType> initializedClassesOnNormalExit) {
@@ -314,19 +367,19 @@
}
void markMayNotHaveSideEffects() {
- mayHaveSideEffects = false;
+ clearFlag(MAY_HAVE_SIDE_EFFECT_FLAG);
}
void markReturnValueOnlyDependsOnArguments() {
- returnValueOnlyDependsOnArguments = true;
+ setFlag(RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG);
}
void markNeverReturnsNull() {
- neverReturnsNull = true;
+ setFlag(NEVER_RETURNS_NULL_FLAG);
}
void markNeverReturnsNormally() {
- neverReturnsNormally = true;
+ setFlag(NEVER_RETURNS_NORMALLY_FLAG);
}
void markReturnsAbstractValue(AbstractValue value) {
@@ -385,25 +438,25 @@
// TODO(b/140214568): Should be package-private.
public void markUseIdentifierNameString() {
- useIdentifierNameString = true;
+ setFlag(USE_IDENTIFIER_NAME_STRING_FLAG);
}
void markCheckNullReceiverBeforeAnySideEffect(boolean mark) {
- checksNullReceiverBeforeAnySideEffect = mark;
+ setFlag(CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT_FLAG, mark);
}
void markTriggerClassInitBeforeAnySideEffect(boolean mark) {
- triggersClassInitBeforeAnySideEffect = mark;
+ setFlag(TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG, mark);
}
// TODO(b/140214568): Should be package-private.
public void markAsPropagated() {
- returnValueHasBeenPropagated = true;
+ setFlag(RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG);
}
@Override
public boolean returnValueHasBeenPropagated() {
- return returnValueHasBeenPropagated;
+ return isFlagSet(RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG);
}
@Override
@@ -415,9 +468,9 @@
public void adjustOptimizationInfoAfterRemovingThisParameter() {
// cannotBeKept: doesn't depend on `this`
// classInitializerMayBePostponed: `this` could trigger <clinit> of the previous holder.
- classInitializerMayBePostponed = false;
+ clearFlag(CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG);
// hasBeenInlinedIntoSingleCallSite: then it should not be staticized.
- hasBeenInlinedIntoSingleCallSite = false;
+ clearFlag(HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG);
// initializedClassesOnNormalExit: `this` could trigger <clinit> of the previous holder.
initializedClassesOnNormalExit =
DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZED_CLASSES_ON_NORMAL_EXIT;
@@ -441,18 +494,19 @@
inlining = InlinePreference.Default;
// useIdentifierNameString: code is not changed.
// checksNullReceiverBeforeAnySideEffect: no more receiver.
- checksNullReceiverBeforeAnySideEffect =
- DefaultMethodOptimizationInfo.UNKNOWN_CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT;
+ markCheckNullReceiverBeforeAnySideEffect(
+ DefaultMethodOptimizationInfo.UNKNOWN_CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT);
// triggersClassInitBeforeAnySideEffect: code is not changed.
- triggersClassInitBeforeAnySideEffect =
- DefaultMethodOptimizationInfo.UNKNOWN_TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT;
+ markTriggerClassInitBeforeAnySideEffect(
+ DefaultMethodOptimizationInfo.UNKNOWN_TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT);
// classInlinerEligibility: chances are the method is not an instance method anymore.
classInlinerEligibility = DefaultMethodOptimizationInfo.UNKNOWN_CLASS_INLINER_ELIGIBILITY;
// initializerInfo: the computed initializer info may become invalid.
instanceInitializerInfo = null;
// initializerEnablingJavaAssertions: `this` could trigger <clinit> of the previous holder.
- initializerEnablingJavaAssertions =
- DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZER_ENABLING_JAVA_ASSERTIONS;
+ setFlag(
+ INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG,
+ DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZER_ENABLING_JAVA_ASSERTIONS);
parametersUsages =
parametersUsages == DefaultMethodOptimizationInfo.UNKNOWN_PARAMETER_USAGE_INFO
? DefaultMethodOptimizationInfo.UNKNOWN_PARAMETER_USAGE_INFO
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index 9981290..a11f309 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -434,9 +434,7 @@
.map(method -> appView.graphLense().mapDexEncodedMethod(method, appView))
.collect(Collectors.toSet());
converter.processMethodsConcurrently(methods, executorService);
- methods.forEach(method -> {
- assert method.isProcessed();
- });
+ assert methods.stream().allMatch(DexEncodedMethod::isProcessed);
}
private void analyzeClass(DexProgramClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
index 1784753..98e83c4 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
@@ -9,11 +9,10 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.analysis.type.Nullability;
-import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.conversion.DexSourceCode;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.SourceCode;
import java.util.ArrayList;
@@ -25,6 +24,7 @@
protected final static Predicate<IRBuilder> doesNotEndBlock = x -> false;
protected final static Predicate<IRBuilder> endsBlock = x -> true;
+ // TODO(b/146124603): Remove these fields as optimzations (e.g., merging) could invalidate them.
protected final DexType receiver;
protected final DexMethod method;
protected final DexProto proto;
@@ -156,19 +156,11 @@
@Override
public final void buildPrelude(IRBuilder builder) {
- if (receiver != null) {
- builder.addThisArgument(
- receiverRegister,
- TypeLatticeElement.fromDexType(
- receiver, Nullability.definitelyNotNull(), builder.appView));
- }
- // Fill in the Argument instructions in the argument block.
- DexType[] parameters = proto.parameters.values;
- for (int i = 0; i < parameters.length; i++) {
- TypeLatticeElement typeLattice =
- TypeLatticeElement.fromDexType(parameters[i], Nullability.maybeNull(), builder.appView);
- builder.addNonThisArgument(paramRegisters[i], typeLattice);
- }
+ DexSourceCode.buildArgumentsWithUnusedArgumentStubs(
+ builder,
+ 0,
+ builder.getMethod(),
+ DexSourceCode::doNothingWriteConsumer);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassFacade.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassFacade.java
index a24055e..f8c1c12 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassFacade.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassFacade.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.kotlin;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.naming.NamingLens;
@@ -35,12 +34,15 @@
@Override
void rewrite(AppView<AppInfoWithLiveness> appView, NamingLens lens) {
- throw new Unreachable(toString());
+ // TODO(b/70169921): no idea yet!
+ assert lens.lookupType(clazz.type, appView.dexItemFactory()) == clazz.type
+ : toString();
}
@Override
KotlinClassHeader createHeader() {
- throw new Unreachable(toString());
+ // TODO(b/70169921): may need to update if `rewrite` is implemented.
+ return metadata.getHeader();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
index c05b48f..a195f97 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -83,10 +83,13 @@
if (kMetadata instanceof KotlinClassMetadata.Class) {
return KotlinClass.fromKotlinClassMetadata(kMetadata, clazz);
} else if (kMetadata instanceof KotlinClassMetadata.FileFacade) {
+ // e.g., B.kt becomes class `BKt`
return KotlinFile.fromKotlinClassMetadata(kMetadata, clazz);
} else if (kMetadata instanceof KotlinClassMetadata.MultiFileClassFacade) {
+ // multi-file class with the same @JvmName.
return KotlinClassFacade.fromKotlinClassMetadata(kMetadata, clazz);
} else if (kMetadata instanceof KotlinClassMetadata.MultiFileClassPart) {
+ // A single file, which is part of multi-file class.
return KotlinClassPart.fromKotlinClassMetadata(kMetadata, clazz);
} else if (kMetadata instanceof KotlinClassMetadata.SyntheticClass) {
return KotlinSyntheticClass.fromKotlinClassMetadata(kMetadata, kotlin, clazz);
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
index 054c5e2..5658b0d 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -66,9 +66,6 @@
clazz -> {
KotlinInfo<?> kotlinInfo = clazz.getKotlinInfo();
if (kotlinInfo != null) {
- assert kotlinInfo.isClass()
- || kotlinInfo.isSyntheticClass()
- || kotlinInfo.isFile(); // e.g., B.kt becomes class `BKt`
// If @Metadata is still associated, this class should not be renamed
// (by {@link ClassNameMinifier} of course).
assert lens.lookupType(clazz.type, appView.dexItemFactory()) == clazz.type
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
index 0b061f3..4400273 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
@@ -19,18 +19,16 @@
return null;
}
// For library or classpath class, synthesize @Metadata always.
- if (clazz.isNotProgramClass()) {
- KmType kmType = new KmType(clazz.accessFlags.getAsCfAccessFlags());
- assert type == lens.lookupType(type, appView.dexItemFactory());
- kmType.visitClass(DescriptorUtils.descriptorToInternalName(type.toDescriptorString()));
- return kmType;
- }
- // From now on, it is a program class. First, make sure it is live.
- if (!appView.appInfo().isLiveProgramType(type)) {
+ // For a program class, make sure it is live.
+ if (!appView.appInfo().isNonProgramTypeOrLiveProgramType(type)) {
return null;
}
- KmType kmType = new KmType(clazz.accessFlags.getAsCfAccessFlags());
DexType renamedType = lens.lookupType(type, appView.dexItemFactory());
+ // For library or classpath class, we should not have renamed it.
+ assert clazz.isProgramClass() || renamedType == type
+ : type.toSourceString() + " -> " + renamedType.toSourceString();
+ // TODO(b/70169921): Consult kotlinx.metadata.Flag for kotlin-specific flags (e.g., sealed).
+ KmType kmType = new KmType(clazz.accessFlags.getAsCfAccessFlags());
kmType.visitClass(DescriptorUtils.descriptorToInternalName(renamedType.toDescriptorString()));
return kmType;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 347ae0f..0aea415 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -142,6 +142,8 @@
public final Set<DexMethod> keepConstantArguments;
/** All methods that may not have any unused arguments removed. */
public final Set<DexMethod> keepUnusedArguments;
+ /** All types that should be inlined if possible due to a configuration directive. */
+ public final Set<DexType> alwaysClassInline;
/** All types that *must* never be inlined due to a configuration directive (testing only). */
public final Set<DexType> neverClassInline;
/** All types that *must* never be merged due to a configuration directive (testing only). */
@@ -210,6 +212,7 @@
Set<DexMethod> whyAreYouNotInlining,
Set<DexMethod> keepConstantArguments,
Set<DexMethod> keepUnusedArguments,
+ Set<DexType> alwaysClassInline,
Set<DexType> neverClassInline,
Set<DexType> neverMerge,
Set<DexReference> neverPropagateValue,
@@ -248,6 +251,7 @@
this.whyAreYouNotInlining = whyAreYouNotInlining;
this.keepConstantArguments = keepConstantArguments;
this.keepUnusedArguments = keepUnusedArguments;
+ this.alwaysClassInline = alwaysClassInline;
this.neverClassInline = neverClassInline;
this.neverMerge = neverMerge;
this.neverPropagateValue = neverPropagateValue;
@@ -289,6 +293,7 @@
Set<DexMethod> whyAreYouNotInlining,
Set<DexMethod> keepConstantArguments,
Set<DexMethod> keepUnusedArguments,
+ Set<DexType> alwaysClassInline,
Set<DexType> neverClassInline,
Set<DexType> neverMerge,
Set<DexReference> neverPropagateValue,
@@ -327,6 +332,7 @@
this.whyAreYouNotInlining = whyAreYouNotInlining;
this.keepConstantArguments = keepConstantArguments;
this.keepUnusedArguments = keepUnusedArguments;
+ this.alwaysClassInline = alwaysClassInline;
this.neverClassInline = neverClassInline;
this.neverMerge = neverMerge;
this.neverPropagateValue = neverPropagateValue;
@@ -369,6 +375,7 @@
previous.whyAreYouNotInlining,
previous.keepConstantArguments,
previous.keepUnusedArguments,
+ previous.alwaysClassInline,
previous.neverClassInline,
previous.neverMerge,
previous.neverPropagateValue,
@@ -418,6 +425,7 @@
previous.whyAreYouNotInlining,
previous.keepConstantArguments,
previous.keepUnusedArguments,
+ previous.alwaysClassInline,
previous.neverClassInline,
previous.neverMerge,
previous.neverPropagateValue,
@@ -499,6 +507,7 @@
.map(this::definitionFor)
.filter(Objects::nonNull)
.collect(Collectors.toList()));
+ this.alwaysClassInline = rewriteItems(previous.alwaysClassInline, lense::lookupType);
this.neverClassInline = rewriteItems(previous.neverClassInline, lense::lookupType);
this.neverMerge = rewriteItems(previous.neverMerge, lense::lookupType);
this.neverPropagateValue = lense.rewriteReferencesConservatively(previous.neverPropagateValue);
@@ -550,6 +559,7 @@
this.whyAreYouNotInlining = previous.whyAreYouNotInlining;
this.keepConstantArguments = previous.keepConstantArguments;
this.keepUnusedArguments = previous.keepUnusedArguments;
+ this.alwaysClassInline = previous.alwaysClassInline;
this.neverClassInline = previous.neverClassInline;
this.neverMerge = previous.neverMerge;
this.neverPropagateValue = previous.neverPropagateValue;
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java b/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java
index e7dc76c..4e69cd2 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java
@@ -11,6 +11,7 @@
public class ClassInlineRule extends ProguardConfigurationRule {
public enum Type {
+ ALWAYS,
NEVER
}
@@ -95,8 +96,20 @@
}
@Override
+ public boolean isClassInlineRule() {
+ return true;
+ }
+
+ @Override
+ public ClassInlineRule asClassInlineRule() {
+ return this;
+ }
+
+ @Override
String typeString() {
switch (type) {
+ case ALWAYS:
+ return "alwaysclassinline";
case NEVER:
return "neverclassinline";
}
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 3548caf..8329fcf 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2168,11 +2168,7 @@
// Package protected due to entry point from worklist.
void markSuperMethodAsReachable(DexMethod method, DexEncodedMethod from) {
- // We have to mark the immediate target of the descriptor as targeted, as otherwise
- // the invoke super will fail in the resolution step with a NSM error.
- // See <a
- // href="https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokespecial">
- // the JVM spec for invoke-special.
+ // If the method does not resolve, mark it broken to avoid hiding errors in other optimizations.
SingleResolutionResult resolution =
appInfo.resolveMethod(method.holder, method).asSingleResolution();
if (resolution == null) {
@@ -2180,31 +2176,26 @@
reportMissingMethod(method);
return;
}
-
- DexEncodedMethod resolutionTarget = resolution.getResolvedMethod();
- if (resolutionTarget.accessFlags.isPrivate() || resolutionTarget.accessFlags.isStatic()) {
- brokenSuperInvokes.add(resolutionTarget.method);
- }
- DexProgramClass resolutionTargetClass = resolution.getResolvedHolder().asProgramClass();
- if (resolutionTargetClass != null) {
+ // If the resolution is in the program, mark it targeted.
+ if (resolution.getResolvedHolder().isProgramClass()) {
markMethodAsTargeted(
- resolutionTargetClass, resolutionTarget, KeepReason.targetedBySuperFrom(from));
+ resolution.getResolvedHolder().asProgramClass(),
+ resolution.getResolvedMethod(),
+ KeepReason.targetedBySuperFrom(from));
}
-
- // Now we need to compute the actual target in the context.
- DexEncodedMethod target = resolution.lookupInvokeSuperTarget(from.method.holder, appInfo);
+ // If invoke target is invalid (inaccessible or not an instance-method) record it and stop.
+ // TODO(b/146016987): We should be passing the full program context and not looking it up again.
+ DexProgramClass fromHolder = appInfo.definitionFor(from.method.holder).asProgramClass();
+ DexEncodedMethod target = resolution.lookupInvokeSuperTarget(fromHolder, appInfo);
if (target == null) {
- // The actual implementation in the super class is missing.
- reportMissingMethod(method);
+ brokenSuperInvokes.add(resolution.getResolvedMethod().method);
return;
}
+
DexProgramClass clazz = getProgramClassOrNull(target.method.holder);
if (clazz == null) {
return;
}
- if (target.accessFlags.isPrivate()) {
- brokenSuperInvokes.add(resolutionTarget.method);
- }
if (Log.ENABLED) {
Log.verbose(getClass(), "Adding super constraint from `%s` to `%s`", from.method,
target.method);
@@ -2317,6 +2308,7 @@
rootSet.whyAreYouNotInlining,
rootSet.keepConstantArguments,
rootSet.keepUnusedArguments,
+ rootSet.alwaysClassInline,
rootSet.neverClassInline,
rootSet.neverMerge,
rootSet.neverPropagateValue,
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index cee2d66..4778c35 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -432,6 +432,11 @@
configurationBuilder.addRule(rule);
return true;
}
+ if (acceptString("alwaysclassinline")) {
+ ClassInlineRule rule = parseClassInlineRule(ClassInlineRule.Type.ALWAYS, optionStart);
+ configurationBuilder.addRule(rule);
+ return true;
+ }
if (acceptString("neverclassinline")) {
ClassInlineRule rule = parseClassInlineRule(ClassInlineRule.Type.NEVER, optionStart);
configurationBuilder.addRule(rule);
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
index ed49a01..f899a6b 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
@@ -57,6 +57,14 @@
return null;
}
+ public boolean isClassInlineRule() {
+ return false;
+ }
+
+ public ClassInlineRule asClassInlineRule() {
+ return null;
+ }
+
Iterable<DexProgramClass> relevantCandidatesForRule(
AppView<? extends AppInfoWithSubtyping> appView, Iterable<DexProgramClass> defaultValue) {
if (hasInheritanceClassName() && getInheritanceClassName().hasSpecificType()) {
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 24b5004..b86857a 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
@@ -82,6 +81,7 @@
private final Set<DexMethod> whyAreYouNotInlining = Sets.newIdentityHashSet();
private final Set<DexMethod> keepParametersWithConstantValue = Sets.newIdentityHashSet();
private final Set<DexMethod> keepUnusedArguments = Sets.newIdentityHashSet();
+ private final Set<DexType> alwaysClassInline = Sets.newIdentityHashSet();
private final Set<DexType> neverClassInline = Sets.newIdentityHashSet();
private final Set<DexType> neverMerge = Sets.newIdentityHashSet();
private final Set<DexReference> neverPropagateValue = Sets.newIdentityHashSet();
@@ -312,6 +312,7 @@
whyAreYouNotInlining,
keepParametersWithConstantValue,
keepUnusedArguments,
+ alwaysClassInline,
neverClassInline,
neverMerge,
neverPropagateValue,
@@ -1108,12 +1109,23 @@
}
whyAreYouNotInlining.add(item.asDexEncodedMethod().method);
context.markAsUsed();
- } else if (context instanceof ClassInlineRule) {
- switch (((ClassInlineRule) context).getType()) {
+ } else if (context.isClassInlineRule()) {
+ ClassInlineRule classInlineRule = context.asClassInlineRule();
+ DexClass clazz = item.asDexClass();
+ if (clazz == null) {
+ throw new IllegalStateException(
+ "Unexpected -"
+ + classInlineRule.typeString()
+ + " rule for a non-class type: `"
+ + item.toReference().toSourceString()
+ + "`");
+ }
+ switch (classInlineRule.getType()) {
+ case ALWAYS:
+ alwaysClassInline.add(item.asDexClass().type);
+ break;
case NEVER:
- if (item.isDexClass()) {
- neverClassInline.add(item.asDexClass().type);
- }
+ neverClassInline.add(item.asDexClass().type);
break;
default:
throw new Unreachable();
@@ -1189,6 +1201,7 @@
public final Set<DexMethod> whyAreYouNotInlining;
public final Set<DexMethod> keepConstantArguments;
public final Set<DexMethod> keepUnusedArguments;
+ public final Set<DexType> alwaysClassInline;
public final Set<DexType> neverClassInline;
public final Set<DexType> neverMerge;
public final Set<DexReference> neverPropagateValue;
@@ -1215,6 +1228,7 @@
Set<DexMethod> whyAreYouNotInlining,
Set<DexMethod> keepConstantArguments,
Set<DexMethod> keepUnusedArguments,
+ Set<DexType> alwaysClassInline,
Set<DexType> neverClassInline,
Set<DexType> neverMerge,
Set<DexReference> neverPropagateValue,
@@ -1238,6 +1252,7 @@
this.whyAreYouNotInlining = whyAreYouNotInlining;
this.keepConstantArguments = keepConstantArguments;
this.keepUnusedArguments = keepUnusedArguments;
+ this.alwaysClassInline = alwaysClassInline;
this.neverClassInline = neverClassInline;
this.neverMerge = Collections.unmodifiableSet(neverMerge);
this.neverPropagateValue = neverPropagateValue;
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 77de8e2..9a477cc 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1147,7 +1147,7 @@
// Only rewrite the invoke-super call if it does not lead to a NoSuchMethodError.
boolean resolutionSucceeds =
holder.lookupVirtualMethod(signatureInHolder) != null
- || appInfo.lookupSuperTarget(signatureInHolder, holder.type) != null;
+ || appInfo.lookupSuperTarget(signatureInHolder, holder) != null;
if (resolutionSucceeds) {
deferredRenamings.mapVirtualMethodToDirectInType(
signatureInHolder, new GraphLenseLookupResult(newTarget, DIRECT), target.type);
@@ -1169,7 +1169,7 @@
// its super classes declared the method.
boolean resolutionSucceededBeforeMerge =
renamedMembersLense.hasMappingForSignatureInContext(holder.type, signatureInType)
- || appInfo.lookupSuperTarget(signatureInHolder, holder.type) != null;
+ || appInfo.lookupSuperTarget(signatureInHolder, holder) != null;
if (resolutionSucceededBeforeMerge) {
deferredRenamings.mapVirtualMethodToDirectInType(
signatureInType, new GraphLenseLookupResult(newTarget, DIRECT), target.type);
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 40633b6..a5f672e 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -205,7 +205,8 @@
!Version.isDevelopmentVersion()
|| System.getProperty("com.android.tools.r8.disableinlining") == null;
// TODO(b/141451716): Evaluate the effect of allowing inlining in the inlinee.
- public boolean applyInliningToInlinee = false;
+ public boolean applyInliningToInlinee =
+ System.getProperty("com.android.tools.r8.applyInliningToInlinee") != null;
public int applyInliningToInlineeMaxDepth = 0;
public boolean enableInliningOfInvokesWithNullableReceivers = true;
public boolean disableInliningOfLibraryMethodOverrides = true;
diff --git a/src/test/examples/classmerging/NeverClassInline.java b/src/test/examples/classmerging/NeverClassInline.java
new file mode 100644
index 0000000..2dca10e
--- /dev/null
+++ b/src/test/examples/classmerging/NeverClassInline.java
@@ -0,0 +1,10 @@
+// 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 classmerging;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target({ElementType.TYPE})
+public @interface NeverClassInline {}
diff --git a/src/test/examples/classmerging/ProguardFieldMapTest.java b/src/test/examples/classmerging/ProguardFieldMapTest.java
index 0cbf8a1..e512173 100644
--- a/src/test/examples/classmerging/ProguardFieldMapTest.java
+++ b/src/test/examples/classmerging/ProguardFieldMapTest.java
@@ -16,6 +16,7 @@
public String f = "A.f";
}
+ @NeverClassInline
public static class B extends A {
public void test() {
diff --git a/src/test/examples/classmerging/ProguardMethodMapTest.java b/src/test/examples/classmerging/ProguardMethodMapTest.java
index 9ce0ad7..dd3ccff 100644
--- a/src/test/examples/classmerging/ProguardMethodMapTest.java
+++ b/src/test/examples/classmerging/ProguardMethodMapTest.java
@@ -18,6 +18,7 @@
}
}
+ @NeverClassInline
public static class B extends A {
@Override
diff --git a/src/test/examples/classmerging/keep-rules.txt b/src/test/examples/classmerging/keep-rules.txt
index 11a66c6..5297ee9 100644
--- a/src/test/examples/classmerging/keep-rules.txt
+++ b/src/test/examples/classmerging/keep-rules.txt
@@ -68,6 +68,7 @@
public static void main(...);
}
+-neverclassinline @classmerging.NeverClassInline class *
-neverinline class * {
@classmerging.NeverInline <methods>;
}
diff --git a/src/test/examplesJava10/backport/ListBackportJava10Main.java b/src/test/examplesJava10/backport/ListBackportJava10Main.java
new file mode 100644
index 0000000..376f67a
--- /dev/null
+++ b/src/test/examplesJava10/backport/ListBackportJava10Main.java
@@ -0,0 +1,67 @@
+// 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 backport;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ListBackportJava10Main {
+
+ public static void main(String[] args) {
+ testCopyOf();
+ }
+
+ private static void testCopyOf() {
+ Object anObject0 = new Object();
+ Object anObject1 = new Object();
+ List<Object> original = Arrays.asList(anObject0, anObject1);
+ List<Object> copy = List.copyOf(original);
+ assertEquals(2, copy.size());
+ assertEquals(original, copy);
+ assertSame(anObject0, copy.get(0));
+ assertSame(anObject1, copy.get(1));
+ assertMutationNotAllowed(copy);
+
+ // Mutate the original backing collection and ensure it's not reflected in copy.
+ original.set(0, new Object());
+ assertSame(anObject0, copy.get(0));
+
+ try {
+ List.copyOf(null);
+ throw new AssertionError();
+ } catch (NullPointerException expected) {
+ }
+ try {
+ List.copyOf(Arrays.asList(1, null, 2));
+ throw new AssertionError();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ private static void assertMutationNotAllowed(List<Object> ofObject) {
+ try {
+ ofObject.add(new Object());
+ throw new AssertionError();
+ } catch (UnsupportedOperationException expected) {
+ }
+ try {
+ ofObject.set(0, new Object());
+ throw new AssertionError();
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ private static void assertSame(Object expected, Object actual) {
+ if (expected != actual) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+ }
+ }
+
+ private static void assertEquals(Object expected, Object actual) {
+ if (expected != actual && !expected.equals(actual)) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+ }
+ }
+}
diff --git a/src/test/examplesJava10/backport/MapBackportJava10Main.java b/src/test/examplesJava10/backport/MapBackportJava10Main.java
new file mode 100644
index 0000000..95413e9
--- /dev/null
+++ b/src/test/examplesJava10/backport/MapBackportJava10Main.java
@@ -0,0 +1,82 @@
+// 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 backport;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MapBackportJava10Main {
+
+ public static void main(String[] args) {
+ testCopyOf();
+ }
+
+ private static void testCopyOf() {
+ Object key0 = new Object();
+ Object value0 = new Object();
+ Object key1 = new Object();
+ Object value1 = new Object();
+ Map<Object, Object> original = new HashMap<>();
+ original.put(key0, value0);
+ original.put(key1, value1);
+ Map<Object, Object> copy = Map.copyOf(original);
+ assertEquals(2, copy.size());
+ assertEquals(original, copy);
+ assertSame(value0, copy.get(key0));
+ assertSame(value1, copy.get(key1));
+ assertMutationNotAllowed(copy);
+
+ // Mutate the original backing collection and ensure it's not reflected in copy.
+ original.put(key0, new Object());
+ assertSame(value0, copy.get(key0));
+
+ try {
+ Map.copyOf(null);
+ throw new AssertionError();
+ } catch (NullPointerException expected) {
+ }
+ try {
+ Map<Object, Object> map = new HashMap<>();
+ map.put(null, new Object());
+ Map.copyOf(map);
+ throw new AssertionError();
+ } catch (NullPointerException expected) {
+ }
+ try {
+ Map<Object, Object> map = new HashMap<>();
+ map.put(new Object(), null);
+ Map.copyOf(map);
+ throw new AssertionError();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ private static void assertMutationNotAllowed(Map<Object, Object> ofObject) {
+ try {
+ ofObject.put(new Object(), new Object());
+ throw new AssertionError();
+ } catch (UnsupportedOperationException expected) {
+ }
+ for (Map.Entry<Object, Object> entry : ofObject.entrySet()) {
+ try {
+ entry.setValue(new Object());
+ throw new AssertionError();
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+ }
+
+ private static void assertSame(Object expected, Object actual) {
+ if (expected != actual) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+ }
+ }
+
+ private static void assertEquals(Object expected, Object actual) {
+ if (expected != actual && !expected.equals(actual)) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+ }
+ }
+}
diff --git a/src/test/examplesJava10/backport/OptionalBackportJava10Main.java b/src/test/examplesJava10/backport/OptionalBackportJava10Main.java
new file mode 100644
index 0000000..3d2c919
--- /dev/null
+++ b/src/test/examplesJava10/backport/OptionalBackportJava10Main.java
@@ -0,0 +1,32 @@
+// 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 backport;
+
+import java.util.NoSuchElementException;
+import java.util.Optional;
+
+public final class OptionalBackportJava10Main {
+
+ public static void main(String[] args) {
+ testOrElseThrow();
+ }
+
+ private static void testOrElseThrow() {
+ Optional<String> present = Optional.of("hey");
+ assertEquals("hey", present.orElseThrow());
+
+ Optional<String> absent = Optional.empty();
+ try {
+ throw new AssertionError(absent.orElseThrow());
+ } catch (NoSuchElementException expected) {
+ }
+ }
+
+ private static void assertEquals(Object expected, Object actual) {
+ if (expected != actual && !expected.equals(actual)) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+ }
+ }
+}
diff --git a/src/test/examplesJava10/backport/OptionalDoubleBackportJava10Main.java b/src/test/examplesJava10/backport/OptionalDoubleBackportJava10Main.java
new file mode 100644
index 0000000..1c27538
--- /dev/null
+++ b/src/test/examplesJava10/backport/OptionalDoubleBackportJava10Main.java
@@ -0,0 +1,32 @@
+// 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 backport;
+
+import java.util.NoSuchElementException;
+import java.util.OptionalDouble;
+
+public final class OptionalDoubleBackportJava10Main {
+
+ public static void main(String[] args) {
+ testOrElseThrow();
+ }
+
+ private static void testOrElseThrow() {
+ OptionalDouble present = OptionalDouble.of(2d);
+ assertEquals(2d, present.orElseThrow());
+
+ OptionalDouble absent = OptionalDouble.empty();
+ try {
+ throw new AssertionError(absent.orElseThrow());
+ } catch (NoSuchElementException expected) {
+ }
+ }
+
+ private static void assertEquals(Object expected, Object actual) {
+ if (expected != actual && !expected.equals(actual)) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+ }
+ }
+}
diff --git a/src/test/examplesJava10/backport/OptionalIntBackportJava10Main.java b/src/test/examplesJava10/backport/OptionalIntBackportJava10Main.java
new file mode 100644
index 0000000..06c85f5
--- /dev/null
+++ b/src/test/examplesJava10/backport/OptionalIntBackportJava10Main.java
@@ -0,0 +1,32 @@
+// 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 backport;
+
+import java.util.NoSuchElementException;
+import java.util.OptionalInt;
+
+public final class OptionalIntBackportJava10Main {
+
+ public static void main(String[] args) {
+ testOrElseThrow();
+ }
+
+ private static void testOrElseThrow() {
+ OptionalInt present = OptionalInt.of(2);
+ assertEquals(2, present.orElseThrow());
+
+ OptionalInt absent = OptionalInt.empty();
+ try {
+ throw new AssertionError(absent.orElseThrow());
+ } catch (NoSuchElementException expected) {
+ }
+ }
+
+ private static void assertEquals(Object expected, Object actual) {
+ if (expected != actual && !expected.equals(actual)) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+ }
+ }
+}
diff --git a/src/test/examplesJava10/backport/OptionalLongBackportJava10Main.java b/src/test/examplesJava10/backport/OptionalLongBackportJava10Main.java
new file mode 100644
index 0000000..e92b9a5
--- /dev/null
+++ b/src/test/examplesJava10/backport/OptionalLongBackportJava10Main.java
@@ -0,0 +1,32 @@
+// 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 backport;
+
+import java.util.NoSuchElementException;
+import java.util.OptionalLong;
+
+public final class OptionalLongBackportJava10Main {
+
+ public static void main(String[] args) {
+ testOrElseThrow();
+ }
+
+ private static void testOrElseThrow() {
+ OptionalLong present = OptionalLong.of(2L);
+ assertEquals(2L, present.orElseThrow());
+
+ OptionalLong absent = OptionalLong.empty();
+ try {
+ throw new AssertionError(absent.orElseThrow());
+ } catch (NoSuchElementException expected) {
+ }
+ }
+
+ private static void assertEquals(Object expected, Object actual) {
+ if (expected != actual && !expected.equals(actual)) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+ }
+ }
+}
diff --git a/src/test/examplesJava10/backport/SetBackportJava10Main.java b/src/test/examplesJava10/backport/SetBackportJava10Main.java
new file mode 100644
index 0000000..b8fb356
--- /dev/null
+++ b/src/test/examplesJava10/backport/SetBackportJava10Main.java
@@ -0,0 +1,74 @@
+// 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 backport;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class SetBackportJava10Main {
+
+ public static void main(String[] args) {
+ testCopyOf();
+ }
+
+ private static void testCopyOf() {
+ Object anObject0 = new Object();
+ Object anObject1 = new Object();
+ List<Object> original = Arrays.asList(anObject0, anObject1);
+ Set<Object> copy = Set.copyOf(original);
+ assertEquals(2, copy.size());
+ assertEquals(new HashSet<>(original), copy);
+ assertTrue(copy.contains(anObject0));
+ assertTrue(copy.contains(anObject1));
+ assertMutationNotAllowed(copy);
+
+ // Mutate the original backing collection and ensure it's not reflected in copy.
+ Object newObject = new Object();
+ original.set(0, newObject);
+ assertFalse(copy.contains(newObject));
+
+ // Ensure duplicates are allowed and are de-duped.
+ assertEquals(Set.of(1, 2), Set.copyOf(List.of(1, 2, 1, 2)));
+
+ try {
+ Set.copyOf(null);
+ throw new AssertionError();
+ } catch (NullPointerException expected) {
+ }
+ try {
+ Set.copyOf(Arrays.asList(1, null, 2));
+ throw new AssertionError();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ private static void assertMutationNotAllowed(Set<Object> ofObject) {
+ try {
+ ofObject.add(new Object());
+ throw new AssertionError();
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ private static void assertTrue(boolean value) {
+ if (!value) {
+ throw new AssertionError("Expected <true> but was <false>");
+ }
+ }
+
+ private static void assertFalse(boolean value) {
+ if (value) {
+ throw new AssertionError("Expected <false> but was <true>");
+ }
+ }
+
+ private static void assertEquals(Object expected, Object actual) {
+ if (expected != actual && !expected.equals(actual)) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+ }
+ }
+}
diff --git a/src/test/examplesJava11/backport/OptionalBackportJava11Main.java b/src/test/examplesJava11/backport/OptionalBackportJava11Main.java
new file mode 100644
index 0000000..d1f6fa1
--- /dev/null
+++ b/src/test/examplesJava11/backport/OptionalBackportJava11Main.java
@@ -0,0 +1,34 @@
+// 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 backport;
+
+import java.util.Optional;
+
+public final class OptionalBackportJava11Main {
+
+ public static void main(String[] args) {
+ testIsEmpty();
+ }
+
+ private static void testIsEmpty() {
+ Optional<String> present = Optional.of("hey");
+ assertFalse(present.isEmpty());
+
+ Optional<String> absent = Optional.empty();
+ assertTrue(absent.isEmpty());
+ }
+
+ private static void assertTrue(boolean value) {
+ if (!value) {
+ throw new AssertionError("Expected <true> but was <false>");
+ }
+ }
+
+ private static void assertFalse(boolean value) {
+ if (value) {
+ throw new AssertionError("Expected <false> but was <true>");
+ }
+ }
+}
diff --git a/src/test/examplesJava11/backport/OptionalDoubleBackportJava11Main.java b/src/test/examplesJava11/backport/OptionalDoubleBackportJava11Main.java
new file mode 100644
index 0000000..1fa5617
--- /dev/null
+++ b/src/test/examplesJava11/backport/OptionalDoubleBackportJava11Main.java
@@ -0,0 +1,34 @@
+// 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 backport;
+
+import java.util.OptionalDouble;
+
+public final class OptionalDoubleBackportJava11Main {
+
+ public static void main(String[] args) {
+ testIsEmpty();
+ }
+
+ private static void testIsEmpty() {
+ OptionalDouble present = OptionalDouble.of(2d);
+ assertFalse(present.isEmpty());
+
+ OptionalDouble absent = OptionalDouble.empty();
+ assertTrue(absent.isEmpty());
+ }
+
+ private static void assertTrue(boolean value) {
+ if (!value) {
+ throw new AssertionError("Expected <true> but was <false>");
+ }
+ }
+
+ private static void assertFalse(boolean value) {
+ if (value) {
+ throw new AssertionError("Expected <false> but was <true>");
+ }
+ }
+}
diff --git a/src/test/examplesJava11/backport/OptionalIntBackportJava11Main.java b/src/test/examplesJava11/backport/OptionalIntBackportJava11Main.java
new file mode 100644
index 0000000..9d1a09a
--- /dev/null
+++ b/src/test/examplesJava11/backport/OptionalIntBackportJava11Main.java
@@ -0,0 +1,34 @@
+// 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 backport;
+
+import java.util.OptionalInt;
+
+public final class OptionalIntBackportJava11Main {
+
+ public static void main(String[] args) {
+ testIsEmpty();
+ }
+
+ private static void testIsEmpty() {
+ OptionalInt present = OptionalInt.of(2);
+ assertFalse(present.isEmpty());
+
+ OptionalInt absent = OptionalInt.empty();
+ assertTrue(absent.isEmpty());
+ }
+
+ private static void assertTrue(boolean value) {
+ if (!value) {
+ throw new AssertionError("Expected <true> but was <false>");
+ }
+ }
+
+ private static void assertFalse(boolean value) {
+ if (value) {
+ throw new AssertionError("Expected <false> but was <true>");
+ }
+ }
+}
diff --git a/src/test/examplesJava11/backport/OptionalLongBackportJava11Main.java b/src/test/examplesJava11/backport/OptionalLongBackportJava11Main.java
new file mode 100644
index 0000000..573bbba
--- /dev/null
+++ b/src/test/examplesJava11/backport/OptionalLongBackportJava11Main.java
@@ -0,0 +1,34 @@
+// 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 backport;
+
+import java.util.OptionalLong;
+
+public final class OptionalLongBackportJava11Main {
+
+ public static void main(String[] args) {
+ testIsEmpty();
+ }
+
+ private static void testIsEmpty() {
+ OptionalLong present = OptionalLong.of(2L);
+ assertFalse(present.isEmpty());
+
+ OptionalLong absent = OptionalLong.empty();
+ assertTrue(absent.isEmpty());
+ }
+
+ private static void assertTrue(boolean value) {
+ if (!value) {
+ throw new AssertionError("Expected <true> but was <false>");
+ }
+ }
+
+ private static void assertFalse(boolean value) {
+ if (value) {
+ throw new AssertionError("Expected <false> but was <true>");
+ }
+ }
+}
diff --git a/src/test/examplesJava9/backport/MathBackportJava9Main.java b/src/test/examplesJava9/backport/MathBackportJava9Main.java
index 5eefb65..9030283 100644
--- a/src/test/examplesJava9/backport/MathBackportJava9Main.java
+++ b/src/test/examplesJava9/backport/MathBackportJava9Main.java
@@ -4,10 +4,14 @@
package backport;
+import java.math.BigInteger;
+
public class MathBackportJava9Main {
public static void main(String[] args) {
testMultiplyExactLongInt();
+ testMultiplyFull();
+ testMultiplyHigh();
testFloorDivLongInt();
testFloorModLongInt();
}
@@ -26,6 +30,37 @@
}
}
+ public static void testMultiplyFull() {
+ assertEquals(8L, Math.multiplyFull(2, 4));
+ assertEquals(4611686014132420609L,
+ Math.multiplyFull(Integer.MAX_VALUE, Integer.MAX_VALUE));
+ assertEquals(-4611686016279904256L,
+ Math.multiplyFull(Integer.MAX_VALUE, Integer.MIN_VALUE));
+ assertEquals(4611686018427387904L,
+ Math.multiplyFull(Integer.MIN_VALUE, Integer.MIN_VALUE));
+ }
+
+ public static void testMultiplyHigh() {
+ long[] interestingValues = {
+ Long.MIN_VALUE, Long.MAX_VALUE,
+ Integer.MIN_VALUE, Integer.MAX_VALUE,
+ Short.MIN_VALUE, Short.MAX_VALUE,
+ Byte.MIN_VALUE, Byte.MAX_VALUE,
+ 0L,
+ -1L, 1L,
+ -42L, 42L
+ };
+ for (long x : interestingValues) {
+ for (long y : interestingValues) {
+ long expected = BigInteger.valueOf(x)
+ .multiply(BigInteger.valueOf(y))
+ .shiftRight(64)
+ .longValue();
+ assertEquals(expected, Math.multiplyHigh(x, y));
+ }
+ }
+ }
+
public static void testFloorDivLongInt() {
assertEquals(1L, Math.floorDiv(4L, 4));
assertEquals(1L, Math.floorDiv(-4L, -4));
diff --git a/src/test/examplesJava9/backport/OptionalBackportJava9Main.java b/src/test/examplesJava9/backport/OptionalBackportJava9Main.java
index b337875..c25226f 100644
--- a/src/test/examplesJava9/backport/OptionalBackportJava9Main.java
+++ b/src/test/examplesJava9/backport/OptionalBackportJava9Main.java
@@ -5,9 +5,6 @@
package backport;
import java.util.Optional;
-import java.util.OptionalDouble;
-import java.util.OptionalInt;
-import java.util.OptionalLong;
public final class OptionalBackportJava9Main {
@@ -15,9 +12,6 @@
testOr();
testOrNull();
testIfPresentOrElse();
- testIfPresentOrElseInt();
- testIfPresentOrElseLong();
- testIfPresentOrElseDouble();
testStream();
}
@@ -69,27 +63,6 @@
emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
}
- private static void testIfPresentOrElseInt() {
- OptionalInt value = OptionalInt.of(1);
- OptionalInt emptyValue = OptionalInt.empty();
- value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
- emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
- }
-
- private static void testIfPresentOrElseLong() {
- OptionalLong value = OptionalLong.of(1L);
- OptionalLong emptyValue = OptionalLong.empty();
- value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
- emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
- }
-
- private static void testIfPresentOrElseDouble() {
- OptionalDouble value = OptionalDouble.of(1.0d);
- OptionalDouble emptyValue = OptionalDouble.empty();
- value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
- emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
- }
-
private static void testStream() {
Optional<String> value = Optional.of("value");
Optional<String> emptyValue = Optional.empty();
diff --git a/src/test/examplesJava9/backport/OptionalDoubleBackportJava9Main.java b/src/test/examplesJava9/backport/OptionalDoubleBackportJava9Main.java
new file mode 100644
index 0000000..9b08718
--- /dev/null
+++ b/src/test/examplesJava9/backport/OptionalDoubleBackportJava9Main.java
@@ -0,0 +1,35 @@
+// 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 backport;
+
+import java.util.OptionalDouble;
+
+public final class OptionalDoubleBackportJava9Main {
+
+ public static void main(String[] args) {
+ testIfPresentOrElseDouble();
+ testStreamDouble();
+ }
+
+ private static void testIfPresentOrElseDouble() {
+ OptionalDouble value = OptionalDouble.of(1.0d);
+ OptionalDouble emptyValue = OptionalDouble.empty();
+ value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
+ emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
+ }
+
+ private static void testStreamDouble() {
+ OptionalDouble value = OptionalDouble.of(2d);
+ OptionalDouble emptyValue = OptionalDouble.empty();
+ assertTrue(value.stream().count() == 1);
+ assertTrue(emptyValue.stream().count() == 0);
+ }
+
+ private static void assertTrue(boolean value) {
+ if (!value) {
+ throw new AssertionError("Expected <true> but was <false>");
+ }
+ }
+}
diff --git a/src/test/examplesJava9/backport/OptionalIntBackportJava9Main.java b/src/test/examplesJava9/backport/OptionalIntBackportJava9Main.java
new file mode 100644
index 0000000..fedc472
--- /dev/null
+++ b/src/test/examplesJava9/backport/OptionalIntBackportJava9Main.java
@@ -0,0 +1,35 @@
+// 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 backport;
+
+import java.util.OptionalInt;
+
+public final class OptionalIntBackportJava9Main {
+
+ public static void main(String[] args) {
+ testIfPresentOrElseInt();
+ testStreamInt();
+ }
+
+ private static void testIfPresentOrElseInt() {
+ OptionalInt value = OptionalInt.of(1);
+ OptionalInt emptyValue = OptionalInt.empty();
+ value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
+ emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
+ }
+
+ private static void testStreamInt() {
+ OptionalInt value = OptionalInt.of(2);
+ OptionalInt emptyValue = OptionalInt.empty();
+ assertTrue(value.stream().count() == 1);
+ assertTrue(emptyValue.stream().count() == 0);
+ }
+
+ private static void assertTrue(boolean value) {
+ if (!value) {
+ throw new AssertionError("Expected <true> but was <false>");
+ }
+ }
+}
diff --git a/src/test/examplesJava9/backport/OptionalLongBackportJava9Main.java b/src/test/examplesJava9/backport/OptionalLongBackportJava9Main.java
new file mode 100644
index 0000000..07438e1
--- /dev/null
+++ b/src/test/examplesJava9/backport/OptionalLongBackportJava9Main.java
@@ -0,0 +1,35 @@
+// 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 backport;
+
+import java.util.OptionalLong;
+
+public final class OptionalLongBackportJava9Main {
+
+ public static void main(String[] args) {
+ testIfPresentOrElseLong();
+ testStreamLong();
+ }
+
+ private static void testIfPresentOrElseLong() {
+ OptionalLong value = OptionalLong.of(1L);
+ OptionalLong emptyValue = OptionalLong.empty();
+ value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
+ emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
+ }
+
+ private static void testStreamLong() {
+ OptionalLong value = OptionalLong.of(2L);
+ OptionalLong emptyValue = OptionalLong.empty();
+ assertTrue(value.stream().count() == 1);
+ assertTrue(emptyValue.stream().count() == 0);
+ }
+
+ private static void assertTrue(boolean value) {
+ if (!value) {
+ throw new AssertionError("Expected <true> but was <false>");
+ }
+ }
+}
diff --git a/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java b/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java
index b711539..e9c33ca 100644
--- a/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java
+++ b/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java
@@ -4,10 +4,13 @@
package backport;
+import java.math.BigInteger;
+
public class StrictMathBackportJava9Main {
public static void main(String[] args) {
testMultiplyExactLongInt();
+ testMultiplyFull();
testFloorDivLongInt();
testFloorModLongInt();
}
@@ -26,6 +29,37 @@
}
}
+ public static void testMultiplyFull() {
+ assertEquals(8L, StrictMath.multiplyFull(2, 4));
+ assertEquals(4611686014132420609L,
+ StrictMath.multiplyFull(Integer.MAX_VALUE, Integer.MAX_VALUE));
+ assertEquals(-4611686016279904256L,
+ StrictMath.multiplyFull(Integer.MAX_VALUE, Integer.MIN_VALUE));
+ assertEquals(4611686018427387904L,
+ StrictMath.multiplyFull(Integer.MIN_VALUE, Integer.MIN_VALUE));
+ }
+
+ public static void testMultiplyHigh() {
+ long[] interestingValues = {
+ Long.MIN_VALUE, Long.MAX_VALUE,
+ Integer.MIN_VALUE, Integer.MAX_VALUE,
+ Short.MIN_VALUE, Short.MAX_VALUE,
+ Byte.MIN_VALUE, Byte.MAX_VALUE,
+ 0L,
+ -1L, 1L,
+ -42L, 42L
+ };
+ for (long x : interestingValues) {
+ for (long y : interestingValues) {
+ long expected = BigInteger.valueOf(x)
+ .multiply(BigInteger.valueOf(y))
+ .shiftRight(64)
+ .longValue();
+ assertEquals(expected, StrictMath.multiplyHigh(x, y));
+ }
+ }
+ }
+
public static void testFloorDivLongInt() {
assertEquals(1L, StrictMath.floorDiv(4L, 4));
assertEquals(1L, StrictMath.floorDiv(-4L, -4));
diff --git a/src/test/java/com/android/tools/r8/GenerateMainDexListTestBuilder.java b/src/test/java/com/android/tools/r8/GenerateMainDexListTestBuilder.java
index 3ceeb97..e0f3cea 100644
--- a/src/test/java/com/android/tools/r8/GenerateMainDexListTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/GenerateMainDexListTestBuilder.java
@@ -46,6 +46,7 @@
throw new Unimplemented("No support for running with a main class");
}
+ @Override
public DebugTestConfig debugConfig() {
throw new Unimplemented("No support for debug configuration");
}
diff --git a/src/test/java/com/android/tools/r8/JvmTestBuilder.java b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
index e44287f..bef8a14 100644
--- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -44,6 +44,7 @@
return run(TestRuntime.getDefaultJavaRuntime(), mainClass);
}
+ @Override
public JvmTestRunResult run(TestRuntime runtime, String mainClass, String... args)
throws IOException {
assert runtime.isCf();
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 8e3e149..59ae602 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -35,7 +35,7 @@
}
private boolean enableInliningAnnotations = false;
- private boolean enableClassInliningAnnotations = false;
+ private boolean enableNeverClassInliningAnnotations = false;
private boolean enableMergeAnnotations = false;
private boolean enableMemberValuePropagationAnnotations = false;
private boolean enableConstantArgumentAnnotations = false;
@@ -51,7 +51,7 @@
Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
throws CompilationFailedException {
if (enableInliningAnnotations
- || enableClassInliningAnnotations
+ || enableNeverClassInliningAnnotations
|| enableMergeAnnotations
|| enableMemberValuePropagationAnnotations
|| enableConstantArgumentAnnotations
@@ -239,9 +239,9 @@
return self();
}
- public T enableClassInliningAnnotations() {
- if (!enableClassInliningAnnotations) {
- enableClassInliningAnnotations = true;
+ public T enableNeverClassInliningAnnotations() {
+ if (!enableNeverClassInliningAnnotations) {
+ enableNeverClassInliningAnnotations = true;
addInternalKeepRules("-neverclassinline @com.android.tools.r8.NeverClassInline class *");
}
return self();
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index 94b0afc..27af1aa 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -5,10 +5,12 @@
import com.android.tools.r8.debug.DebugTestConfig;
import com.android.tools.r8.utils.ListUtils;
+import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import java.util.concurrent.ExecutionException;
public abstract class TestBuilder<RR extends TestRunResult, T extends TestBuilder<RR, T>> {
@@ -110,6 +112,26 @@
return addLibraryFiles(Arrays.asList(files));
}
+ public final T addTestingAnnotationsAsProgramClasses() {
+ return addProgramClasses(getTestingAnnotations());
+ }
+
+ public final T addTestingAnnotationsAsLibraryClasses() {
+ return addLibraryClasses(getTestingAnnotations());
+ }
+
+ private List<Class<?>> getTestingAnnotations() {
+ return ImmutableList.of(
+ AssumeMayHaveSideEffects.class,
+ ForceInline.class,
+ KeepConstantArguments.class,
+ KeepUnusedArguments.class,
+ NeverClassInline.class,
+ NeverInline.class,
+ NeverMerge.class,
+ NeverPropagateValue.class);
+ }
+
static Collection<Path> getFilesForClasses(Collection<Class<?>> classes) {
return ListUtils.map(classes, ToolHelper::getClassFileForTestClass);
}
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index af1b81e..3b368b6 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -61,8 +61,6 @@
}
}
- abstract T self();
-
abstract CR internalCompile(
B builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
throws CompilationFailedException;
diff --git a/src/test/java/com/android/tools/r8/TestRunResult.java b/src/test/java/com/android/tools/r8/TestRunResult.java
index f286bac..e1ebfa2 100644
--- a/src/test/java/com/android/tools/r8/TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@@ -90,6 +91,15 @@
return self();
}
+ public RR assertFailureWithErrorThatThrows(Class<? extends Throwable> expectedError) {
+ assertFailure();
+ assertThat(
+ errorMessage("Run stderr incorrect.", expectedError.getName()),
+ result.stderr,
+ containsString(expectedError.getName()));
+ return self();
+ }
+
public RR assertStderrMatches(Matcher<String> matcher) {
assertThat(errorMessage("Run stderr incorrect.", matcher.toString()), result.stderr, matcher);
return self();
diff --git a/src/test/java/com/android/tools/r8/TestRuntime.java b/src/test/java/com/android/tools/r8/TestRuntime.java
index 6347853..99f9a71 100644
--- a/src/test/java/com/android/tools/r8/TestRuntime.java
+++ b/src/test/java/com/android/tools/r8/TestRuntime.java
@@ -25,7 +25,9 @@
public enum CfVm {
JDK8("jdk8", 52),
JDK9("jdk9", 53),
- JDK11("jdk11", 55);
+ JDK10("jdk10", 54),
+ JDK11("jdk11", 55),
+ ;
private final String name;
private final int classfileVersion;
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index c0a5ee0..87b2806 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -107,6 +107,7 @@
public static final String EXAMPLES_ANDROID_O_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidO/";
public static final String EXAMPLES_ANDROID_P_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidP/";
public static final String EXAMPLES_JAVA9_BUILD_DIR = TESTS_BUILD_DIR + "examplesJava9/";
+ public static final String EXAMPLES_JAVA10_BUILD_DIR = TESTS_BUILD_DIR + "examplesJava10/";
public static final String EXAMPLES_JAVA11_JAR_DIR = TESTS_BUILD_DIR + "examplesJava11/";
public static final String EXAMPLES_JAVA11_BUILD_DIR = BUILD_DIR + "classes/java/examplesJava11/";
public static final String EXAMPLES_PROTO_BUILD_DIR = TESTS_BUILD_DIR + "examplesProto/";
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/NoRelaxationForSerializableTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/NoRelaxationForSerializableTest.java
index 294ee96..b9883ef 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/NoRelaxationForSerializableTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/NoRelaxationForSerializableTest.java
@@ -82,8 +82,7 @@
@RunWith(Parameterized.class)
public class NoRelaxationForSerializableTest extends AccessRelaxationTestBase {
private static final Class<?> MAIN = NoRelaxationForSerializableTestRunner.class;
- private static final List<Class<?>> CLASSES = ImmutableList.of(
- NeverMerge.class, NeverInline.class, MySerializable.class, MAIN);
+ private static final List<Class<?>> CLASSES = ImmutableList.of(MySerializable.class, MAIN);
private static final String KEEPMEMBER_RULES = StringUtils.lines(
"-keepclassmembers class * implements java.io.Serializable {",
" private void writeObject(java.io.ObjectOutputStream);",
@@ -101,7 +100,8 @@
@Parameterized.Parameters(name = "{0}, access-modification: {1}")
public static List<Object[]> data() {
- return buildParameters(getTestParameters().withAllRuntimes().build(), BooleanUtils.values());
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
}
public NoRelaxationForSerializableTest(TestParameters parameters, boolean accessModification) {
@@ -123,6 +123,7 @@
assumeTrue(parameters.isCfRuntime());
testForProguard()
.addProgramClasses(CLASSES)
+ .addTestingAnnotationsAsProgramClasses()
.addKeepRuleFiles(configuration)
.addKeepRules(KEEPMEMBER_RULES)
.compile()
@@ -133,14 +134,15 @@
@Test
public void testR8_withKeepRules() throws Exception {
- R8TestCompileResult result = testForR8(parameters.getBackend())
- .addProgramClasses(CLASSES)
- .enableInliningAnnotations()
- .addKeepRuleFiles(configuration)
- .addKeepRules(KEEPMEMBER_RULES)
- .setMinApi(parameters.getRuntime())
- .compile()
- .inspect(this::inspect);
+ R8TestCompileResult result =
+ testForR8(parameters.getBackend())
+ .addProgramClasses(CLASSES)
+ .enableInliningAnnotations()
+ .addKeepRuleFiles(configuration)
+ .addKeepRules(KEEPMEMBER_RULES)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect);
// TODO(b/117302947): Need to update ART binary.
if (parameters.isCfRuntime()) {
result
@@ -154,20 +156,22 @@
assumeTrue(parameters.isCfRuntime());
testForProguard()
.addProgramClasses(CLASSES)
+ .addTestingAnnotationsAsProgramClasses()
.addKeepRuleFiles(configuration)
.compile()
- .run(MAIN)
+ .run(parameters.getRuntime(), MAIN)
.assertFailureWithErrorThatMatches(containsString("Could not deserialize"));
}
@Test
public void testR8_withoutKeepRules() throws Exception {
- R8TestCompileResult result = testForR8(parameters.getBackend())
- .addProgramClasses(CLASSES)
- .enableInliningAnnotations()
- .addKeepRuleFiles(configuration)
- .setMinApi(parameters.getRuntime())
- .compile();
+ R8TestCompileResult result =
+ testForR8(parameters.getBackend())
+ .addProgramClasses(CLASSES)
+ .enableInliningAnnotations()
+ .addKeepRuleFiles(configuration)
+ .setMinApi(parameters.getApiLevel())
+ .compile();
// TODO(b/117302947): Need to update ART binary.
if (parameters.isCfRuntime()) {
result
@@ -182,5 +186,4 @@
assertNotPublic(inspector, MySerializable.class,
new MethodSignature("readObject", "void", ImmutableList.of("java.io.ObjectInputStream")));
}
-
}
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
index f203ade..7756299 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
@@ -36,7 +36,8 @@
@Parameterized.Parameters(name = "{0}, argument removal: {1}")
public static List<Object[]> data() {
- return buildParameters(getTestParameters().withAllRuntimes().build(), BooleanUtils.values());
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
}
public NonConstructorRelaxationTest(TestParameters parameters, boolean enableArgumentRemoval) {
@@ -99,7 +100,7 @@
" *** pBlah1();",
"}")
.allowAccessModification()
- .setMinApi(parameters.getRuntime())
+ .setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), mainClass);
assertEquals(
@@ -157,6 +158,7 @@
.addProgramFiles(ToolHelper.getClassFilesForTestPackage(mainClass.getPackage()))
.addKeepMainRule(mainClass)
.addOptionsModification(o -> o.enableVerticalClassMerging = enableVerticalClassMerging)
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.enableMemberValuePropagationAnnotations()
.noMinification()
@@ -171,7 +173,7 @@
" *** p*();",
"}")
.allowAccessModification()
- .setMinApi(parameters.getRuntime())
+ .setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), mainClass);
assertEquals(
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub1.java b/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub1.java
index 0793001..b45a708 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub1.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub1.java
@@ -3,8 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.accessrelaxation.privateinstance;
+import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
+@NeverClassInline
public class Sub1 extends Base implements Itf1 {
@Override
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub2.java b/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub2.java
index 018bc90..fbc2ebc 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub2.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub2.java
@@ -3,8 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.accessrelaxation.privateinstance;
+import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
+@NeverClassInline
public class Sub2 extends Base implements Itf2 {
@Override
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/KeepNonVisibilityBridgeMethodsTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/KeepNonVisibilityBridgeMethodsTest.java
index c188c87..3b7481b 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/KeepNonVisibilityBridgeMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/KeepNonVisibilityBridgeMethodsTest.java
@@ -51,7 +51,7 @@
" synthetic void registerObserver(...);",
"}")
.allowAccessModification()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
// TODO(b/120764902): MemberSubject.getOriginalName() is not working without the @NeverMerge
// annotation on DataAdapter.Observer.
.enableMergeAnnotations()
diff --git a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedOverriddenMethodTest.java b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedOverriddenMethodTest.java
index 851fff9..3f5b778 100644
--- a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedOverriddenMethodTest.java
+++ b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedOverriddenMethodTest.java
@@ -46,7 +46,7 @@
.addKeepMainRule(main)
.addKeepRules(
"-checkdiscard class **.*$" + targetClass.getSimpleName() + " { void gone(); }")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.enableMergeAnnotations()
.minification(minification)
diff --git a/src/test/java/com/android/tools/r8/classmerging/B141942381.java b/src/test/java/com/android/tools/r8/classmerging/B141942381.java
index 438ab13..2c47534 100644
--- a/src/test/java/com/android/tools/r8/classmerging/B141942381.java
+++ b/src/test/java/com/android/tools/r8/classmerging/B141942381.java
@@ -51,7 +51,7 @@
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getRuntime())
.addKeepAttributes("Signatures")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.noMinification()
.compile()
.inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/classmerging/InterfaceWithProxyTest.java b/src/test/java/com/android/tools/r8/classmerging/InterfaceWithProxyTest.java
index 8284d3f..03f5803 100644
--- a/src/test/java/com/android/tools/r8/classmerging/InterfaceWithProxyTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/InterfaceWithProxyTest.java
@@ -35,7 +35,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InterfaceWithProxyTest.class)
.addKeepMainRule(TestClass.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/StaticClassMergerInterfaceTest.java b/src/test/java/com/android/tools/r8/classmerging/StaticClassMergerInterfaceTest.java
index f37eab0..b0557d3 100644
--- a/src/test/java/com/android/tools/r8/classmerging/StaticClassMergerInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/StaticClassMergerInterfaceTest.java
@@ -44,7 +44,7 @@
.addKeepMainRule(TestClass.class)
.addKeepRules("-dontobfuscate")
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.run(TestClass.class)
.assertSuccessWithOutput(expectedOutput)
.inspector();
diff --git a/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerInitTest.java b/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerInitTest.java
index 1c4f406..b95a89a 100644
--- a/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerInitTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerInitTest.java
@@ -8,6 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -45,6 +46,7 @@
.addInnerClasses(VerticalClassMergerInitTest.class)
.addKeepMainRule(Main.class)
.addMainDexRules("-keep class " + Main.class.getTypeName())
+ .enableNeverClassInliningAnnotations()
.setMinApi(AndroidApiLevel.K_WATCH)
.addOptionsModification(
options -> {
@@ -76,6 +78,7 @@
}
}
+ @NeverClassInline
public static class Child extends Base {
// We need a static member to force the main-dex tracing to include Child and Base.
diff --git a/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerTest.java
index fc3f22f..7fab7a1 100644
--- a/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerTest.java
@@ -509,8 +509,8 @@
" 1:1:void <init>():14:14 -> <init>",
" 2:2:void <init>():16:16 -> <init>",
"classmerging.ProguardFieldMapTest$B -> classmerging.ProguardFieldMapTest$B:",
- " 1:1:void <init>():19:19 -> <init>",
- " 1:1:void test():22:22 -> test");
+ " 1:1:void <init>():20:20 -> <init>",
+ " 1:1:void test():23:23 -> test");
runTestOnInput(
main,
readProgramFiles(programFiles),
@@ -536,10 +536,10 @@
"classmerging.ProguardFieldMapTest$B -> classmerging.ProguardFieldMapTest$B:",
" java.lang.String classmerging.ProguardFieldMapTest$A.f -> f",
" 1:1:void classmerging.ProguardFieldMapTest$A.<init>():14:14 -> <init>",
- " 1:1:void <init>():19 -> <init>",
+ " 1:1:void <init>():20 -> <init>",
" 2:2:void classmerging.ProguardFieldMapTest$A.<init>():16:16 -> <init>",
- " 2:2:void <init>():19 -> <init>",
- " 1:1:void test():22:22 -> test");
+ " 2:2:void <init>():20 -> <init>",
+ " 1:1:void test():23:23 -> test");
Set<String> preservedClassNames =
ImmutableSet.of("classmerging.ProguardFieldMapTest", "classmerging.ProguardFieldMapTest$B");
runTestOnInput(
@@ -577,8 +577,8 @@
" 1:1:void <init>():14:14 -> <init>",
" 1:1:void method():17:17 -> method",
"classmerging.ProguardMethodMapTest$B -> classmerging.ProguardMethodMapTest$B:",
- " 1:1:void <init>():21:21 -> <init>",
- " 1:2:void method():25:26 -> method");
+ " 1:1:void <init>():22:22 -> <init>",
+ " 1:2:void method():26:27 -> method");
runTestOnInput(
main,
readProgramFiles(programFiles),
@@ -606,8 +606,8 @@
// A.<init> has been inlined into B.<init>?
" 1:1:void classmerging.ProguardMethodMapTest$A.<init>():14:14 -> <init>",
// TODO(christofferqa): Should this be " ...<init>():21:21 -> <init>"?
- " 1:1:void <init>():21 -> <init>",
- " 1:2:void method():25:26 -> method",
+ " 1:1:void <init>():22 -> <init>",
+ " 1:2:void method():26:27 -> method",
" 1:1:void classmerging.ProguardMethodMapTest$A.method():17:17 -> "
+ "method$classmerging$ProguardMethodMapTest$A");
Set<String> preservedClassNames =
@@ -647,10 +647,10 @@
"classmerging.ProguardMethodMapTest$A -> classmerging.ProguardMethodMapTest$A:",
" 1:1:void <init>():14:14 -> <init>",
"classmerging.ProguardMethodMapTest$B -> classmerging.ProguardMethodMapTest$B:",
- " 1:1:void <init>():21:21 -> <init>",
- " 1:1:void method():25:25 -> method",
+ " 1:1:void <init>():22:22 -> <init>",
+ " 1:1:void method():26:26 -> method",
" 2:2:void classmerging.ProguardMethodMapTest$A.method():17:17 -> method",
- " 2:2:void method():26 -> method");
+ " 2:2:void method():27 -> method");
runTestOnInput(
main,
readProgramFiles(programFiles),
@@ -677,10 +677,10 @@
" 1:2:void main(java.lang.String[]):10:11 -> main",
"classmerging.ProguardMethodMapTest$B -> classmerging.ProguardMethodMapTest$B:",
" 1:1:void classmerging.ProguardMethodMapTest$A.<init>():14:14 -> <init>",
- " 1:1:void <init>():21 -> <init>",
- " 1:1:void method():25:25 -> method",
+ " 1:1:void <init>():22 -> <init>",
+ " 1:1:void method():26:26 -> method",
" 2:2:void classmerging.ProguardMethodMapTest$A.method():17:17 -> method",
- " 2:2:void method():26 -> method");
+ " 2:2:void method():27 -> method");
Set<String> preservedClassNames =
ImmutableSet.of(
"classmerging.ProguardMethodMapTest", "classmerging.ProguardMethodMapTest$B");
diff --git a/src/test/java/com/android/tools/r8/debug/R8DebugNonMinifiedProgramTestRunner.java b/src/test/java/com/android/tools/r8/debug/R8DebugNonMinifiedProgramTestRunner.java
index ecfc8c1..3f61638 100644
--- a/src/test/java/com/android/tools/r8/debug/R8DebugNonMinifiedProgramTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debug/R8DebugNonMinifiedProgramTestRunner.java
@@ -54,17 +54,19 @@
private static R8TestCompileResult compile(R8FullTestBuilder builder, AndroidApiLevel apiLevel)
throws Exception {
- return builder.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ return builder
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.addProgramClassesAndInnerClasses(CLASS)
.addKeepMainRule(CLASS)
.setMinApi(apiLevel)
.compile()
- .inspect(inspector -> {
- // Check that tree shaking is running (e.g., B is removed).
- assertTrue(inspector.clazz(R8DebugNonMinifiedProgramTest.A.class).isPresent());
- assertFalse(inspector.clazz(R8DebugNonMinifiedProgramTest.B.class).isPresent());
- });
+ .inspect(
+ inspector -> {
+ // Check that tree shaking is running (e.g., B is removed).
+ assertTrue(inspector.clazz(R8DebugNonMinifiedProgramTest.A.class).isPresent());
+ assertFalse(inspector.clazz(R8DebugNonMinifiedProgramTest.B.class).isPresent());
+ });
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
index b89f09a..c04e3eb 100644
--- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.R8TestCompileResult;
-import com.android.tools.r8.TestBase;
import com.android.tools.r8.debug.DebugTestBase;
import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.Command;
import com.android.tools.r8.debug.DebugTestConfig;
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
index 28eefe3..37aa606 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
@@ -31,6 +31,7 @@
public ByteBackportJava9Test(TestParameters parameters) {
super(parameters, Byte.class, TEST_JAR, "backport.ByteBackportJava9Main");
- // TODO Once shipped in an actual API level, migrate to ByteBackportTest
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to ByteBackportTest.
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/CharacterBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/CharacterBackportJava11Test.java
index f1d51fc..9a03c16 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/CharacterBackportJava11Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/CharacterBackportJava11Test.java
@@ -30,7 +30,8 @@
Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
public CharacterBackportJava11Test(TestParameters parameters) {
- super(parameters, Short.class, TEST_JAR, "backport.CharacterBackportJava11Main");
- // TODO Once shipped in an actual API level, migrate to CharacterBackportTest
+ super(parameters, Character.class, TEST_JAR, "backport.CharacterBackportJava11Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to CharacterBackportTest.
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java
new file mode 100644
index 0000000..309b319
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public class ListBackportJava10Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+ .withDexRuntimes()
+ .withAllApiLevels()
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public ListBackportJava10Test(TestParameters parameters) {
+ super(parameters, List.class, TEST_JAR, "backport.ListBackportJava10Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to ListBackportTest.
+
+ // Available since API 1 and used to test created lists.
+ ignoreInvokes("add");
+ ignoreInvokes("get");
+ ignoreInvokes("set");
+ ignoreInvokes("size");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
index a861d1f..03843cc0 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
@@ -32,7 +32,8 @@
public ListBackportJava9Test(TestParameters parameters) {
super(parameters, List.class, TEST_JAR, "backport.ListBackportJava9Main");
- // TODO Once shipped in an actual API level, migrate to ListBackportTest
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to ListBackportTest.
// Available since API 1 and used to test created lists.
ignoreInvokes("add");
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java
new file mode 100644
index 0000000..e54d7d8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public class MapBackportJava10Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+ .withDexRuntimes()
+ .withAllApiLevels()
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public MapBackportJava10Test(TestParameters parameters) {
+ super(parameters, Map.class, TEST_JAR, "backport.MapBackportJava10Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to MapBackportTest.
+
+ // Available since API 1 and used to test created maps.
+ ignoreInvokes("entrySet");
+ ignoreInvokes("get");
+ ignoreInvokes("put");
+ ignoreInvokes("size");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
index 06e41f8..fb39b49 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
@@ -32,7 +32,8 @@
public MapBackportJava9Test(TestParameters parameters) {
super(parameters, Map.class, TEST_JAR, "backport.MapBackportJava9Main");
- // TODO Once shipped in an actual API level, migrate to MapBackportTest
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to MapBackportTest.
// Available since API 1 and used to test created maps.
ignoreInvokes("entrySet");
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
index 439ef38..387697e 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
@@ -31,6 +31,7 @@
public MathBackportJava9Test(TestParameters parameters) {
super(parameters, Math.class, TEST_JAR, "backport.MathBackportJava9Main");
- // TODO Once shipped in an actual API level, migrate to MathBackportTest
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to MathBackportTest.
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
index 7544e87..ef8b990 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
@@ -31,6 +31,7 @@
public ObjectsBackportJava9Test(TestParameters parameters) {
super(parameters, Short.class, TEST_JAR, "backport.ObjectsBackportJava9Main");
- // TODO Once shipped in an actual API level, migrate to ObjectsBackportTest
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to ObjectsBackportTest.
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava10Test.java
new file mode 100644
index 0000000..25d4081
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava10Test.java
@@ -0,0 +1,45 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalBackportJava10Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalBackportJava10Test(TestParameters parameters) {
+ super(parameters, Optional.class, TEST_JAR, "backport.OptionalBackportJava10Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("get");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java
new file mode 100644
index 0000000..dee14c1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalBackportJava11Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK11)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalBackportJava11Test(TestParameters parameters) {
+ super(parameters, Optional.class, TEST_JAR, "backport.OptionalBackportJava11Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java
index d77052a..31bc82f 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Optional;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@@ -32,6 +33,12 @@
Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
public OptionalBackportJava9Test(TestParameters parameters) {
- super(parameters, Short.class, TEST_JAR, "backport.OptionalBackportJava9Main");
+ super(parameters, Optional.class, TEST_JAR, "backport.OptionalBackportJava9Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("of");
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java
new file mode 100644
index 0000000..97d70df
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java
@@ -0,0 +1,46 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalDoubleBackportJava10Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalDoubleBackportJava10Test(TestParameters parameters) {
+ super(parameters, OptionalDouble.class, TEST_JAR, "backport.OptionalDoubleBackportJava10Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("getAsDouble");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java
new file mode 100644
index 0000000..981e1e2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalDouble;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalDoubleBackportJava11Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK11)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalDoubleBackportJava11Test(TestParameters parameters) {
+ super(parameters, OptionalDouble.class, TEST_JAR, "backport.OptionalDoubleBackportJava11Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava9Test.java
new file mode 100644
index 0000000..5aa0e1c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava9Test.java
@@ -0,0 +1,45 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalDoubleBackportJava9Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalDoubleBackportJava9Test(TestParameters parameters) {
+ super(parameters, OptionalDouble.class, TEST_JAR, "backport.OptionalDoubleBackportJava9Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalDoubleBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java
new file mode 100644
index 0000000..b44f1cf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java
@@ -0,0 +1,46 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalIntBackportJava10Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalIntBackportJava10Test(TestParameters parameters) {
+ super(parameters, OptionalInt.class, TEST_JAR, "backport.OptionalIntBackportJava10Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("getAsInt");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java
new file mode 100644
index 0000000..e594db3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalInt;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalIntBackportJava11Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK11)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalIntBackportJava11Test(TestParameters parameters) {
+ super(parameters, OptionalInt.class, TEST_JAR, "backport.OptionalIntBackportJava11Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava9Test.java
new file mode 100644
index 0000000..71a8dd9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava9Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalInt;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalIntBackportJava9Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalIntBackportJava9Test(TestParameters parameters) {
+ super(parameters, OptionalInt.class, TEST_JAR, "backport.OptionalIntBackportJava9Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalIntBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java
new file mode 100644
index 0000000..a4bef8c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java
@@ -0,0 +1,45 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalLong;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalLongBackportJava10Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalLongBackportJava10Test(TestParameters parameters) {
+ super(parameters, OptionalLong.class, TEST_JAR, "backport.OptionalLongBackportJava10Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("getAsLong");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java
new file mode 100644
index 0000000..bc1f4aa
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalLong;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalLongBackportJava11Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK11)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalLongBackportJava11Test(TestParameters parameters) {
+ super(parameters, OptionalLong.class, TEST_JAR, "backport.OptionalLongBackportJava11Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava9Test.java
new file mode 100644
index 0000000..b0dfd62
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava9Test.java
@@ -0,0 +1,46 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalLong;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalLongBackportJava9Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+ .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public OptionalLongBackportJava9Test(TestParameters parameters) {
+ super(parameters, OptionalLong.class, TEST_JAR, "backport.OptionalLongBackportJava9Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to OptionalLongBackportTest.
+
+ // Available since N as part of library desugaring.
+ ignoreInvokes("empty");
+ ignoreInvokes("getAsLong");
+ ignoreInvokes("isPresent");
+ ignoreInvokes("of");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java
new file mode 100644
index 0000000..5c08b8f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java
@@ -0,0 +1,43 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Set;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public class SetBackportJava10Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+ .withDexRuntimes()
+ .withAllApiLevels()
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+ public SetBackportJava10Test(TestParameters parameters) {
+ super(parameters, Set.class, TEST_JAR, "backport.SetBackportJava10Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to SetBackportTest.
+
+ // Available since API 1 and used to test created sets.
+ ignoreInvokes("add");
+ ignoreInvokes("contains");
+ ignoreInvokes("size");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
index b248e0b..6947ff2 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
@@ -32,7 +32,8 @@
public SetBackportJava9Test(TestParameters parameters) {
super(parameters, Set.class, TEST_JAR, "backport.SetBackportJava9Main");
- // TODO Once shipped in an actual API level, migrate to SetBackportTest
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to SetBackportTest.
// Available since API 1 and used to test created sets.
ignoreInvokes("add");
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
index d56ef5b..beffd8a 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
@@ -31,6 +31,7 @@
public ShortBackportJava9Test(TestParameters parameters) {
super(parameters, Short.class, TEST_JAR, "backport.ShortBackportJava9Main");
- // TODO Once shipped in an actual API level, migrate to ShortBackportTest
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to ShortBackportTest.
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/StreamBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/StreamBackportJava9Test.java
index 0f08ff9..073c179 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/StreamBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/StreamBackportJava9Test.java
@@ -34,6 +34,9 @@
public StreamBackportJava9Test(TestParameters parameters) {
super(parameters, Stream.class, TEST_JAR, "backport.StreamBackportJava9Main");
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to StreamBackportTest.
+
// Available since N as part of library desugaring.
ignoreInvokes("of");
ignoreInvokes("empty");
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java
index 43cbf48..2f124e7 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java
@@ -31,6 +31,7 @@
public StrictMathBackportJava9Test(TestParameters parameters) {
super(parameters, Math.class, TEST_JAR, "backport.StrictMathBackportJava9Main");
- // TODO Once shipped in an actual API level, migrate to MathBackportTest
+ // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+ // an actual API level, migrate these tests to StrictMathBackportTest.
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java
index d00811f..4a92fd8 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static org.junit.Assume.assumeTrue;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
@@ -70,6 +72,28 @@
.assertSuccessWithOutput(EXPECTED_OUTPUT);
}
+ @Test
+ public void testCustomCollectionR8() throws Exception {
+ // Desugared library tests do not make sense in the Cf to Cf, and the JVM is already tested
+ // in the D8 test. Just return.
+ assumeTrue(parameters.isDexRuntime());
+ KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+ testForR8(parameters.getBackend())
+ .addInnerClasses(CustomCollectionInterfaceSuperTest.class)
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .compile()
+ .assertNoMessages()
+ .addDesugaredCoreLibraryRunClassPath(
+ this::buildDesugaredLibrary,
+ parameters.getApiLevel(),
+ keepRuleConsumer.get(),
+ shrinkDesugaredLibrary)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
static class Main {
@SuppressWarnings({
@@ -89,7 +113,7 @@
}
}
- interface MyCol1<E> extends Collection<E> {
+ interface Col1Itf<E> extends Collection<E> {
@Override
default boolean removeIf(Predicate<? super E> filter) {
@@ -98,12 +122,12 @@
}
}
- interface MyCol2<E> extends MyCol1<E> {
+ interface Col2Itf<E> extends Col1Itf<E> {
@Override
default boolean removeIf(Predicate<? super E> filter) {
System.out.println("removeIf from MyCol2");
- return MyCol1.super.removeIf(filter);
+ return Col1Itf.super.removeIf(filter);
}
}
@@ -180,10 +204,10 @@
public void clear() {}
}
- static class Col1<E> implements MyCol1<E> {
+ static class Col1<E> implements Col1Itf<E> {
public boolean superRemoveIf(Predicate<? super E> filter) {
- return MyCol1.super.removeIf(filter);
+ return Col1Itf.super.removeIf(filter);
}
@Override
@@ -253,10 +277,10 @@
public void clear() {}
}
- static class Col2<E> implements MyCol2<E> {
+ static class Col2<E> implements Col2Itf<E> {
public boolean superRemoveIf(Predicate<? super E> filter) {
- return MyCol2.super.removeIf(filter);
+ return Col2Itf.super.removeIf(filter);
}
@Override
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java
new file mode 100644
index 0000000..616ec2c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java
@@ -0,0 +1,85 @@
+// 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.desugaredlibrary;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.function.Predicate;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@SuppressWarnings("ALL")
+@RunWith(Parameterized.class)
+public class MinimalInterfaceSuperTest extends DesugaredLibraryTestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+ }
+
+ public MinimalInterfaceSuperTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ private static final String EXPECTED_OUTPUT = StringUtils.lines("removeIf from Col1Itf");
+
+ @Test
+ public void testCustomCollectionR8() throws Exception {
+ if (parameters.isCfRuntime()) {
+ testForJvm()
+ .addInnerClasses(MinimalInterfaceSuperTest.class)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ return;
+ }
+ testForR8(parameters.getBackend())
+ .addInnerClasses(MinimalInterfaceSuperTest.class)
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel())
+ .compile()
+ .assertNoMessages()
+ .addDesugaredCoreLibraryRunClassPath(this::buildDesugaredLibrary, parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ static class Main {
+ public static void main(String[] args) {
+ Col1<Integer> ints1 = new Col1<>();
+ ints1.removeIf(x -> x == 3);
+ }
+ }
+
+ interface Col1Itf<E> extends Collection<E> {
+ @Override
+ default boolean removeIf(Predicate<? super E> filter) {
+ System.out.println("removeIf from Col1Itf");
+ return Collection.super.removeIf(filter);
+ }
+ }
+
+ static class Col1<E> extends AbstractCollection<E> implements Col1Itf<E> {
+ @NotNull
+ @Override
+ public Iterator<E> iterator() {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java
index 3693f87..adaa55f 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java
@@ -22,7 +22,7 @@
testForR8(Backend.DEX)
.addInnerClasses(InvokeSuperInDefaultInterfaceMethodTest.class)
.addKeepMainRule(TestClass.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations()
.setMinApi(AndroidApiLevel.M)
.run(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/graph/initializedclasses/InitializedClassesInInstanceMethodsTest.java b/src/test/java/com/android/tools/r8/graph/initializedclasses/InitializedClassesInInstanceMethodsTest.java
index 0e19132..43015bf 100644
--- a/src/test/java/com/android/tools/r8/graph/initializedclasses/InitializedClassesInInstanceMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/graph/initializedclasses/InitializedClassesInInstanceMethodsTest.java
@@ -51,7 +51,7 @@
enableInitializedClassesInInstanceMethodsAnalysis;
})
.allowAccessModification()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionsMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionsMethods.java
index dd300da..eac9b74 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionsMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionsMethods.java
@@ -4,10 +4,18 @@
package com.android.tools.r8.ir.desugar.backports;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.ListIterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
public final class CollectionsMethods {
@@ -22,4 +30,30 @@
public static <T> ListIterator<T> emptyListIterator() {
return Collections.<T>emptyList().listIterator();
}
+
+ public static <T> List<T> copyOfList(Collection<? extends T> other) {
+ ArrayList<T> list = new ArrayList<>(other.size());
+ for (T item : other) {
+ list.add(Objects.requireNonNull(item));
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ public static <T> Set<T> copyOfSet(Collection<? extends T> other) {
+ HashSet<T> set = new HashSet<>(other.size());
+ for (T item : other) {
+ set.add(Objects.requireNonNull(item));
+ }
+ return Collections.unmodifiableSet(set);
+ }
+
+ public static <K, V> Map<K, V> copyOfMap(Map<? extends K, ? extends V> other) {
+ HashMap<K, V> map = new HashMap<>(other.size());
+ for (Map.Entry<? extends K, ? extends V> entry : other.entrySet()) {
+ map.put(
+ Objects.requireNonNull(entry.getKey()),
+ Objects.requireNonNull(entry.getValue()));
+ }
+ return Collections.unmodifiableMap(map);
+ }
}
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
index 2f112ab..a41259d 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
@@ -154,6 +154,33 @@
return Math.multiplyExact(x, (long) y);
}
+ public static long multiplyFull(int x, int y) {
+ return (long) x * y;
+ }
+
+ public static long multiplyHigh(long x, long y) {
+ // Adapted from Hacker's Delight (2nd ed), 8-2.
+ long xLow = x & 0xFFFFFFFFL;
+ long xHigh = x >> 32;
+ long yLow = y & 0xFFFFFFFFL;
+ long yHigh = y >> 32;
+
+ long lowLow = xLow * yLow;
+ long lowLowCarry = lowLow >>> 32;
+
+ long highLow = xHigh * yLow;
+ long mid1 = highLow + lowLowCarry;
+ long mid1Low = mid1 & 0xFFFFFFFFL;
+ long mid1High = mid1 >> 32;
+
+ long lowHigh = xLow * yHigh;
+ long mid2 = lowHigh + mid1Low;
+ long mid2High = mid2 >> 32;
+
+ long highHigh = xHigh * yHigh;
+ return highHigh + mid1High + mid2High;
+ }
+
public static int negateExactInt(int value) {
if (value == Integer.MIN_VALUE) {
throw new ArithmeticException();
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/OptionalMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/OptionalMethods.java
index 43c749a..6fb1a83 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/OptionalMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/OptionalMethods.java
@@ -14,6 +14,9 @@
import java.util.function.IntConsumer;
import java.util.function.LongConsumer;
import java.util.function.Supplier;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
import java.util.stream.Stream;
public class OptionalMethods {
@@ -73,4 +76,44 @@
return Stream.empty();
}
}
+
+ public static IntStream streamInt(OptionalInt receiver) {
+ if (receiver.isPresent()) {
+ return IntStream.of(receiver.getAsInt());
+ } else {
+ return IntStream.empty();
+ }
+ }
+
+ public static LongStream streamLong(OptionalLong receiver) {
+ if (receiver.isPresent()) {
+ return LongStream.of(receiver.getAsLong());
+ } else {
+ return LongStream.empty();
+ }
+ }
+
+ public static DoubleStream streamDouble(OptionalDouble receiver) {
+ if (receiver.isPresent()) {
+ return DoubleStream.of(receiver.getAsDouble());
+ } else {
+ return DoubleStream.empty();
+ }
+ }
+
+ public static boolean isEmpty(Optional<?> receiver) {
+ return !receiver.isPresent();
+ }
+
+ public static boolean isEmptyInt(OptionalInt receiver) {
+ return !receiver.isPresent();
+ }
+
+ public static boolean isEmptyLong(OptionalLong receiver) {
+ return !receiver.isPresent();
+ }
+
+ public static boolean isEmptyDouble(OptionalDouble receiver) {
+ return !receiver.isPresent();
+ }
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/DefaultInterfaceIssue143628636Test.java b/src/test/java/com/android/tools/r8/ir/optimize/DefaultInterfaceIssue143628636Test.java
index 945e1af..94de4ba 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/DefaultInterfaceIssue143628636Test.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/DefaultInterfaceIssue143628636Test.java
@@ -42,7 +42,7 @@
public void test() throws Exception {
testForR8(parameters.getBackend())
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations()
.addInnerClasses(DefaultInterfaceIssue143628636Test.class)
.addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
index 07106f3..e01ede5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
@@ -7,7 +7,6 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.NeverInline;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
@@ -24,6 +23,7 @@
import com.android.tools.r8.ir.optimize.nonnull.NonNullParamInterface;
import com.android.tools.r8.ir.optimize.nonnull.NonNullParamInterfaceImpl;
import com.android.tools.r8.ir.optimize.nonnull.NotPinnedClass;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -43,7 +43,7 @@
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimes().build();
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
}
public NonNullParamTest(TestParameters parameters) {
@@ -54,7 +54,7 @@
options.enableDevirtualization = false;
}
- CodeInspector buildAndRun(
+ private CodeInspector buildAndRun(
Class<?> mainClass,
Collection<Class<?>> classes,
ThrowableConsumer<R8FullTestBuilder> configuration)
@@ -65,6 +65,7 @@
.addProgramClasses(classes)
.addKeepMainRule(mainClass)
.addKeepRules(ImmutableList.of("-keepattributes InnerClasses,Signature,EnclosingMethod"))
+ .addTestingAnnotationsAsProgramClasses()
// All tests are checking if invocations to certain null-check utils are gone.
.noMinification()
.addOptionsModification(
@@ -73,7 +74,7 @@
options.inliningInstructionLimit = 4;
})
.apply(configuration)
- .setMinApi(parameters.getRuntime())
+ .setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), mainClass)
.assertSuccessWithOutput(javaOutput)
.inspector();
@@ -84,9 +85,7 @@
Class<?> mainClass = IntrinsicsDeputy.class;
CodeInspector inspector =
buildAndRun(
- mainClass,
- ImmutableList.of(NeverInline.class, mainClass),
- R8TestBuilder::enableInliningAnnotations);
+ mainClass, ImmutableList.of(mainClass), R8TestBuilder::enableInliningAnnotations);
ClassSubject mainSubject = inspector.clazz(mainClass);
assertThat(mainSubject, isPresent());
@@ -120,8 +119,7 @@
CodeInspector inspector =
buildAndRun(
mainClass,
- ImmutableList.of(
- NeverInline.class, IntrinsicsDeputy.class, NotPinnedClass.class, mainClass),
+ ImmutableList.of(IntrinsicsDeputy.class, NotPinnedClass.class, mainClass),
R8TestBuilder::enableInliningAnnotations);
ClassSubject mainSubject = inspector.clazz(mainClass);
@@ -149,8 +147,7 @@
CodeInspector inspector =
buildAndRun(
mainClass,
- ImmutableList.of(
- NeverInline.class, IntrinsicsDeputy.class, NotPinnedClass.class, mainClass),
+ ImmutableList.of(IntrinsicsDeputy.class, NotPinnedClass.class, mainClass),
R8TestBuilder::enableInliningAnnotations);
ClassSubject mainSubject = inspector.clazz(mainClass);
@@ -179,12 +176,11 @@
buildAndRun(
mainClass,
ImmutableList.of(
- NeverInline.class,
IntrinsicsDeputy.class,
NonNullParamAfterInvokeVirtual.class,
NotPinnedClass.class,
mainClass),
- R8TestBuilder::enableInliningAnnotations);
+ builder -> builder.enableNeverClassInliningAnnotations().enableInliningAnnotations());
ClassSubject mainSubject = inspector.clazz(NonNullParamAfterInvokeVirtual.class);
assertThat(mainSubject, isPresent());
@@ -192,7 +188,12 @@
MethodSubject checkViaCall = mainSubject.uniqueMethodWithName("checkViaCall");
assertThat(checkViaCall, isPresent());
assertEquals(0, countActCall(checkViaCall));
- assertEquals(2, countPrintCall(checkViaCall));
+ // With API level >= Q we get a register assignment that allows us to share the print call in a
+ // successor block. See also InternalOptions.canHaveThisJitCodeDebuggingBug().
+ boolean canSharePrintCallInSuccessorBlock =
+ parameters.isDexRuntime()
+ && parameters.getApiLevel().getLevel() >= AndroidApiLevel.Q.getLevel();
+ assertEquals(canSharePrintCallInSuccessorBlock ? 1 : 2, countPrintCall(checkViaCall));
MethodSubject checkViaIntrinsic = mainSubject.uniqueMethodWithName("checkViaIntrinsic");
assertThat(checkViaIntrinsic, isPresent());
@@ -212,7 +213,6 @@
buildAndRun(
mainClass,
ImmutableList.of(
- NeverInline.class,
IntrinsicsDeputy.class,
NonNullParamInterface.class,
NonNullParamInterfaceImpl.class,
@@ -223,7 +223,7 @@
builder
.addOptionsModification(this::disableDevirtualization)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations());
ClassSubject mainSubject = inspector.clazz(NonNullParamAfterInvokeInterface.class);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
index b804cbe..4890c6a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
@@ -45,13 +45,15 @@
.addInnerClasses(InvokeInterfaceWithRefinedReceiverTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
- o.enableDevirtualization = false;
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+ // target.
+ o.enableDevirtualization = false;
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("null", "C")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
index c69f0c1..a0a436d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
@@ -45,11 +45,12 @@
.addInnerClasses(InvokeVirtualWithRefinedReceiverTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("null", "C")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
index 3e87f06..51797eb 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
@@ -43,11 +43,12 @@
.addInnerClasses(KeptMethodTest.class)
.addKeepMainRule(MAIN)
.addKeepClassAndMembersRules(A.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("non-null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/WithStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/WithStaticizerTest.java
index 9b424d3..c1839b9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/WithStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/WithStaticizerTest.java
@@ -43,7 +43,7 @@
.addInnerClasses(WithStaticizerTest.class)
.addKeepMainRule(MAIN)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("Input")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java
index a0bafae..19a9034 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java
@@ -43,11 +43,12 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeDirectNegativeTest.class)
.addKeepMainRule(MAIN)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
index e4200b8..30aec5e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
@@ -45,11 +45,12 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeDirectPositiveTest.class)
.addKeepMainRule(MAIN)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.addOptionsModification(InternalOptions::enablePropagationOfConstantsAtCallSites)
.run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
index 7f9aedb..ba6b644 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
@@ -45,13 +45,15 @@
.addInnerClasses(InvokeInterfaceNegativeTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
- o.enableDevirtualization = false;
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+ // target.
+ o.enableDevirtualization = false;
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
index 76d8e03..a966e62 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
@@ -45,14 +45,16 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeInterfacePositiveTest.class)
.addKeepMainRule(MAIN)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(InternalOptions::enablePropagationOfConstantsAtCallSites)
- .addOptionsModification(o -> {
- // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
- o.enableDevirtualization = false;
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+ // target.
+ o.enableDevirtualization = false;
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
index b772bff..28523aa 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
@@ -45,11 +45,12 @@
.addInnerClasses(InvokeVirtualNegativeTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("null", "non-null", "null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
index 3541836..ab5d763 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
@@ -46,11 +46,12 @@
.addInnerClasses(InvokeVirtualPositiveTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.addOptionsModification(InternalOptions::enablePropagationOfConstantsAtCallSites)
.run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java
index f350e73..27db8be 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java
@@ -43,11 +43,12 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeDirectNegativeTest.class)
.addKeepMainRule(MAIN)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("Sub1", "Sub2")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
index 5f0a56c..67bb7db 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
@@ -45,11 +45,12 @@
.addInnerClasses(InvokeDirectPositiveTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("Sub1")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
index 14f9b2f..1493d73 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
@@ -45,13 +45,15 @@
.addInnerClasses(InvokeInterfaceNegativeTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
- o.enableDevirtualization = false;
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+ // target.
+ o.enableDevirtualization = false;
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("Sub1", "Sub2")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
index 9f1308d..24cad5b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
@@ -45,13 +45,15 @@
.addInnerClasses(InvokeInterfacePositiveTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
- o.enableDevirtualization = false;
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+ // target.
+ o.enableDevirtualization = false;
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("A:Sub1", "B:Sub2")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
index e62f6b4..cc0a69f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
@@ -45,11 +45,12 @@
.addInnerClasses(InvokeVirtualNegativeTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("A:Sub1", "A:Sub2", "B:Sub1", "B:Sub2")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
index 81da3d5..f49d16e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
@@ -45,11 +45,12 @@
.addInnerClasses(InvokeVirtualPositiveTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("A:Sub1", "B:Sub1")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java
index def280a..5b79156 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java
@@ -41,11 +41,12 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeDirectNegativeTest.class)
.addKeepMainRule(MAIN)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java
index e24eadd..9630bab 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java
@@ -42,11 +42,12 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeDirectPositiveTest.class)
.addKeepMainRule(MAIN)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
index 80b24a5..3fde0f1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
@@ -45,13 +45,15 @@
.addInnerClasses(InvokeInterfaceNegativeTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
- o.enableDevirtualization = false;
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+ // target.
+ o.enableDevirtualization = false;
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("null", "A")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java
index 6cbbad3..17cea42 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java
@@ -42,13 +42,15 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeInterfacePositiveTest.class)
.addKeepMainRule(MAIN)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
- o.enableDevirtualization = false;
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+ // target.
+ o.enableDevirtualization = false;
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("A")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java
index c9b215a..d2181d5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java
@@ -42,7 +42,7 @@
.addInnerClasses(InvokeVirtualCascadeTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
index cd20498..e36d2e9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
@@ -45,11 +45,12 @@
.addInnerClasses(InvokeVirtualNegativeTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("null", "A", "null", "B")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
index 6ab99d7..e05b279 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
@@ -45,11 +45,12 @@
.addInnerClasses(InvokeVirtualPositiveTest.class)
.addKeepMainRule(MAIN)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("A", "null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java
index 0ae036d..d35a11d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java
@@ -25,7 +25,7 @@
.addInnerClasses(ClassInliningOracleTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations()
.enableUnusedArgumentAnnotations()
.compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/AbstractClassAlsoImplementedByMissingClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/AbstractClassAlsoImplementedByMissingClassTest.java
index d1d5d5f..65cc34d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/AbstractClassAlsoImplementedByMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/AbstractClassAlsoImplementedByMissingClassTest.java
@@ -52,7 +52,7 @@
// of A after the R8 compilation.
.addKeepRules(
"-keep class " + A.class.getTypeName() + " { void <init>(); void kept(); }")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/InterfaceAlsoImplementedByMissingClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/InterfaceAlsoImplementedByMissingClassTest.java
index 818b1eb..89586d8 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/InterfaceAlsoImplementedByMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/InterfaceAlsoImplementedByMissingClassTest.java
@@ -50,7 +50,7 @@
// Keeping I and I.kept() should make it possible to provide an implementation of
// I after the R8 compilation.
.addKeepRules("-keep class " + I.class.getTypeName() + " { void kept(); }")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningInvokeSuperTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningInvokeSuperTest.java
index b5109d6..9bc40d7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningInvokeSuperTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningInvokeSuperTest.java
@@ -37,7 +37,7 @@
.addInnerClasses(DoubleInliningInvokeSuperTest.class)
.addKeepMainRule(TestClass.class)
.addKeepRules("-keepclassmembers class * { void fooCaller(...); }")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.enableMergeAnnotations()
.setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineFunctionalInterfaceMethodImplementedByLambdasTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineFunctionalInterfaceMethodImplementedByLambdasTest.java
index 4a9025a..8a999ff 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineFunctionalInterfaceMethodImplementedByLambdasTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineFunctionalInterfaceMethodImplementedByLambdasTest.java
@@ -36,7 +36,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InlineFunctionalInterfaceMethodImplementedByLambdasTest.class)
.addKeepMainRule(TestClass.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineNonReboundFieldTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineNonReboundFieldTest.java
index beb56a7..d0d52ec 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineNonReboundFieldTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineNonReboundFieldTest.java
@@ -27,7 +27,7 @@
.addProgramClasses(
TestClass.class, Greeter.class, Greeting.class, Greeting.getGreetingBase())
.addKeepMainRule(TestClass.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations()
.run(TestClass.class)
.assertSuccessWithOutput(expectedOutput)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynchronizedTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynchronizedTest.java
index b3a7ce8..1cb4d4f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynchronizedTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynchronizedTest.java
@@ -39,7 +39,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InlineSynchronizedTest.class)
.addKeepMainRule(TestClass.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOfVirtualMethodOnKeptClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOfVirtualMethodOnKeptClassTest.java
index 2349809..cc347c5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOfVirtualMethodOnKeptClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOfVirtualMethodOnKeptClassTest.java
@@ -40,7 +40,7 @@
.addKeepRules(
"-keep class " + A.class.getTypeName() + " { void bar(); }",
"-keep class " + I.class.getTypeName() + " { void baz(); }")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
.inspect(this::verifyOutput)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/LibraryOverrideInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/LibraryOverrideInliningTest.java
index 1a70cde..0b58101 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/LibraryOverrideInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/LibraryOverrideInliningTest.java
@@ -47,7 +47,7 @@
options ->
options.disableInliningOfLibraryMethodOverrides =
disableInliningOfLibraryMethodOverrides)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
.inspect(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetAfterInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetAfterInliningTest.java
index 5f1b7a5..9ccdb7f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetAfterInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetAfterInliningTest.java
@@ -50,7 +50,7 @@
options.applyInliningToInlineeMaxDepth = maxInliningDepth;
})
.enableAlwaysInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableSideEffectAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetFromExactReceiverTypeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetFromExactReceiverTypeTest.java
index 24f4402..7c9b7b7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetFromExactReceiverTypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetFromExactReceiverTypeTest.java
@@ -48,7 +48,7 @@
"-keepclassmembers class " + A.class.getTypeName() + " {",
" void cannotBeInlinedDueToKeepRule();",
"}")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
index df9ab8d..0e4627b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
@@ -41,7 +41,7 @@
.addInnerClasses(InlineDefaultInterfaceMethodTest.class)
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations()
.noMinification()
.run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/InstanceFieldValuePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/InstanceFieldValuePropagationTest.java
index b0bf180..5b4c540 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/InstanceFieldValuePropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/InstanceFieldValuePropagationTest.java
@@ -42,12 +42,13 @@
testForR8(parameters.getBackend())
.addInnerClasses(InstanceFieldValuePropagationTest.class)
.addKeepMainRule(TestClass.class)
- .addOptionsModification(options -> {
- // TODO(b/125282093): Remove options modification once landed.
- assert !options.enableValuePropagationForInstanceFields;
- options.enableValuePropagationForInstanceFields = true;
- })
- .enableClassInliningAnnotations()
+ .addOptionsModification(
+ options -> {
+ // TODO(b/125282093): Remove options modification once landed.
+ assert !options.enableValuePropagationForInstanceFields;
+ options.enableValuePropagationForInstanceFields = true;
+ })
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/NoConstructorPropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/NoConstructorPropagationTest.java
index 904342a..63939b1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/NoConstructorPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/NoConstructorPropagationTest.java
@@ -37,7 +37,7 @@
"-assumenosideeffects class " + Greeter.class.getTypeName() + " {",
" <init>(...);",
"}")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getRuntime())
.run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtual.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtual.java
index 994c87a..d577644 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtual.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtual.java
@@ -5,8 +5,10 @@
import static com.android.tools.r8.ir.optimize.nonnull.IntrinsicsDeputy.checkParameterIsNotNull;
+import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
+@NeverClassInline
public class NonNullParamAfterInvokeVirtual {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java
index bea51f6..59602da 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java
@@ -45,7 +45,7 @@
@Test
public void testNonNullOnOneSide() throws Exception {
testForR8(parameters.getBackend())
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addProgramClasses(TestArg.class, TestClassWithNonNullOnOneSide.class)
.addKeepMainRule(TestClassWithNonNullOnOneSide.class)
@@ -70,7 +70,7 @@
@Test
public void testNonNullOnBothSides() throws Exception {
testForR8(parameters.getBackend())
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addProgramClasses(TestArg.class, TestClassWithNonNullOnBothSides.class)
.addKeepMainRule(TestClassWithNonNullOnBothSides.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java
index b380f62..5691577 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java
@@ -62,7 +62,7 @@
String expectedOutput = StringUtils.lines("Hello, world 5");
testForR8(parameters.getBackend())
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations()
.enableSideEffectAnnotations()
.addInnerClasses(B133215941.class)
@@ -70,13 +70,14 @@
.addKeepClassAndMembersRules(ClassWithStaticMethod.class)
.setMinApi(parameters.getRuntime())
.noMinification()
- .addOptionsModification(options -> {
- if (parameters.isCfRuntime()) {
- assert !options.outline.enabled;
- options.outline.enabled = true;
- }
- options.outline.threshold = 2;
- })
+ .addOptionsModification(
+ options -> {
+ if (parameters.isCfRuntime()) {
+ assert !options.outline.enabled;
+ options.outline.enabled = true;
+ }
+ options.outline.threshold = 2;
+ })
.compile()
.inspect(this::validateOutlining)
.run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java
index f6e72b2..db3ef77 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java
@@ -54,7 +54,7 @@
throws Exception {
testForR8(parameters.getBackend())
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.addProgramClasses(testClass)
.addProgramClasses(MyStringBuilder.class)
.addKeepMainRule(testClass)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantInstanceFieldLoadAfterStoreTest.java b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantInstanceFieldLoadAfterStoreTest.java
index 09f1326..7c39564 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantInstanceFieldLoadAfterStoreTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantInstanceFieldLoadAfterStoreTest.java
@@ -39,7 +39,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(RedundantInstanceFieldLoadAfterStoreTest.class)
.addKeepMainRule(TestClass.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
.inspect(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/CompanionAsArgumentTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/CompanionAsArgumentTest.java
index 92cc700..be47557 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/CompanionAsArgumentTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/CompanionAsArgumentTest.java
@@ -42,7 +42,7 @@
.addInnerClasses(CompanionAsArgumentTest.class)
.addKeepMainRule(MAIN)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("Companion#foo(true)")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InstanceInsideCompanionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InstanceInsideCompanionTest.java
index fe55066..f28235b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InstanceInsideCompanionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InstanceInsideCompanionTest.java
@@ -43,7 +43,7 @@
.addInnerClasses(InstanceInsideCompanionTest.class)
.addKeepMainRule(MAIN)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("Candidate#foo(false)")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
index 2635741..e552581 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
@@ -44,7 +44,7 @@
.addInnerClasses(InvokeStaticWithNullOutvalueTest.class)
.addKeepMainRule(MAIN)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("Companion#boo", "Companion#foo")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
index c790d0a..41a1935 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
@@ -61,7 +61,7 @@
.addInnerClasses(PrivateInstanceMethodCollisionTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.minification(minification)
.allowAccessModification(allowAccessModification)
.setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java
index c92103e..035ab54 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java
@@ -57,7 +57,7 @@
.addKeepMainRule(TestClass.class)
.addKeepClassRules(Instantiated.class, Uninstantiated.class)
.addKeepAttributes("RuntimeVisibleParameterAnnotations")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableConstantArgumentAnnotations(keepUninstantiatedArguments)
.enableInliningAnnotations()
.enableUnusedArgumentAnnotations()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
index 5c89be9..45d858d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
@@ -46,7 +46,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(CollisionWithLibraryMethodsTest.class)
.addKeepMainRule(TestClass.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.minification(minification)
.setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java
index 25797a1..073c3b4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java
@@ -61,7 +61,7 @@
.addInnerClasses(PrivateInstanceMethodCollisionTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.minification(minification)
.allowAccessModification(allowAccessModification)
.setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsTest.java
index 86e4d24..09c0de7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsTest.java
@@ -55,7 +55,7 @@
.addKeepMainRule(TestClass.class)
.addKeepClassRules(Used.class, Unused.class)
.addKeepAttributes("RuntimeVisibleParameterAnnotations")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.enableUnusedArgumentAnnotations(keepUnusedArguments)
// TODO(b/123060011): Mapping not working in presence of unused argument removal.
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
index a3f1b9b..461ec6b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
@@ -46,7 +46,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(UnusedArgumentRemovalWithOverridingTest.class)
.addKeepMainRule(TestClass.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.enableMergeAnnotations()
.minification(minification)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
index 003a06f..08d8c09 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
@@ -57,7 +57,7 @@
.addInnerClasses(UnusedArgumentsCollisionTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations()
.minification(minification)
.setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
index 5e303bc..ea67170 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
@@ -49,7 +49,7 @@
.addInnerClasses(UnusedArgumentsInstanceConstructorTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.run(TestClass.class)
.assertSuccessWithOutput(expectedOutput)
.inspector();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java
index 17287a4..794d588 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java
@@ -110,7 +110,7 @@
@Override
public void configure(R8FullTestBuilder builder) {
- builder.enableClassInliningAnnotations().enableInliningAnnotations();
+ builder.enableNeverClassInliningAnnotations().enableInliningAnnotations();
}
@Override
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInMultifileClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInMultifileClassTest.java
new file mode 100644
index 0000000..9280756
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInMultifileClassTest.java
@@ -0,0 +1,176 @@
+// 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.kotlin.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertNotEquals;
+
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.nio.file.Path;
+import java.util.Collection;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRenameInMultifileClassTest extends KotlinMetadataTestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0} target: {1}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ }
+
+ public MetadataRenameInMultifileClassTest(
+ TestParameters parameters, KotlinTargetVersion targetVersion) {
+ super(targetVersion);
+ this.parameters = parameters;
+ }
+
+ private static Path multifileLibJar;
+
+ @BeforeClass
+ public static void createLibJar() throws Exception {
+ String multifileLibFolder = PKG_PREFIX + "/multifileclass_lib";
+ multifileLibJar =
+ kotlinc(KOTLINC, KotlinTargetVersion.JAVA_8)
+ .addSourceFiles(
+ getKotlinFileInTest(multifileLibFolder, "signed"),
+ getKotlinFileInTest(multifileLibFolder, "unsigned"))
+ .compile();
+ }
+
+ @Test
+ public void testMetadataInMultifileClass_merged() throws Exception {
+ R8TestCompileResult compileResult =
+ testForR8(parameters.getBackend())
+ .addProgramFiles(multifileLibJar)
+ // Keep UtilKt#comma*Join*(). Let R8 optimize (inline) others, such as joinOf*(String).
+ .addKeepRules("-keep class **.UtilKt")
+ .addKeepRules("-keepclassmembers class * { ** comma*Join*(...); }")
+ .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+ .compile();
+ String pkg = getClass().getPackage().getName();
+ final String utilClassName = pkg + ".multifileclass_lib.UtilKt";
+ final String signedClassName = pkg + ".multifileclass_lib.UtilKt__SignedKt";
+ compileResult.inspect(inspector -> {
+ ClassSubject util = inspector.clazz(utilClassName);
+ assertThat(util, isPresent());
+ assertThat(util, not(isRenamed()));
+ MethodSubject commaJoinOfInt = util.uniqueMethodWithName("commaSeparatedJoinOfInt");
+ assertThat(commaJoinOfInt, isPresent());
+ assertThat(commaJoinOfInt, not(isRenamed()));
+ MethodSubject joinOfInt = util.uniqueMethodWithName("joinOfInt");
+ assertThat(joinOfInt, not(isPresent()));
+ // API entry is kept, hence the presence of Metadata.
+ AnnotationSubject annotationSubject = util.annotation(METADATA_TYPE);
+ assertThat(annotationSubject, isPresent());
+ // TODO(b/70169921): need further inspection.
+
+ ClassSubject signed = inspector.clazz(signedClassName);
+ assertThat(signed, isPresent());
+ assertThat(signed, isRenamed());
+ commaJoinOfInt = signed.uniqueMethodWithName("commaSeparatedJoinOfInt");
+ assertThat(commaJoinOfInt, isPresent());
+ assertThat(commaJoinOfInt, not(isRenamed()));
+ joinOfInt = signed.uniqueMethodWithName("joinOfInt");
+ assertThat(joinOfInt, isPresent());
+ assertThat(joinOfInt, isRenamed());
+ // API entry is kept, hence the presence of Metadata.
+ annotationSubject = util.annotation(METADATA_TYPE);
+ assertThat(annotationSubject, isPresent());
+ // TODO(b/70169921): need further inspection.
+ });
+
+ Path libJar = compileResult.writeToZip();
+
+ String appFolder = PKG_PREFIX + "/multifileclass_app";
+ ProcessResult kotlinTestCompileResult =
+ kotlinc(parameters.getRuntime().asCf(), KOTLINC, KotlinTargetVersion.JAVA_8)
+ .addClasspathFiles(libJar)
+ .addSourceFiles(getKotlinFileInTest(appFolder, "main"))
+ .setOutputPath(temp.newFolder().toPath())
+ // TODO(b/143687784): update to just .compile() once fixed.
+ .compileRaw();
+ // TODO(b/70169921): should be able to compile!
+ assertNotEquals(0, kotlinTestCompileResult.exitCode);
+ assertThat(kotlinTestCompileResult.stderr, containsString("unresolved reference: join"));
+ }
+
+ @Test
+ public void testMetadataInMultifileClass_renamed() throws Exception {
+ R8TestCompileResult compileResult =
+ testForR8(parameters.getBackend())
+ .addProgramFiles(multifileLibJar)
+ // Keep UtilKt#comma*Join*().
+ .addKeepRules("-keep class **.UtilKt")
+ .addKeepRules("-keepclassmembers class * { ** comma*Join*(...); }")
+ // Keep yet rename joinOf*(String).
+ .addKeepRules(
+ "-keepclassmembers,allowobfuscation class * { ** joinOf*(...); }")
+ .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+ .compile();
+ String pkg = getClass().getPackage().getName();
+ final String utilClassName = pkg + ".multifileclass_lib.UtilKt";
+ final String signedClassName = pkg + ".multifileclass_lib.UtilKt__SignedKt";
+ compileResult.inspect(inspector -> {
+ ClassSubject util = inspector.clazz(utilClassName);
+ assertThat(util, isPresent());
+ assertThat(util, not(isRenamed()));
+ MethodSubject commaJoinOfInt = util.uniqueMethodWithName("commaSeparatedJoinOfInt");
+ assertThat(commaJoinOfInt, isPresent());
+ assertThat(commaJoinOfInt, not(isRenamed()));
+ MethodSubject joinOfInt = util.uniqueMethodWithName("joinOfInt");
+ assertThat(joinOfInt, isPresent());
+ assertThat(joinOfInt, isRenamed());
+ // API entry is kept, hence the presence of Metadata.
+ AnnotationSubject annotationSubject = util.annotation(METADATA_TYPE);
+ assertThat(annotationSubject, isPresent());
+ // TODO(b/70169921): need further inspection.
+
+ ClassSubject signed = inspector.clazz(signedClassName);
+ assertThat(signed, isPresent());
+ assertThat(signed, isRenamed());
+ commaJoinOfInt = signed.uniqueMethodWithName("commaSeparatedJoinOfInt");
+ assertThat(commaJoinOfInt, isPresent());
+ assertThat(commaJoinOfInt, not(isRenamed()));
+ joinOfInt = signed.uniqueMethodWithName("joinOfInt");
+ assertThat(joinOfInt, isPresent());
+ assertThat(joinOfInt, isRenamed());
+ // API entry is kept, hence the presence of Metadata.
+ annotationSubject = util.annotation(METADATA_TYPE);
+ assertThat(annotationSubject, isPresent());
+ // TODO(b/70169921): need further inspection.
+ });
+
+ Path libJar = compileResult.writeToZip();
+
+ String appFolder = PKG_PREFIX + "/multifileclass_app";
+ ProcessResult kotlinTestCompileResult =
+ kotlinc(parameters.getRuntime().asCf(), KOTLINC, KotlinTargetVersion.JAVA_8)
+ .addClasspathFiles(libJar)
+ .addSourceFiles(getKotlinFileInTest(appFolder, "main"))
+ .setOutputPath(temp.newFolder().toPath())
+ // TODO(b/143687784): update to just .compile() once fixed.
+ .compileRaw();
+ // TODO(b/70169921): should be able to compile!
+ assertNotEquals(0, kotlinTestCompileResult.exitCode);
+ assertThat(kotlinTestCompileResult.stderr, containsString("unresolved reference: join"));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_app/main.kt
new file mode 100644
index 0000000..ce098bf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_app/main.kt
@@ -0,0 +1,11 @@
+// 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.kotlin.metadata.multifileclass_app
+
+import com.android.tools.r8.kotlin.metadata.multifileclass_lib.join
+
+fun main() {
+ val s = sequenceOf(1, 2, 3)
+ println(s.join())
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_lib/signed.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_lib/signed.kt
new file mode 100644
index 0000000..81c4994
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_lib/signed.kt
@@ -0,0 +1,16 @@
+// 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.
+@file:kotlin.jvm.JvmMultifileClass
+@file:kotlin.jvm.JvmName("UtilKt")
+package com.android.tools.r8.kotlin.metadata.multifileclass_lib
+
+@kotlin.jvm.JvmName("joinOfInt")
+public fun Sequence<Int>.join(separator: String): String {
+ return fold("") { acc, i -> "$acc$separator$i" }
+}
+
+@kotlin.jvm.JvmName("commaSeparatedJoinOfInt")
+public fun Sequence<Int>.join(): String {
+ return join(", ")
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_lib/unsigned.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_lib/unsigned.kt
new file mode 100644
index 0000000..25dac69
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_lib/unsigned.kt
@@ -0,0 +1,20 @@
+// 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.
+@file:kotlin.jvm.JvmMultifileClass
+@file:kotlin.jvm.JvmName("UtilKt")
+package com.android.tools.r8.kotlin.metadata.multifileclass_lib
+
+@SinceKotlin("1.3")
+@ExperimentalUnsignedTypes
+@kotlin.jvm.JvmName("joinOfUInt")
+public fun Sequence<UInt>.join(separator: String): String {
+ return fold("") { acc, i -> "$acc$separator$i" }
+}
+
+@SinceKotlin("1.3")
+@ExperimentalUnsignedTypes
+@kotlin.jvm.JvmName("commaSeparatedJoinOfUInt")
+public fun Sequence<UInt>.join(): String {
+ return join(", ")
+}
diff --git a/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java b/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java
index 7b89f71..69b4b03 100644
--- a/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java
@@ -29,7 +29,7 @@
.addKeepMainRule(TestClass.class)
.addKeepRules(
"-keep class " + B.class.getTypeName() + " { public java.lang.String f2; }")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.enableMergeAnnotations()
.run(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/naming/FieldNamingObfuscationDictionaryTest.java b/src/test/java/com/android/tools/r8/naming/FieldNamingObfuscationDictionaryTest.java
index 59b273a..be7230d 100644
--- a/src/test/java/com/android/tools/r8/naming/FieldNamingObfuscationDictionaryTest.java
+++ b/src/test/java/com/android/tools/r8/naming/FieldNamingObfuscationDictionaryTest.java
@@ -97,7 +97,7 @@
.addInnerClasses(FieldNamingObfuscationDictionaryTest.class)
.addKeepRules("-overloadaggressively", "-obfuscationdictionary " + dictionary.toString())
.addKeepMainRule(Runner.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.run(parameters.getRuntime(), Runner.class, "HELLO", "WORLD")
diff --git a/src/test/java/com/android/tools/r8/naming/InterfaceFieldMinificationTest.java b/src/test/java/com/android/tools/r8/naming/InterfaceFieldMinificationTest.java
index 2041fac..4d43352 100644
--- a/src/test/java/com/android/tools/r8/naming/InterfaceFieldMinificationTest.java
+++ b/src/test/java/com/android/tools/r8/naming/InterfaceFieldMinificationTest.java
@@ -23,7 +23,7 @@
TestClass.class, Greeter.class, Greeting.class, Greeting.getGreetingBase(), Tag.class)
.addKeepMainRule(TestClass.class)
.addKeepRules("-keep,allowobfuscation class " + Tag.class.getTypeName() + " { <fields>; }")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.enableMergeAnnotations()
.run(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java
index 8503e9b..dc74758 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java
@@ -7,10 +7,10 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.NeverInline;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import org.junit.Assume;
@@ -56,7 +56,6 @@
// Test runner code follows.
private static final Class<?>[] LIBRARY_CLASSES = {
- NeverInline.class,
LibraryA.class,
LibraryB.class,
LibraryMain.class
@@ -66,33 +65,37 @@
ProgramClass.class
};
- private Backend backend;
+ private TestParameters parameters;
@Parameterized.Parameters(name = "{0}")
- public static Backend[] data() {
- return ToolHelper.getBackends();
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
}
- public ApplyMappingAfterHorizontalMergingFieldTest(Backend backend) {
- this.backend = backend;
+ public ApplyMappingAfterHorizontalMergingFieldTest(TestParameters parameters) {
+ this.parameters = parameters;
}
@Test
public void runOnJvm() throws Throwable {
- Assume.assumeTrue(backend == Backend.CF);
+ Assume.assumeTrue(parameters.isCfRuntime());
testForJvm()
.addProgramClasses(LIBRARY_CLASSES)
.addProgramClasses(PROGRAM_CLASSES)
- .run(ProgramClass.class)
+ .addTestingAnnotationsAsProgramClasses()
+ .run(parameters.getRuntime(), ProgramClass.class)
.assertSuccessWithOutput(EXPECTED_SUCCESS);
}
@Test
public void b121042934() throws Exception {
- R8TestCompileResult libraryResult = testForR8(backend)
- .addProgramClasses(LIBRARY_CLASSES)
- .addKeepMainRule(LibraryMain.class)
- .compile();
+ R8TestCompileResult libraryResult =
+ testForR8(parameters.getBackend())
+ .addProgramClasses(LIBRARY_CLASSES)
+ .addTestingAnnotationsAsProgramClasses()
+ .addKeepMainRule(LibraryMain.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile();
CodeInspector inspector = libraryResult.inspector();
assertThat(inspector.clazz(LibraryMain.class), isPresent());
@@ -100,16 +103,18 @@
assertTrue(inspector.clazz(LibraryA.class).isPresent()
!= inspector.clazz(LibraryB.class).isPresent());
- testForR8(backend)
+ testForR8(parameters.getBackend())
.noTreeShaking()
.noMinification()
.addProgramClasses(PROGRAM_CLASSES)
.addApplyMapping(libraryResult.getProguardMap())
.addLibraryClasses(LIBRARY_CLASSES)
- .addLibraryFiles(runtimeJar(backend))
+ .addTestingAnnotationsAsLibraryClasses()
+ .addLibraryFiles(runtimeJar(parameters.getBackend()))
+ .setMinApi(parameters.getApiLevel())
.compile()
.addRunClasspathFiles(libraryResult.writeToZip())
- .run(ProgramClass.class)
+ .run(parameters.getRuntime(), ProgramClass.class)
.assertSuccessWithOutput(EXPECTED_SUCCESS);
}
}
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingKeepPrecedenceTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingKeepPrecedenceTest.java
index 854a730..da47d4c 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingKeepPrecedenceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingKeepPrecedenceTest.java
@@ -74,7 +74,7 @@
public void testNaming() throws IOException, CompilationFailedException, ExecutionException {
testForR8(parameters.getBackend())
.addInnerClasses(ApplyMappingKeepPrecedenceTest.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addApplyMapping(
A.class.getTypeName()
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingMinificationTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingMinificationTest.java
index 572e070..d6382aa 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingMinificationTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingMinificationTest.java
@@ -96,7 +96,7 @@
.addKeepRules(
"-keepclassmembers class " + A.class.getTypeName() + " { void methodC(); }")
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.addApplyMapping(StringUtils.lines(pgMap))
.setMinApi(parameters.getRuntime())
.run(parameters.getRuntime(), C.class)
diff --git a/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java b/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java
index 234d00c..f063f9e 100644
--- a/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java
+++ b/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java
@@ -25,9 +25,8 @@
public void testField() throws Exception {
Class<?> main = TestClassMainForField.class;
testForR8(Backend.DEX)
- .addProgramClasses(
- Greeting.class, Greeting.getGreetingBase(), TestClassSub.class, main)
- .enableClassInliningAnnotations()
+ .addProgramClasses(Greeting.class, Greeting.getGreetingBase(), TestClassSub.class, main)
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations()
.addKeepMainRule(main)
.addKeepRules(
@@ -36,14 +35,15 @@
+ "{ static java.lang.String a; }")
.run(main)
.assertSuccessWithOutput(StringUtils.lines("TestClassSub.greeting", "TestClassSub.a"))
- .inspect(inspector -> {
- ClassSubject greetingBase = inspector.clazz(Greeting.getGreetingBase());
- assertThat(greetingBase, isPresent());
- FieldSubject greeting = greetingBase.uniqueFieldWithName("greeting");
- assertThat(greeting, isPresent());
- assertThat(greeting, isRenamed());
- assertNotEquals("a", greeting.getFinalName());
- });
+ .inspect(
+ inspector -> {
+ ClassSubject greetingBase = inspector.clazz(Greeting.getGreetingBase());
+ assertThat(greetingBase, isPresent());
+ FieldSubject greeting = greetingBase.uniqueFieldWithName("greeting");
+ assertThat(greeting, isPresent());
+ assertThat(greeting, isRenamed());
+ assertNotEquals("a", greeting.getFinalName());
+ });
}
@NeverClassInline
@@ -74,26 +74,24 @@
public void testMethod() throws Exception {
Class<?> main = TestClassMainForMethod.class;
testForR8(Backend.DEX)
- .addProgramClasses(
- TestClassBase.class, TestClassSub2.class, main)
+ .addProgramClasses(TestClassBase.class, TestClassSub2.class, main)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addKeepMainRule(main)
.addKeepRules(
- "-keepclassmembernames class "
- + TestClassSub2.class.getTypeName()
- + "{ void a(...); }")
+ "-keepclassmembernames class " + TestClassSub2.class.getTypeName() + "{ void a(...); }")
.run(main)
.assertSuccessWithOutput(StringUtils.lines("TestClassSub2::a", "TestClassBase::foo"))
- .inspect(inspector -> {
- ClassSubject base = inspector.clazz(TestClassBase.class);
- assertThat(base, isPresent());
- MethodSubject foo = base.uniqueMethodWithName("foo");
- assertThat(foo, isPresent());
- assertThat(foo, isRenamed());
- assertNotEquals("a", foo.getFinalName());
- });
+ .inspect(
+ inspector -> {
+ ClassSubject base = inspector.clazz(TestClassBase.class);
+ assertThat(base, isPresent());
+ MethodSubject foo = base.uniqueMethodWithName("foo");
+ assertThat(foo, isPresent());
+ assertThat(foo, isRenamed());
+ assertNotEquals("a", foo.getFinalName());
+ });
}
@NeverMerge
diff --git a/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java b/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java
index 40cd981..b12b05f 100644
--- a/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java
+++ b/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java
@@ -9,6 +9,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeFalse;
+import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.ProguardTestBuilder;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
@@ -63,6 +64,7 @@
byte foo();
}
+@NeverClassInline
class SomeClass implements SomeInterface {
@Override
public byte foo() {
@@ -133,7 +135,8 @@
.addProgramClasses(CLASSES)
.addLibraryFiles(ToolHelper.getDefaultAndroidJar())
.addKeepClassAndMembersRules(MAIN)
- .addKeepRules(RULES);
+ .addKeepRules(RULES)
+ .addTestingAnnotationsAsProgramClasses();
if (!enableClassMerging) {
builder.addKeepRules("-optimizations !class/merging/*");
}
@@ -149,7 +152,8 @@
.addProgramClasses(CLASSES)
.addLibraryFiles(ToolHelper.getDefaultAndroidJar())
.addKeepClassAndMembersRules(MAIN)
- .addKeepRules(RULES);
+ .addKeepRules(RULES)
+ .enableNeverClassInliningAnnotations();
if (!enableClassMerging) {
builder.addOptionsModification(o -> o.enableVerticalClassMerging = false);
}
diff --git a/src/test/java/com/android/tools/r8/peephole/suffixsharing/IdenticalBlockSuffixSharingWithArrayTypesTest.java b/src/test/java/com/android/tools/r8/peephole/suffixsharing/IdenticalBlockSuffixSharingWithArrayTypesTest.java
index 3f89628..1781d9f 100644
--- a/src/test/java/com/android/tools/r8/peephole/suffixsharing/IdenticalBlockSuffixSharingWithArrayTypesTest.java
+++ b/src/test/java/com/android/tools/r8/peephole/suffixsharing/IdenticalBlockSuffixSharingWithArrayTypesTest.java
@@ -83,7 +83,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(IdenticalBlockSuffixSharingWithArrayTypesTest.class)
.addKeepMainRule(clazz)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
new file mode 100644
index 0000000..a9dc70f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
@@ -0,0 +1,234 @@
+// 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.resolution.access;
+
+import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ResolutionResult;
+import com.android.tools.r8.graph.ResolutionResult.NoSuchMethodResult;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.Opcodes;
+
+/** Tests the behavior of invoke-special on interfaces with a direct private definition. */
+@RunWith(Parameterized.class)
+public class NestInvokeSpecialInterfaceMethodAccessTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("I::bar");
+
+ private final TestParameters parameters;
+
+ // If true, all classes are in the same nest, otherwise each is in its own.
+ private final boolean inSameNest;
+
+ // If true, the invoke will reference the actual type defining the method.
+ private final boolean symbolicReferenceIsDefiningType;
+
+ @Parameterized.Parameters(name = "{0}, in-same-nest:{1}, sym-ref-is-def-type:{2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters()
+ .withCfRuntimesStartingFromIncluding(JDK11)
+ .withDexRuntimes()
+ .withAllApiLevels()
+ .build(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
+ }
+
+ public NestInvokeSpecialInterfaceMethodAccessTest(
+ TestParameters parameters, boolean inSameNest, boolean symbolicReferenceIsDefiningType) {
+ this.parameters = parameters;
+ this.inSameNest = inSameNest;
+ this.symbolicReferenceIsDefiningType = symbolicReferenceIsDefiningType;
+ }
+
+ public Collection<Class<?>> getClasses() {
+ return ImmutableList.of(Main.class);
+ }
+
+ public Collection<byte[]> getTransformedClasses() throws Exception {
+ return ImmutableList.of(
+ withNest(I.class).setPrivate(I.class.getDeclaredMethod("bar")).transform(),
+ withNest(A.class)
+ .transformMethodInsnInMethod(
+ "foo",
+ (opcode, owner, name, descriptor, isInterface, continuation) -> {
+ assertEquals(Opcodes.INVOKEVIRTUAL, opcode);
+ assertEquals(DescriptorUtils.getBinaryNameFromJavaType(A.class.getName()), owner);
+ String newOwner =
+ symbolicReferenceIsDefiningType
+ ? DescriptorUtils.getBinaryNameFromJavaType(I.class.getName())
+ : DescriptorUtils.getBinaryNameFromJavaType(A.class.getName());
+ boolean newIsInterface = symbolicReferenceIsDefiningType;
+ continuation.apply(
+ Opcodes.INVOKESPECIAL, newOwner, name, descriptor, newIsInterface);
+ })
+ .transform());
+ }
+
+ private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
+ if (inSameNest) {
+ // If in the same nest make A host and B a member.
+ return transformer(clazz).setNest(I.class, A.class);
+ }
+ // Otherwise, set the class to be its own host and no additional members.
+ return transformer(clazz).setNest(clazz);
+ }
+
+ @Test
+ public void testResolutionAccess() throws Exception {
+ // White-box test of the R8 resolution and lookup methods.
+ Class<?> definingClass = I.class;
+ Class<?> declaredClass = symbolicReferenceIsDefiningType ? definingClass : A.class;
+ Class<?> callerClass = A.class;
+
+ AppView<AppInfoWithLiveness> appView = getAppView();
+ AppInfoWithLiveness appInfo = appView.appInfo();
+
+ DexProgramClass definingClassDefinition = getDexProgramClass(definingClass, appInfo);
+ DexProgramClass declaredClassDefinition = getDexProgramClass(declaredClass, appInfo);
+ DexProgramClass callerClassDefinition = getDexProgramClass(callerClass, appInfo);
+
+ DexMethod method = getTargetMethodSignature(declaredClass, appInfo);
+ assertCallingClassCallsTarget(callerClass, appInfo, method);
+
+ // Resolve the method from the point of the declared holder.
+ assertEquals(method.holder, declaredClassDefinition.type);
+ ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method);
+
+ if (!symbolicReferenceIsDefiningType) {
+ // The targeted method is a private interface method and thus not a maximally specific method.
+ assertTrue(resolutionResult instanceof NoSuchMethodResult);
+ return;
+ }
+
+ assertEquals(inSameNest, resolutionResult.isAccessibleFrom(callerClassDefinition, appInfo));
+ DexEncodedMethod targetSpecial =
+ resolutionResult.lookupInvokeSpecialTarget(callerClassDefinition, appInfo);
+ DexEncodedMethod targetSuper =
+ resolutionResult.lookupInvokeSuperTarget(callerClassDefinition, appInfo);
+ if (inSameNest) {
+ assertEquals(definingClassDefinition.type, targetSpecial.method.holder);
+ assertEquals(targetSpecial, targetSuper);
+ } else {
+ assertNull(targetSpecial);
+ assertNull(targetSuper);
+ }
+ }
+
+ private void assertCallingClassCallsTarget(
+ Class<?> callerClass, AppInfoWithLiveness appInfo, DexMethod target) {
+ CodeInspector inspector = new CodeInspector(appInfo.app());
+ MethodSubject foo = inspector.clazz(callerClass).uniqueMethodWithName("foo");
+ assertTrue(
+ foo.streamInstructions().anyMatch(i -> i.isInvokeSpecial() && i.getMethod() == target));
+ }
+
+ private DexMethod getTargetMethodSignature(Class<?> declaredClass, AppInfoWithLiveness appInfo) {
+ return buildMethod(
+ Reference.method(Reference.classFromClass(declaredClass), "bar", ImmutableList.of(), null),
+ appInfo.dexItemFactory());
+ }
+
+ private DexProgramClass getDexProgramClass(Class<?> clazz, AppInfoWithLiveness appInfo) {
+ return appInfo.definitionFor(buildType(clazz, appInfo.dexItemFactory())).asProgramClass();
+ }
+
+ private AppView<AppInfoWithLiveness> getAppView() throws Exception {
+ return computeAppViewWithLiveness(
+ buildClasses(getClasses())
+ .addClassProgramData(getTransformedClasses())
+ .addLibraryFile(TestBase.runtimeJar(parameters.getBackend()))
+ .build(),
+ Main.class);
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(getClasses())
+ .addProgramClassFileData(getTransformedClasses())
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkExpectedResult);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(getClasses())
+ .addProgramClassFileData(getTransformedClasses())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkExpectedResult);
+ }
+
+ private void checkExpectedResult(TestRunResult<?> result) {
+ if (!symbolicReferenceIsDefiningType) {
+ result.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+ return;
+ }
+
+ if (!inSameNest) {
+ // TODO(b/145775365): Desugaring causes change to reported error.
+ // The default method desugar will target $default$bar, but the definition is $private$bar.
+ result.assertFailureWithErrorThatThrows(
+ isDesugaring() ? NoSuchMethodError.class : IllegalAccessError.class);
+ return;
+ }
+
+ result.assertSuccessWithOutput(EXPECTED);
+ }
+
+ private boolean isDesugaring() {
+ return parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(AndroidApiLevel.N);
+ }
+
+ interface I {
+ /* will be private */ default void bar() {
+ System.out.println("I::bar");
+ }
+ }
+
+ static class A implements I {
+ public void foo() {
+ // Rewritten to invoke-special A.bar or I.bar which resolves to private method A.bar
+ // When targeting B.bar => throws NoSuchMethodError.
+ // When targeting A.bar:
+ // - in same nest => success.
+ // - not in nest => throws IllegalAccessError.
+ bar();
+ }
+ }
+
+ static class Main {
+ public static void main(String[] args) {
+ new A().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java
new file mode 100644
index 0000000..bae2756
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java
@@ -0,0 +1,220 @@
+// 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.resolution.access;
+
+import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ResolutionResult;
+import com.android.tools.r8.graph.ResolutionResult.NoSuchMethodResult;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.Opcodes;
+
+/** Tests the behavior of invoke-special on interfaces with an indirect private definition. */
+@RunWith(Parameterized.class)
+public class NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ // If true, all classes are in the same nest, otherwise each is in its own.
+ private final boolean inSameNest;
+
+ // If true, the invoke will reference the actual type defining the method.
+ private final boolean symbolicReferenceIsDefiningType;
+
+ @Parameterized.Parameters(name = "{0}, in-same-nest:{1}, sym-ref-is-def-type:{2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters()
+ .withCfRuntimesStartingFromIncluding(JDK11)
+ .withDexRuntimes()
+ .withAllApiLevels()
+ .build(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
+ }
+
+ public NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest(
+ TestParameters parameters, boolean inSameNest, boolean symbolicReferenceIsDefiningType) {
+ this.parameters = parameters;
+ this.inSameNest = inSameNest;
+ this.symbolicReferenceIsDefiningType = symbolicReferenceIsDefiningType;
+ }
+
+ public Collection<Class<?>> getClasses() {
+ return ImmutableList.of(Main.class);
+ }
+
+ public Collection<byte[]> getTransformedClasses() throws Exception {
+ return ImmutableList.of(
+ withNest(I.class).setPrivate(I.class.getDeclaredMethod("bar")).transform(),
+ withNest(J.class).transform(),
+ withNest(A.class)
+ .transformMethodInsnInMethod(
+ "foo",
+ (opcode, owner, name, descriptor, isInterface, continuation) -> {
+ assertEquals(Opcodes.INVOKEVIRTUAL, opcode);
+ assertEquals(DescriptorUtils.getBinaryNameFromJavaType(A.class.getName()), owner);
+ String newOwner =
+ symbolicReferenceIsDefiningType
+ ? DescriptorUtils.getBinaryNameFromJavaType(I.class.getName())
+ : DescriptorUtils.getBinaryNameFromJavaType(J.class.getName());
+ continuation.apply(Opcodes.INVOKESPECIAL, newOwner, name, descriptor, true);
+ })
+ .transform());
+ }
+
+ private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
+ if (inSameNest) {
+ // If in the same nest make A host and B a member.
+ return transformer(clazz).setNest(I.class, J.class, A.class);
+ }
+ // Otherwise, set the class to be its own host and no additional members.
+ return transformer(clazz).setNest(clazz);
+ }
+
+ @Test
+ public void testResolutionAccess() throws Exception {
+ assumeFalse(
+ "b/144410139. Don't test internals for non-verifying input",
+ symbolicReferenceIsDefiningType);
+
+ // White-box test of the R8 resolution and lookup methods.
+ Class<?> definingClass = I.class;
+ Class<?> declaredClass = symbolicReferenceIsDefiningType ? definingClass : J.class;
+ Class<?> callerClass = A.class;
+
+ AppView<AppInfoWithLiveness> appView = getAppView();
+ AppInfoWithLiveness appInfo = appView.appInfo();
+
+ DexProgramClass declaredClassDefinition = getDexProgramClass(declaredClass, appInfo);
+
+ DexMethod method = getTargetMethodSignature(declaredClass, appInfo);
+
+ assertCallingClassCallsTarget(callerClass, appInfo, method);
+
+ // Resolve the method from the point of the declared holder.
+ assertEquals(method.holder, declaredClassDefinition.type);
+ ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method);
+
+ // The targeted method is a private interface method and thus not a maximally specific method.
+ assertTrue(resolutionResult instanceof NoSuchMethodResult);
+ }
+
+ private void assertCallingClassCallsTarget(
+ Class<?> callerClass, AppInfoWithLiveness appInfo, DexMethod method) {
+ CodeInspector inspector = new CodeInspector(appInfo.app());
+ MethodSubject foo = inspector.clazz(callerClass).uniqueMethodWithName("foo");
+ assertTrue(
+ foo.streamInstructions().anyMatch(i -> i.isInvokeSpecial() && i.getMethod() == method));
+ }
+
+ private DexMethod getTargetMethodSignature(Class<?> declaredClass, AppInfoWithLiveness appInfo) {
+ return buildMethod(
+ Reference.method(Reference.classFromClass(declaredClass), "bar", ImmutableList.of(), null),
+ appInfo.dexItemFactory());
+ }
+
+ private DexProgramClass getDexProgramClass(Class<?> definingClass, AppInfoWithLiveness appInfo) {
+ return appInfo
+ .definitionFor(buildType(definingClass, appInfo.dexItemFactory()))
+ .asProgramClass();
+ }
+
+ private AppView<AppInfoWithLiveness> getAppView() throws Exception {
+ return computeAppViewWithLiveness(
+ buildClasses(getClasses())
+ .addClassProgramData(getTransformedClasses())
+ .addLibraryFile(TestBase.runtimeJar(parameters.getBackend()))
+ .build(),
+ Main.class);
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(getClasses())
+ .addProgramClassFileData(getTransformedClasses())
+ .run(parameters.getRuntime(), Main.class)
+ .apply(result -> checkExpectedResult(result, false));
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(getClasses())
+ .addProgramClassFileData(getTransformedClasses())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .run(parameters.getRuntime(), Main.class)
+ .apply(result -> checkExpectedResult(result, true));
+ }
+
+ private void checkExpectedResult(TestRunResult<?> result, boolean isR8) {
+ if (symbolicReferenceIsDefiningType) {
+ assumeTrue(
+ "TODO(b/144410139): Input does not verify. Should compilation throw an error?",
+ parameters.isCfRuntime() && !isR8);
+ result.assertFailureWithErrorThatMatches(containsString(VerifyError.class.getName()));
+ } else if (isDesugaring()) {
+ // TODO(b/145775365): Desugaring results in a reference to a non-existent companion class.
+ result.assertFailureWithErrorThatMatches(
+ containsString(NoClassDefFoundError.class.getName()));
+ } else {
+ result.assertFailureWithErrorThatMatches(containsString(NoSuchMethodError.class.getName()));
+ }
+ }
+
+ private boolean isDesugaring() {
+ return parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(AndroidApiLevel.N);
+ }
+
+ interface I {
+ /* will be private */ default void bar() {
+ System.out.println("I::bar");
+ }
+ }
+
+ interface J extends I {
+ // Intentionally empty.
+ }
+
+ static class A implements J {
+ public void foo() {
+ // Rewritten to invoke-special I.bar or J.bar which resolves to private method I.bar
+ // With sym-ref I.bar the classfile fails verification.
+ // With sym-ref J.bar results in a NoSuchMethodError.
+ bar();
+ }
+ }
+
+ static class Main {
+ public static void main(String[] args) {
+ new A().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
new file mode 100644
index 0000000..490b7dc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
@@ -0,0 +1,192 @@
+// 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.resolution.access;
+
+import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ResolutionResult;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class NestInvokeSpecialMethodAccessTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("A::bar");
+
+ private final TestParameters parameters;
+ private final boolean inSameNest;
+
+ @Parameterized.Parameters(name = "{0}, in-same-nest:{1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters()
+ .withCfRuntimesStartingFromIncluding(JDK11)
+ .withDexRuntimes()
+ .withAllApiLevels()
+ .build(),
+ BooleanUtils.values());
+ }
+
+ public NestInvokeSpecialMethodAccessTest(TestParameters parameters, boolean inSameNest) {
+ this.parameters = parameters;
+ this.inSameNest = inSameNest;
+ }
+
+ private Collection<Class<?>> getClasses() {
+ return ImmutableList.of(Main.class);
+ }
+
+ private Collection<byte[]> getTransformedClasses() throws Exception {
+ return ImmutableList.of(
+ withNest(A.class).setPrivate(A.class.getDeclaredMethod("bar")).transform(),
+ withNest(B.class).transform());
+ }
+
+ private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
+ if (inSameNest) {
+ // If in the same nest make A host and B a member.
+ return transformer(clazz).setNest(A.class, B.class);
+ }
+ // Otherwise, set the class to be its own host and no additional members.
+ return transformer(clazz).setNest(clazz);
+ }
+
+ @Test
+ public void testResolutionAccess() throws Exception {
+ // White-box test of the R8 resolution and lookup methods.
+ Class<?> definingClass = A.class;
+ Class<?> declaredClass = A.class;
+ Class<?> callerClass = B.class;
+
+ AppView<AppInfoWithLiveness> appView = getAppView();
+ AppInfoWithLiveness appInfo = appView.appInfo();
+
+ DexClass definingClassDefinition = getDexProgramClass(definingClass, appInfo);
+ DexClass declaredClassDefinition = getDexProgramClass(declaredClass, appInfo);
+ DexProgramClass callerClassDefinition = getDexProgramClass(callerClass, appInfo);
+
+ DexMethod method = getTargetMethodSignature(declaredClass, appInfo);
+
+ assertCallingClassCallsTarget(callerClass, appInfo, method);
+
+ // Resolve the method from the point of the declared holder.
+ assertEquals(method.holder, declaredClassDefinition.type);
+ ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method);
+
+ // Verify that the resolved method is on the defining class.
+ assertEquals(
+ definingClassDefinition, resolutionResult.asSingleResolution().getResolvedHolder());
+
+ // Verify that the resolved method is accessible if in the same nest.
+ assertEquals(inSameNest, resolutionResult.isAccessibleFrom(callerClassDefinition, appInfo));
+
+ // Verify that looking up the dispatch target returns the defining method.
+ DexEncodedMethod targetSpecial =
+ resolutionResult.lookupInvokeSpecialTarget(callerClassDefinition, appInfo);
+ DexEncodedMethod targetSuper =
+ resolutionResult.lookupInvokeSuperTarget(callerClassDefinition, appInfo);
+ if (inSameNest) {
+ assertEquals(definingClassDefinition.type, targetSpecial.method.holder);
+ assertEquals(targetSpecial, targetSuper);
+ } else {
+ assertNull(targetSpecial);
+ assertNull(targetSuper);
+ }
+ }
+
+ private void assertCallingClassCallsTarget(
+ Class<?> callerClass, AppInfoWithLiveness appInfo, DexMethod target) {
+ CodeInspector inspector = new CodeInspector(appInfo.app());
+ MethodSubject foo = inspector.clazz(callerClass).uniqueMethodWithName("foo");
+ assertTrue(
+ foo.streamInstructions().anyMatch(i -> i.isInvokeSpecial() && i.getMethod() == target));
+ }
+
+ private DexMethod getTargetMethodSignature(Class<?> declaredClass, AppInfoWithLiveness appInfo) {
+ return buildMethod(
+ Reference.method(Reference.classFromClass(declaredClass), "bar", ImmutableList.of(), null),
+ appInfo.dexItemFactory());
+ }
+
+ private DexProgramClass getDexProgramClass(Class<?> definingClass, AppInfoWithLiveness appInfo) {
+ return appInfo
+ .definitionFor(buildType(definingClass, appInfo.dexItemFactory()))
+ .asProgramClass();
+ }
+
+ private AppView<AppInfoWithLiveness> getAppView() throws Exception {
+ return computeAppViewWithLiveness(
+ buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build(),
+ Main.class);
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(getClasses())
+ .addProgramClassFileData(getTransformedClasses())
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkExpectedResult);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(getClasses())
+ .addProgramClassFileData(getTransformedClasses())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkExpectedResult);
+ }
+
+ private void checkExpectedResult(TestRunResult<?> result) {
+ if (inSameNest) {
+ result.assertSuccessWithOutput(EXPECTED);
+ } else {
+ result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
+ }
+ }
+
+ static class A {
+ /* will be private */ void bar() {
+ System.out.println("A::bar");
+ }
+ }
+
+ static class B extends A {
+ public void foo() {
+ // invoke-special to private method.
+ super.bar();
+ }
+ }
+
+ static class Main {
+ public static void main(String[] args) {
+ new B().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
new file mode 100644
index 0000000..52dbd4b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
@@ -0,0 +1,247 @@
+// 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.resolution.access;
+
+import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ResolutionResult;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.Opcodes;
+
+/** Tests the behavior of invoke-special among related (non-interface) classes. */
+@RunWith(Parameterized.class)
+public class NestInvokeSpecialMethodAccessWithIntermediateTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("A::bar");
+
+ private final TestParameters parameters;
+
+ // If true, all classes are in the same nest, otherwise each is in its own.
+ private final boolean inSameNest;
+
+ // If true, the invoke will reference the actual type defining the method.
+ private final boolean symbolicReferenceIsDefiningType;
+
+ @Parameterized.Parameters(name = "{0}, in-same-nest:{1}, sym-ref-is-def-type:{2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters()
+ .withCfRuntimesStartingFromIncluding(JDK11)
+ .withDexRuntimes()
+ .withAllApiLevels()
+ .build(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
+ }
+
+ public NestInvokeSpecialMethodAccessWithIntermediateTest(
+ TestParameters parameters, boolean inSameNest, boolean symbolicReferenceIsDefiningType) {
+ this.parameters = parameters;
+ this.inSameNest = inSameNest;
+ this.symbolicReferenceIsDefiningType = symbolicReferenceIsDefiningType;
+ }
+
+ public Collection<Class<?>> getClasses() {
+ return ImmutableList.of(Main.class);
+ }
+
+ public Collection<byte[]> getTransformedClasses() throws Exception {
+ return ImmutableList.of(
+ withNest(A.class).setPrivate(A.class.getDeclaredMethod("bar")).transform(),
+ withNest(B.class).transform(),
+ withNest(C.class)
+ .transformMethodInsnInMethod(
+ "foo",
+ (opcode, owner, name, descriptor, isInterface, continuation) -> {
+ assertEquals(Opcodes.INVOKESPECIAL, opcode);
+ assertEquals(DescriptorUtils.getBinaryNameFromJavaType(B.class.getName()), owner);
+ String newOwner =
+ symbolicReferenceIsDefiningType
+ ? DescriptorUtils.getBinaryNameFromJavaType(A.class.getName())
+ : DescriptorUtils.getBinaryNameFromJavaType(B.class.getName());
+ continuation.apply(opcode, newOwner, name, descriptor, isInterface);
+ })
+ .transform());
+ }
+
+ private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
+ if (inSameNest) {
+ // If in the same nest make A host and B a member.
+ return transformer(clazz).setNest(A.class, B.class, C.class);
+ }
+ // Otherwise, set the class to be its own host and no additional members.
+ return transformer(clazz).setNest(clazz);
+ }
+
+ @Test
+ public void testResolutionAccess() throws Exception {
+ // White-box test of the R8 resolution and lookup methods.
+ Class<?> definingClass = A.class;
+ Class<?> declaredClass = symbolicReferenceIsDefiningType ? definingClass : B.class;
+ Class<?> callerClass = C.class;
+
+ AppView<AppInfoWithLiveness> appView = getAppView();
+ AppInfoWithLiveness appInfo = appView.appInfo();
+
+ DexClass definingClassDefinition = getDexProgramClass(definingClass, appInfo);
+ DexClass declaredClassDefinition = getDexProgramClass(declaredClass, appInfo);
+ DexProgramClass callerClassDefinition = getDexProgramClass(callerClass, appInfo);
+
+ DexMethod method = getTargetMethodSignature(declaredClass, appInfo);
+
+ assertCallingClassCallsTarget(callerClass, appInfo, method);
+
+ // Resolve the method from the point of the declared holder.
+ assertEquals(method.holder, declaredClassDefinition.type);
+ ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method);
+
+ // Verify that the resolved method is on the defining class.
+ assertEquals(
+ definingClassDefinition, resolutionResult.asSingleResolution().getResolvedHolder());
+
+ // Verify that the resolved method is accessible only when in the same nest.
+ assertEquals(inSameNest, resolutionResult.isAccessibleFrom(callerClassDefinition, appInfo));
+
+ // Verify that looking up the dispatch target returns a valid target
+ // iff in the same nest and declaredHolder == definingHolder.
+ DexEncodedMethod targetSpecial =
+ resolutionResult.lookupInvokeSpecialTarget(callerClassDefinition, appInfo);
+ DexEncodedMethod targetSuper =
+ resolutionResult.lookupInvokeSuperTarget(callerClassDefinition, appInfo);
+ if (inSameNest && symbolicReferenceIsDefiningType) {
+ assertEquals(definingClassDefinition.type, targetSpecial.method.holder);
+ assertEquals(targetSpecial, targetSuper);
+ } else {
+ assertNull(targetSpecial);
+ if (!inSameNest) {
+ assertNull(targetSuper);
+ } else {
+ // TODO(b/145775365): The current invoke-super will return the resolution target.
+ assertNotNull(targetSuper);
+ }
+ }
+ }
+
+ private void assertCallingClassCallsTarget(
+ Class<?> callerClass, AppInfoWithLiveness appInfo, DexMethod target) {
+ CodeInspector inspector = new CodeInspector(appInfo.app());
+ MethodSubject foo = inspector.clazz(callerClass).uniqueMethodWithName("foo");
+ assertTrue(
+ foo.streamInstructions().anyMatch(i -> i.isInvokeSpecial() && i.getMethod() == target));
+ }
+
+ private DexMethod getTargetMethodSignature(Class<?> declaredClass, AppInfoWithLiveness appInfo) {
+ return buildMethod(
+ Reference.method(Reference.classFromClass(declaredClass), "bar", ImmutableList.of(), null),
+ appInfo.dexItemFactory());
+ }
+
+ private DexProgramClass getDexProgramClass(Class<?> clazz, AppInfoWithLiveness appInfo) {
+ return appInfo.definitionFor(buildType(clazz, appInfo.dexItemFactory())).asProgramClass();
+ }
+
+ private AppView<AppInfoWithLiveness> getAppView() throws Exception {
+ return computeAppViewWithLiveness(
+ buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build(),
+ Main.class);
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(getClasses())
+ .addProgramClassFileData(getTransformedClasses())
+ .run(parameters.getRuntime(), Main.class)
+ .apply(result -> checkExpectedResult(result, false));
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(getClasses())
+ .addProgramClassFileData(getTransformedClasses())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .run(parameters.getRuntime(), Main.class)
+ .apply(result -> checkExpectedResult(result, true));
+ }
+
+ private void checkExpectedResult(TestRunResult<?> result, boolean isR8) {
+ // If not in the same nest, the error is always illegal access.
+ if (!inSameNest) {
+ result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
+ return;
+ }
+
+ // If in the same nest but the reference is not exact, the error is always no such method.
+ if (!symbolicReferenceIsDefiningType) {
+ // TODO(b/145775365): R8 incorrectly compiles the input to a working program.
+ if (isR8) {
+ result.assertSuccessWithOutput(EXPECTED);
+ return;
+ }
+ // TODO(b/145775365): D8/R8 does not preserve the thrown error.
+ if (parameters.isDexRuntime()) {
+ result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
+ return;
+ }
+ result.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+ return;
+ }
+
+ // Finally, if in the same nest and the reference is exact match the program runs successfully.
+ result.assertSuccessWithOutput(EXPECTED);
+ }
+
+ static class A {
+ /* will be private */ void bar() {
+ System.out.println("A::bar");
+ }
+ }
+
+ static class B extends A {
+ // Intentionally empty.
+ }
+
+ static class C extends B {
+ public void foo() {
+ // invoke-special A.bar or B.bar which resolves to private method A.bar
+ // Without nests, results in an IllegalAccessError.
+ // With nests and sym-ref B.bar, results in a NoSuchMethodError.
+ // With nests and sym-ref A.bar runs without error.
+ super.bar();
+ }
+ }
+
+ static class Main {
+ public static void main(String[] args) {
+ new C().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
new file mode 100644
index 0000000..49426c4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
@@ -0,0 +1,190 @@
+// 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.resolution.access;
+
+import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ResolutionResult;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class NestInvokeSpecialMethodPublicAccessWithIntermediateTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("A::bar");
+
+ private final TestParameters parameters;
+ private final boolean inSameNest;
+
+ @Parameterized.Parameters(name = "{0}, in-same-nest:{1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters()
+ .withCfRuntimesStartingFromIncluding(JDK11)
+ .withDexRuntimes()
+ .withAllApiLevels()
+ .build(),
+ BooleanUtils.values());
+ }
+
+ public NestInvokeSpecialMethodPublicAccessWithIntermediateTest(
+ TestParameters parameters, boolean inSameNest) {
+ this.parameters = parameters;
+ this.inSameNest = inSameNest;
+ }
+
+ public Collection<Class<?>> getClasses() {
+ return ImmutableList.of(Main.class);
+ }
+
+ public Collection<byte[]> getTransformedClasses() throws Exception {
+ return ImmutableList.of(
+ withNest(A.class).transform(),
+ withNest(B.class).transform(),
+ withNest(C.class).transform());
+ }
+
+ private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
+ if (inSameNest) {
+ // If in the same nest make A host and B a member.
+ return transformer(clazz).setNest(A.class, B.class, C.class);
+ }
+ // Otherwise, set the class to be its own host and no additional members.
+ return transformer(clazz).setNest(clazz);
+ }
+
+ @Test
+ public void testResolutionAccess() throws Exception {
+ // White-box test of the R8 resolution and lookup methods.
+ Class<?> definingClass = A.class;
+ Class<?> declaredClass = B.class;
+ Class<?> callerClass = C.class;
+
+ AppView<AppInfoWithLiveness> appView = getAppView();
+
+ AppInfoWithLiveness appInfo = appView.appInfo();
+
+ DexClass definingClassDefinition = getDexProgramClass(definingClass, appInfo);
+ DexClass declaredClassDefinition = getDexProgramClass(declaredClass, appInfo);
+ DexProgramClass callerClassDefinition = getDexProgramClass(callerClass, appInfo);
+
+ DexMethod method = getTargetMethodSignature(declaredClass, appInfo);
+
+ assertCallingClassCallsTarget(callerClass, appInfo, method);
+
+ // Resolve the method from the point of the declared holder.
+ assertEquals(method.holder, declaredClassDefinition.type);
+ ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method);
+
+ // Verify that the resolved method is on the defining class.
+ assertEquals(
+ definingClassDefinition, resolutionResult.asSingleResolution().getResolvedHolder());
+
+ // Verify that the resolved method is accessible (it is public).
+ assertTrue(resolutionResult.isAccessibleFrom(callerClassDefinition, appInfo));
+
+ // Verify that looking up the dispatch target returns the defining method.
+ DexEncodedMethod targetSpecial =
+ resolutionResult.lookupInvokeSpecialTarget(callerClassDefinition, appInfo);
+ assertEquals(definingClassDefinition.type, targetSpecial.method.holder);
+
+ DexEncodedMethod targetSuper =
+ resolutionResult.lookupInvokeSuperTarget(callerClassDefinition, appInfo);
+ assertEquals(targetSpecial, targetSuper);
+ }
+
+ private void assertCallingClassCallsTarget(
+ Class<?> callerClass, AppInfoWithLiveness appInfo, DexMethod target) {
+ CodeInspector inspector = new CodeInspector(appInfo.app());
+ MethodSubject foo = inspector.clazz(callerClass).uniqueMethodWithName("foo");
+ assertTrue(
+ foo.streamInstructions().anyMatch(i -> i.isInvokeSpecial() && i.getMethod() == target));
+ }
+
+ private DexMethod getTargetMethodSignature(Class<?> declaredClass, AppInfoWithLiveness appInfo) {
+ return buildMethod(
+ Reference.method(Reference.classFromClass(declaredClass), "bar", ImmutableList.of(), null),
+ appInfo.dexItemFactory());
+ }
+
+ private DexProgramClass getDexProgramClass(Class<?> clazz, AppInfoWithLiveness appInfo) {
+ return appInfo.definitionFor(buildType(clazz, appInfo.dexItemFactory())).asProgramClass();
+ }
+
+ private AppView<AppInfoWithLiveness> getAppView() throws Exception {
+ return computeAppViewWithLiveness(
+ buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build(),
+ Main.class);
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(getClasses())
+ .addProgramClassFileData(getTransformedClasses())
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkExpectedResult);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(getClasses())
+ .addProgramClassFileData(getTransformedClasses())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkExpectedResult);
+ }
+
+ private void checkExpectedResult(TestRunResult<?> result) {
+ result.assertSuccessWithOutput(EXPECTED);
+ }
+
+ static class A {
+ public void bar() {
+ System.out.println("A::bar");
+ }
+ }
+
+ static class B extends A {
+ // Intentionally empty.
+ }
+
+ static class C extends B {
+ public void foo() {
+ // invoke-special B.bar which resolves to private method A.bar
+ // Without nests, results in an IllegalAccessError.
+ // With nests, results in a NoSuchMethodError.
+ super.bar();
+ }
+ }
+
+ static class Main {
+ public static void main(String[] args) {
+ new C().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
index d6343fc..3e85f1a 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
@@ -4,12 +4,8 @@
package com.android.tools.r8.resolution.access;
import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
-import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRunResult;
@@ -89,31 +85,20 @@
@Test
public void testR8() throws Exception {
- R8FullTestBuilder builder =
- testForR8(parameters.getBackend())
- .addProgramClasses(getClasses())
- .addProgramClassFileData(getTransformedClasses())
- .setMinApi(parameters.getApiLevel())
- .addKeepMainRule(Main.class);
- // TODO(b/145196085): R8 fails compilation when the classes are in the same nest.
- if (inSameNest) {
- if (parameters.isDexRuntime()) {
- try {
- builder.compile();
- } catch (CompilationFailedException e) {
- // Expected failure.
- return;
- }
- fail("Expected failure: b/145196085");
- }
- }
- builder
+ testForR8(parameters.getBackend())
+ .addProgramClasses(getClasses())
+ .addProgramClassFileData(getTransformedClasses())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
.run(parameters.getRuntime(), Main.class)
.apply(
result -> {
- if (inSameNest) {
- // TODO(b/145187969): R8 compiles out the errors when in the same nest.
+ if (inSameNest && parameters.isCfRuntime()) {
+ // TODO(b/145187969): R8/CF compiles to a "working" program.
result.assertSuccessWithOutput(EXPECTED);
+ } else if (inSameNest && parameters.isDexRuntime()) {
+ // TODO(b/145187969): R8/DEX compiles to a throw null program.
+ result.assertFailureWithErrorThatThrows(NullPointerException.class);
} else {
checkExpectedResult(result);
}
@@ -123,9 +108,9 @@
private void checkExpectedResult(TestRunResult<?> result) {
if (inSameNest && parameters.isCfRuntime()) {
// TODO(b/145187969): Investigate if the change to NoSuchMethodError is according to spec?
- result.assertFailureWithErrorThatMatches(containsString(NoSuchMethodError.class.getName()));
+ result.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
} else {
- result.assertFailureWithErrorThatMatches(containsString(IllegalAccessError.class.getName()));
+ result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
}
}
diff --git a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
index 3985648..8ae759f 100644
--- a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
@@ -58,7 +58,7 @@
options.enableValuePropagationForInstanceFields = true;
})
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
diff --git a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java
index 1b54e8a..6f18cdc 100644
--- a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java
@@ -52,46 +52,57 @@
.addInnerClasses(EffectivelyFinalStaticFieldsTest.class)
.addKeepMainRule(MAIN)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
- .inspect(codeInspector -> {
- ClassSubject main = codeInspector.clazz(MAIN);
- assertThat(main, isPresent());
+ .inspect(
+ codeInspector -> {
+ ClassSubject main = codeInspector.clazz(MAIN);
+ assertThat(main, isPresent());
- MethodSubject mainMethod = main.mainMethod();
- assertThat(mainMethod, isPresent());
+ MethodSubject mainMethod = main.mainMethod();
+ assertThat(mainMethod, isPresent());
- assertTrue(
- mainMethod.streamInstructions().noneMatch(
- i -> i.isConstString("Dead code: 1", JumboStringMode.ALLOW)));
- // TODO(b/138913138): effectively final, and default value is set.
- assertFalse(
- mainMethod.streamInstructions().noneMatch(
- i -> i.isConstString("Dead code: 2", JumboStringMode.ALLOW)));
- // TODO(b/138913138): not trivial; assigned multiple times, but can determine the value.
- assertFalse(
- mainMethod.streamInstructions().noneMatch(
- i -> i.isConstString("Dead code: 3", JumboStringMode.ALLOW)));
- assertTrue(
- mainMethod.streamInstructions().noneMatch(
- i -> i.isConstString("Dead code: 4", JumboStringMode.ALLOW)));
- assertTrue(
- mainMethod.streamInstructions().noneMatch(
- i -> i.isConstString("Dead code: 5", JumboStringMode.ALLOW)));
- // TODO(b/138913138): not trivial; assigned multiple times, but within a certain range.
- assertFalse(
- mainMethod.streamInstructions().noneMatch(
- i -> i.isConstString("Dead code: 6", JumboStringMode.ALLOW)));
- assertTrue(
- mainMethod.streamInstructions().noneMatch(
- i -> i.isConstString("Dead code: 7", JumboStringMode.ALLOW)));
- // TODO(b/138913138): effectively final, and default value is set.
- assertFalse(
- mainMethod.streamInstructions().noneMatch(
- i -> i.isConstString("Dead code: 8", JumboStringMode.ALLOW)));
- })
+ assertTrue(
+ mainMethod
+ .streamInstructions()
+ .noneMatch(i -> i.isConstString("Dead code: 1", JumboStringMode.ALLOW)));
+ // TODO(b/138913138): effectively final, and default value is set.
+ assertFalse(
+ mainMethod
+ .streamInstructions()
+ .noneMatch(i -> i.isConstString("Dead code: 2", JumboStringMode.ALLOW)));
+ // TODO(b/138913138): not trivial; assigned multiple times, but can determine the
+ // value.
+ assertFalse(
+ mainMethod
+ .streamInstructions()
+ .noneMatch(i -> i.isConstString("Dead code: 3", JumboStringMode.ALLOW)));
+ assertTrue(
+ mainMethod
+ .streamInstructions()
+ .noneMatch(i -> i.isConstString("Dead code: 4", JumboStringMode.ALLOW)));
+ assertTrue(
+ mainMethod
+ .streamInstructions()
+ .noneMatch(i -> i.isConstString("Dead code: 5", JumboStringMode.ALLOW)));
+ // TODO(b/138913138): not trivial; assigned multiple times, but within a certain
+ // range.
+ assertFalse(
+ mainMethod
+ .streamInstructions()
+ .noneMatch(i -> i.isConstString("Dead code: 6", JumboStringMode.ALLOW)));
+ assertTrue(
+ mainMethod
+ .streamInstructions()
+ .noneMatch(i -> i.isConstString("Dead code: 7", JumboStringMode.ALLOW)));
+ // TODO(b/138913138): effectively final, and default value is set.
+ assertFalse(
+ mainMethod
+ .streamInstructions()
+ .noneMatch(i -> i.isConstString("Dead code: 8", JumboStringMode.ALLOW)));
+ })
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("The end");
}
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java
index 9398f79..d24d8c1 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java
@@ -46,7 +46,7 @@
@Test
public void test() throws Exception {
testForR8Compat(backend)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.addProgramClasses(CLASSES)
.addKeepMainRule(MainClass.class)
.addKeepRules(
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/PrunedOrMergedAnnotationTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/PrunedOrMergedAnnotationTest.java
index 45b29f7..9b11b86 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/PrunedOrMergedAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/PrunedOrMergedAnnotationTest.java
@@ -52,7 +52,7 @@
.addKeepAttributes("*Annotation*")
.addKeepClassAndMembersRules(Factory.class)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("Hello", "World!")
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
index 8928015..ebf633c 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
@@ -151,7 +151,7 @@
.addKeepRules(config.getKeepRule())
.noMinification()
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java
index 6806661..29e4588 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java
@@ -94,7 +94,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(AssumenosideeffectsWithMultipleTargetsTest.class)
.enableMergeAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addKeepMainRule(MAIN)
.addKeepRules(config.getKeepRule())
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/StringBuildersAfterAssumenosideeffectsTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/StringBuildersAfterAssumenosideeffectsTest.java
index 9507055..2787932 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/StringBuildersAfterAssumenosideeffectsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/StringBuildersAfterAssumenosideeffectsTest.java
@@ -18,8 +18,8 @@
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import org.junit.Test;
-import org.junit.runners.Parameterized;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class StringBuildersAfterAssumenosideeffectsTest extends TestBase {
@@ -43,7 +43,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(StringBuildersAfterAssumenosideeffectsTest.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addKeepMainRule(MAIN)
.addKeepRules(
diff --git a/src/test/java/com/android/tools/r8/shaking/assumevalues/AssumevaluesWithMultipleTargetsTest.java b/src/test/java/com/android/tools/r8/shaking/assumevalues/AssumevaluesWithMultipleTargetsTest.java
index f91de77..eb205d0 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumevalues/AssumevaluesWithMultipleTargetsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumevalues/AssumevaluesWithMultipleTargetsTest.java
@@ -155,7 +155,7 @@
public void testR8() throws Exception {
testForR8(parameters.getBackend())
.addProgramClasses(MAIN, Seed.class, Itf.class, Impl1.class, Impl2.class)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addKeepMainRule(MAIN)
.addKeepRules(config.getKeepRule())
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
index 268a673..8cb1cf0 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
@@ -11,8 +11,6 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
-import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestShrinkerBuilder;
import com.android.tools.r8.errors.Unreachable;
@@ -31,12 +29,7 @@
public class IfOnAccessModifierTest extends ProguardCompatibilityTestBase {
private static final List<Class<?>> CLASSES =
- ImmutableList.of(
- ClassForIf.class,
- ClassForSubsequent.class,
- MainForAccessModifierTest.class,
- NeverClassInline.class,
- NeverInline.class);
+ ImmutableList.of(ClassForIf.class, ClassForSubsequent.class, MainForAccessModifierTest.class);
private final TestParameters parameters;
private final Shrinker shrinker;
@@ -57,11 +50,12 @@
switch (shrinker) {
case PROGUARD6:
assertTrue(parameters.isCfRuntime());
- return testForProguard();
+ return testForProguard().addTestingAnnotationsAsProgramClasses();
case R8:
return testForR8(parameters.getBackend())
+ .addTestingAnnotationsAsProgramClasses()
.allowUnusedProguardConfigurationRules()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations();
default:
throw new Unreachable();
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java
index 8d14c5d..b4e4fce 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java
@@ -56,7 +56,7 @@
"}",
"-keep class " + Unused.class.getTypeName())
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.run(TestClass.class)
.assertSuccessWithOutput(expectedOutput)
.inspector();
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
index 32b5fdf..54fcadf 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
@@ -48,7 +48,7 @@
"-keep class " + Unused2.class.getTypeName())
.allowUnusedProguardConfigurationRules()
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations()
.setMinApi(AndroidApiLevel.M)
.run(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
index 4dba762..1346579 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
@@ -128,7 +128,7 @@
.addProgramClasses(CLASSES)
.addKeepMainRule(Main.class)
.addKeepRules(config)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.addOptionsModification(this::configure)
.run(Main.class)
.assertSuccessWithOutput("123456")
diff --git a/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesTest.java b/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesTest.java
index f618e93..888b231 100644
--- a/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesTest.java
@@ -206,7 +206,7 @@
"In Api.api2",
"In Api.api3");
testForR8(parameters.getBackend())
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.enableUnusedArgumentAnnotations()
.addInnerClasses(KeepParameterNamesTest.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByKeepClassMembersNonStaticTestRunner.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByKeepClassMembersNonStaticTestRunner.java
index d4b5cdd..cd8f5ba 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByKeepClassMembersNonStaticTestRunner.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByKeepClassMembersNonStaticTestRunner.java
@@ -89,7 +89,7 @@
testForR8(parameters.getBackend())
.enableGraphInspector(whyAreYouKeepingConsumer)
.enableInliningAnnotations()
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMemberValuePropagationAnnotations()
.addProgramClasses(CLASS)
.addKeepMainRule(CLASS)
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java
index 62ec020..ba1c576 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java
@@ -68,7 +68,7 @@
WhyAreYouKeepingConsumer whyAreYouKeepingConsumer = new WhyAreYouKeepingConsumer(null);
GraphInspector inspector =
testForR8(parameters.getBackend())
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableGraphInspector(whyAreYouKeepingConsumer)
.addProgramClasses(testClass, fooClass)
.addKeepMainRule(testClass)
diff --git a/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideTest.java b/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideTest.java
index 18188ff..0f8a6bd 100644
--- a/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideTest.java
@@ -41,7 +41,7 @@
.addInnerClasses(LibraryMethodOverrideTest.class)
.addKeepMainRule(TestClass.class)
.addOptionsModification(options -> options.enableTreeShakingOfLibraryMethodOverrides = true)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableMergeAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
diff --git a/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingOverriddenMethodTest.java b/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingOverriddenMethodTest.java
index 8a28bdf..2914c4e 100644
--- a/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingOverriddenMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingOverriddenMethodTest.java
@@ -51,7 +51,7 @@
.addKeepMainRule(main)
.addKeepRules(
"-whyareyoukeeping class **.*$" + targetClass.getSimpleName() + " { void gone(); }")
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.enableMergeAnnotations()
.minification(minification)
@@ -70,7 +70,7 @@
testForR8(Backend.DEX)
.addInnerClasses(WhyAreYouKeepingOverriddenMethodTest.class)
.addKeepMainRule(main)
- .enableClassInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.enableMergeAnnotations()
.minification(minification)
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
index a9ea1b7..b2c8b6f 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
@@ -261,6 +261,7 @@
&& ((CfSwitch) instruction).getKind() == CfSwitch.Kind.LOOKUP;
}
+ @Override
public boolean isInvokeSpecial() {
return instruction instanceof CfInvoke
&& ((CfInvoke) instruction).getOpcode() == Opcodes.INVOKESPECIAL;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
index c46c123..af63ce8 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
@@ -192,6 +192,11 @@
return instruction instanceof InvokeStatic || instruction instanceof InvokeStaticRange;
}
+ @Override
+ public boolean isInvokeSpecial() {
+ return false;
+ }
+
public boolean isInvokeSuper() {
return instruction instanceof InvokeSuper || instruction instanceof InvokeSuperRange;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
index 9c67ece..ebe2f02 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
@@ -36,6 +36,8 @@
boolean isInvokeStatic();
+ boolean isInvokeSpecial();
+
DexMethod getMethod();
boolean isNop();
diff --git a/tools/archive_desugar_jdk_libs.py b/tools/archive_desugar_jdk_libs.py
index f866564..295e006 100755
--- a/tools/archive_desugar_jdk_libs.py
+++ b/tools/archive_desugar_jdk_libs.py
@@ -48,16 +48,16 @@
return (options, args)
-def GetVersion():
- with open(VERSION_FILE, 'r') as version_file:
+def GetVersion(version_file_name):
+ with open(version_file_name, 'r') as version_file:
lines = [line.strip() for line in version_file.readlines()]
lines = [line for line in lines if not line.startswith('#')]
if len(lines) != 1:
raise Exception('Version file '
- + VERSION_FILE + ' is expected to have exactly one line')
+ + version_file + ' is expected to have exactly one line')
version = lines[0].strip()
utils.check_basic_semver_version(
- version, 'in version file ' + VERSION_FILE)
+ version, 'in version file ' + version_file_name)
return version
@@ -106,7 +106,7 @@
'https://github.com/'
+ options.github_account + '/' + LIBRARY_NAME, checkout_dir)
with utils.ChangedWorkingDirectory(checkout_dir):
- version = GetVersion()
+ version = GetVersion(VERSION_FILE)
destination = archive.GetVersionDestination(
'gs://', LIBRARY_NAME + '/' + version, is_master)
diff --git a/tools/r8_release.py b/tools/r8_release.py
index 366b908..bdb8242 100755
--- a/tools/r8_release.py
+++ b/tools/r8_release.py
@@ -15,6 +15,7 @@
import xml.etree.ElementTree as et
import zipfile
+import archive_desugar_jdk_libs
import update_prebuilds_in_android
import utils
@@ -28,6 +29,7 @@
DESUGAR_JDK_LIBS_CONFIGURATION = DESUGAR_JDK_LIBS + '_configuration'
ANDROID_TOOLS_PACKAGE = 'com.android.tools'
+GITHUB_DESUGAR_JDK_LIBS = 'https://github.com/google/desugar_jdk_libs'
def prepare_release(args):
if args.version:
@@ -269,8 +271,7 @@
def g4_change(version, r8version):
return subprocess.check_output(
- 'g4 change --desc "Update R8 to version %s %s\n\n'
- 'IGNORE_COMPLIANCELINT=b/145307639"' % (version, r8version),
+ 'g4 change --desc "Update R8 to version %s %s\n"' % (version, r8version),
shell=True)
@@ -297,9 +298,7 @@
assert args.version
# Check if an existing client exists.
if not args.use_existing_work_branch:
- if ':update-r8:' in subprocess.check_output('g4 myclients', shell=True):
- print "Remove the existing 'update-r8' client before continuing."
- sys.exit(1)
+ check_no_google3_client(args, 'update-r8')
def release_google3(options):
print "Releasing for Google 3"
@@ -417,6 +416,41 @@
return make_release
+def prepare_push_desugar_library(args):
+ client_name = 'push-desugar-library'
+ # Check if an existing client exists.
+ check_no_google3_client(args, client_name)
+
+ def push_desugar_library(options):
+ print 'Pushing to %s' % GITHUB_DESUGAR_JDK_LIBS
+
+ google3_base = subprocess.check_output(
+ ['p4', 'g4d', '-f', client_name]).rstrip()
+ third_party_desugar_jdk_libs = \
+ os.path.join(google3_base, 'third_party', 'java_src', 'desugar_jdk_libs')
+ version = archive_desugar_jdk_libs.GetVersion(
+ os.path.join(third_party_desugar_jdk_libs, 'oss', 'VERSION.txt'))
+ if args.push_desugar_library != version:
+ print ("Failed, version of desugared library is %s, but version %s was expected." %
+ (version, args.push_desugar_library))
+ sys.exit(1)
+ with utils.ChangedWorkingDirectory(google3_base):
+ cmd = [
+ 'copybara',
+ os.path.join(
+ 'third_party',
+ 'java_src',
+ 'desugar_jdk_libs',
+ 'copy.bara.sky'),
+ 'push-to-github']
+ if options.dry_run:
+ print "Dry-run, not running '%s'" % ' '.join(cmd)
+ else:
+ subprocess.check_call(cmd)
+
+ return push_desugar_library
+
+
def download_configuration(hash, archive):
print
print 'Downloading %s from GCS' % archive
@@ -445,6 +479,16 @@
return '%s:%s:%s' % \
(ANDROID_TOOLS_PACKAGE, DESUGAR_JDK_LIBS_CONFIGURATION, version)
+
+def check_no_google3_client(args, client_name):
+ if not args.use_existing_work_branch:
+ clients = subprocess.check_output('g4 myclients', shell=True)
+ if ':%s:' % client_name in clients:
+ print ("Remove the existing '%s' client before continuing, " +
+ "or use option --use-existing-work-branch.") % client_name
+ sys.exit(1)
+
+
def extract_version_from_pom(pom_file):
ns = "http://maven.apache.org/POM/4.0.0"
xml.etree.ElementTree.register_namespace('', ns)
@@ -509,7 +553,7 @@
cmd = [ADMRT, '--archives']
cmd.extend(archives)
cmd.extend(['--action', action])
- subprocess.check_call()
+ subprocess.check_call(cmd)
def branch_change_diff(diff, old_version, new_version):
@@ -639,6 +683,10 @@
group.add_argument('--version',
metavar=('<version>'),
help='The new version of R8 (e.g., 1.4.51) to release to selected channels')
+ group.add_argument('--push-desugar-library',
+ metavar=('<version>'),
+ help='The expected version of '
+ + 'com.android.tools:desugar_jdk_libs to push to GitHub')
group.add_argument('--desugar-library',
nargs=2,
metavar=('<version>', '<configuration hash>'),
@@ -720,7 +768,8 @@
if (args.google3
or (args.studio and not args.no_sync)
- or (args.desugar_library and not args.dry_run)):
+ or (args.desugar_library and not args.dry_run)
+ or (args.push_desugar_library and not args.dry_run)):
utils.check_prodacces()
if args.google3:
@@ -733,6 +782,9 @@
if args.desugar_library:
targets_to_run.append(prepare_desugar_library(args))
+ if args.push_desugar_library:
+ targets_to_run.append(prepare_push_desugar_library(args))
+
final_results = []
for target_closure in targets_to_run:
final_results.append(target_closure(args))
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index 0941623..c31bfea 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -509,6 +509,7 @@
if 'allow-type-errors' in values:
extra_args.append('-Dcom.android.tools.r8.allowTypeErrors=1')
if 'proto-shrinking' in values:
+ extra_args.append('-Dcom.android.tools.r8.applyInliningToInlinee=1')
extra_args.append('-Dcom.android.tools.r8.fieldBitAccessAnalysis=1')
extra_args.append('-Dcom.android.tools.r8.generatedExtensionRegistryShrinking=1')
extra_args.append('-Dcom.android.tools.r8.generatedMessageLiteShrinking=1')