Merge "Remove DebugLocalWrite when it is possible"
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index e8990f3..1306e3b 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -63,7 +63,9 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -452,21 +454,31 @@
}
}
+ private static void writeProguardMapToPath(Path path, AndroidApp outputApp) throws IOException {
+ try (Closer closer = Closer.create()) {
+ OutputStream mapOut = FileUtils.openPathWithDefault(
+ closer,
+ path,
+ System.out,
+ StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
+ outputApp.writeProguardMap(mapOut);
+ }
+ }
+
static void writeOutputs(R8Command command, InternalOptions options, AndroidApp outputApp)
throws IOException {
if (command.getOutputPath() != null) {
outputApp.write(command.getOutputPath(), options.outputMode);
}
- if (options.proguardConfiguration.isPrintMapping() && !options.skipMinification) {
+ if ((options.proguardConfiguration.isPrintMapping() || options.printMappingFile != null)
+ && !options.skipMinification) {
assert outputApp.hasProguardMap();
- try (Closer closer = Closer.create()) {
- OutputStream mapOut = FileUtils.openPathWithDefault(
- closer,
- options.proguardConfiguration.getPrintMappingFile(),
- System.out,
- StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
- outputApp.writeProguardMap(mapOut);
+ if (options.proguardConfiguration.isPrintMapping()) {
+ writeProguardMapToPath(options.proguardConfiguration.getPrintMappingFile(), outputApp);
+ }
+ if (options.printMappingFile != null) {
+ writeProguardMapToPath(options.printMappingFile, outputApp);
}
}
if (options.proguardConfiguration.isPrintSeeds()) {
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index b860de4..301c266 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -36,6 +36,7 @@
private Optional<Boolean> discardedChecker = Optional.empty();
private Optional<Boolean> minification = Optional.empty();
private boolean ignoreMissingClasses = false;
+ private Path printMappingFile = null;
private Path packageDistributionFile = null;
private Builder() {
@@ -176,6 +177,11 @@
return self();
}
+ Builder setPrintMappingFile(Path path) {
+ this.printMappingFile = path;
+ return self();
+ }
+
protected void validate() throws CompilationException {
super.validate();
if (mainDexListOutput != null && mainDexRules.isEmpty() && !getAppBuilder()
@@ -251,7 +257,8 @@
useTreeShaking,
useDiscardedChecker,
useMinification,
- ignoreMissingClasses);
+ ignoreMissingClasses,
+ printMappingFile);
}
}
@@ -274,6 +281,7 @@
" --pg-conf <file> # Proguard configuration <file> (implies tree",
" # shaking/minification).",
" --pg-map <file> # Proguard map <file>.",
+ " --print-mapping <file> # Write name/line mapping to <file>.",
" --no-tree-shaking # Force disable tree shaking of unreachable classes.",
" --no-discarded-checker # Force disable the discarded checker (when tree shaking).",
" --no-minification # Force disable minification of names.",
@@ -291,6 +299,7 @@
private final boolean useDiscardedChecker;
private final boolean useMinification;
private final boolean ignoreMissingClasses;
+ private final Path printMappingFile;
public static Builder builder() {
return new Builder();
@@ -362,6 +371,8 @@
builder.setProguardMapFile(Paths.get(args[++i]));
} else if (arg.equals("--ignore-missing-classes")) {
builder.setIgnoreMissingClasses(true);
+ } else if (arg.equals("--print-mapping")) {
+ builder.setPrintMappingFile(Paths.get(args[++i]));
} else if (arg.startsWith("@")) {
// TODO(zerny): Replace this with pipe reading.
String argsFile = arg.substring(1);
@@ -404,7 +415,8 @@
boolean useTreeShaking,
boolean useDiscardedChecker,
boolean useMinification,
- boolean ignoreMissingClasses) {
+ boolean ignoreMissingClasses,
+ Path printMappingFile) {
super(inputApp, outputPath, outputMode, mode, minApiLevel);
assert proguardConfiguration != null;
assert mainDexKeepRules != null;
@@ -416,6 +428,7 @@
this.useDiscardedChecker = useDiscardedChecker;
this.useMinification = useMinification;
this.ignoreMissingClasses = ignoreMissingClasses;
+ this.printMappingFile = printMappingFile;
}
private R8Command(boolean printHelp, boolean printVersion) {
@@ -427,8 +440,8 @@
useDiscardedChecker = false;
useMinification = false;
ignoreMissingClasses = false;
+ printMappingFile = null;
}
-
public boolean useTreeShaking() {
return useTreeShaking;
}
@@ -471,6 +484,7 @@
// TODO(zerny): Should we support inlining in debug mode? b/62937285
internal.inlineAccessors = false;
}
+ internal.printMappingFile = printMappingFile;
return internal;
}
}
diff --git a/src/main/java/com/android/tools/r8/annotations/SynthesizedClassMap.java b/src/main/java/com/android/tools/r8/annotations/SynthesizedClassMap.java
new file mode 100644
index 0000000..b46a2ba
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/annotations/SynthesizedClassMap.java
@@ -0,0 +1,15 @@
+// Copyright (c) 2017, 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface SynthesizedClassMap {
+ Class<?>[] value() default {};
+}
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 1e70b9b..eba5613 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -133,7 +133,7 @@
// Sort the class members.
// Needed before adding static-value arrays and writing annotation directories and classes.
- sortClassData(mixedSectionOffsets.getClassesWithData());
+ mixedSectionOffsets.getClassesWithData().forEach(DexProgramClass::sortMembers);
// Add the static values for all fields now that we have committed to their sorting.
mixedSectionOffsets.getClassesWithData().forEach(this::addStaticFieldValues);
@@ -254,23 +254,6 @@
return Arrays.copyOf(dest.asArray(), layout.getEndOfFile());
}
- private void sortClassData(Collection<DexProgramClass> classesWithData) {
- for (DexProgramClass clazz : classesWithData) {
- sortEncodedFields(clazz.instanceFields());
- sortEncodedFields(clazz.staticFields());
- sortEncodedMethods(clazz.directMethods());
- sortEncodedMethods(clazz.virtualMethods());
- }
- }
-
- private void sortEncodedFields(DexEncodedField[] fields) {
- Arrays.sort(fields, (DexEncodedField a, DexEncodedField b) -> a.field.compareTo(b.field));
- }
-
- private void sortEncodedMethods(DexEncodedMethod[] methods) {
- Arrays.sort(methods, (DexEncodedMethod a, DexEncodedMethod b) -> a.method.compareTo(b.method));
- }
-
private void checkInterfaceMethods() throws ApiLevelException {
for (DexProgramClass clazz : mapping.getClasses()) {
if (clazz.isInterface()) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index 1afd77e..3a8d56b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -13,7 +13,11 @@
import com.android.tools.r8.graph.DexValue.DexValueString;
import com.android.tools.r8.graph.DexValue.DexValueType;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
public class DexAnnotation extends DexItem {
public static final int VISIBILITY_BUILD = 0x00;
@@ -228,4 +232,37 @@
private static DexValue toDexValue(String string, DexItemFactory factory) {
return new DexValueString(factory.createString(string));
}
+
+ public static Collection<DexType> readAnnotationSynthesizedClassMap(
+ DexProgramClass programClass,
+ DexItemFactory dexItemFactory) {
+ DexAnnotation foundAnnotation = programClass.annotations.getFirstMatching(
+ dexItemFactory.annotationSynthesizedClassMap);
+ if (foundAnnotation != null) {
+ DexAnnotationElement value = foundAnnotation.annotation.elements[0];
+ assert value.name.toSourceString().equals("value");
+ DexValueArray existingList = (DexValueArray) value.value;
+ Collection<DexType> synthesized = new ArrayList<>(existingList.values.length);
+ for (DexValue element : existingList.getValues()) {
+ synthesized.add(((DexValueType) element).value);
+ }
+ return synthesized;
+ }
+ return Collections.emptyList();
+ }
+
+ public static DexAnnotation createAnnotationSynthesizedClassMap(
+ Set<DexType> synthesized,
+ DexItemFactory dexItemFactory) {
+ DexValueType[] values = synthesized.stream()
+ .map(type -> new DexValueType(type))
+ .toArray(length -> new DexValueType[length]);
+ DexValueArray array = new DexValueArray(values);
+ DexAnnotationElement pair =
+ new DexAnnotationElement(dexItemFactory.createString("value"), array);
+ return new DexAnnotation(
+ VISIBILITY_BUILD,
+ new DexEncodedAnnotation(
+ dexItemFactory.annotationSynthesizedClassMap, new DexAnnotationElement[]{pair}));
+ }
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
index 00b99fa..93e103d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
@@ -74,8 +74,44 @@
return null;
}
+ public DexAnnotationSet getWithout(DexType annotationType) {
+ int index = 0;
+ for (DexAnnotation annotation : annotations) {
+ if (annotation.annotation.type == annotationType) {
+ DexAnnotation[] reducedArray = new DexAnnotation[annotations.length - 1];
+ System.arraycopy(annotations, 0, reducedArray, 0, index);
+ if (index < reducedArray.length) {
+ System.arraycopy(annotations, index + 1, reducedArray, index, reducedArray.length - index);
+ }
+ return new DexAnnotationSet(reducedArray);
+ }
+ ++index;
+ }
+ return this;
+ }
+
private int sortedHashCode() {
int hashCode = hashCode();
return hashCode == UNSORTED ? 1 : hashCode;
}
+
+ public DexAnnotationSet getWithAddedOrReplaced(DexAnnotation newAnnotation) {
+
+ // Check existing annotation for replacement.
+ int index = 0;
+ for (DexAnnotation annotation : annotations) {
+ if (annotation.annotation.type == newAnnotation.annotation.type) {
+ DexAnnotation[] modifiedArray = annotations.clone();
+ modifiedArray[index] = newAnnotation;
+ return new DexAnnotationSet(modifiedArray);
+ }
+ ++index;
+ }
+
+ // No existing annotation, append.
+ DexAnnotation[] extendedArray = new DexAnnotation[annotations.length + 1];
+ System.arraycopy(annotations, 0, extendedArray, 0, annotations.length);
+ extendedArray[annotations.length] = newAnnotation;
+ return new DexAnnotationSet(extendedArray);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java
index 0d2edcb..294b031 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -315,6 +315,7 @@
DexString highestSortingString;
private byte[] deadCode;
private final Set<DexType> mainDexList = Sets.newIdentityHashSet();
+ private final Collection<DexProgramClass> synthesizedClasses;
public Builder(DexItemFactory dexItemFactory, Timing timing) {
this.programClasses = new ArrayList<>();
@@ -323,6 +324,7 @@
this.deadCode = null;
this.classpathClasses = null;
this.libraryClasses = null;
+ this.synthesizedClasses = new ArrayList<>();
}
public Builder(DexApplication application) {
@@ -335,6 +337,7 @@
dexItemFactory = application.dexItemFactory;
mainDexList.addAll(application.mainDexList);
deadCode = application.deadCode;
+ synthesizedClasses = new ArrayList<>();
}
public synchronized Builder setProguardMap(ClassNameMapper proguardMap) {
@@ -387,6 +390,7 @@
DexProgramClass synthesizedClass, boolean addToMainDexList) {
assert synthesizedClass.isProgramClass() : "All synthesized classes must be program classes";
addProgramClass(synthesizedClass);
+ synthesizedClasses.add(synthesizedClass);
if (addToMainDexList && !mainDexList.isEmpty()) {
mainDexList.add(synthesizedClass.type);
}
@@ -397,6 +401,14 @@
return programClasses;
}
+ public Collection<DexProgramClass> getSynthesizedClasses() {
+ return synthesizedClasses;
+ }
+
+ public Set<DexType> getMainDexList() {
+ return mainDexList;
+ }
+
public Builder addToMainDexList(Collection<DexType> mainDexList) {
this.mainDexList.addAll(mainDexList);
return this;
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 527f27b..b7e41fe 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -161,6 +161,8 @@
public final DexType annotationSourceDebugExtension = createType(
"Ldalvik/annotation/SourceDebugExtension;");
public final DexType annotationThrows = createType("Ldalvik/annotation/Throws;");
+ public final DexType annotationSynthesizedClassMap =
+ createType("Lcom/android/tools/r8/annotations/SynthesizedClassMap;");
public synchronized void clearSubtypeInformation() {
types.values().forEach(DexType::clearSubtypeInformation);
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index d27a3be..4332df8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -9,6 +9,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;
@@ -213,6 +214,21 @@
directMethods = newDirectMethods;
}
+ public synchronized void sortMembers() {
+ sortEncodedFields(staticFields);
+ sortEncodedFields(instanceFields);
+ sortEncodedMethods(directMethods);
+ sortEncodedMethods(virtualMethods);
+ }
+
+ private void sortEncodedFields(DexEncodedField[] fields) {
+ Arrays.sort(fields, Comparator.comparing(a -> a.field));
+ }
+
+ private void sortEncodedMethods(DexEncodedMethod[] methods) {
+ Arrays.sort(methods, Comparator.comparing(a -> a.method));
+ }
+
@Override
public DexProgramClass get() {
return this;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index c67e229..7dca5bd 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -39,16 +40,22 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.BiConsumer;
+import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
public class IRConverter {
@@ -225,9 +232,72 @@
synthesizeLambdaClasses(builder);
desugarInterfaceMethods(builder, ExcludeDexResources);
+ if (options.intermediate) {
+ updateSynthesizedClassMapping(builder);
+ }
+
+ updateMainDexListWithSynthesizedClassMap(builder);
+
+ if (!options.intermediate) {
+ clearSynthesizedClassMapping(builder);
+ }
+
return builder.build();
}
+ private void updateMainDexListWithSynthesizedClassMap(Builder builder) {
+ Set<DexType> inputMainDexList = builder.getMainDexList();
+ if (!inputMainDexList.isEmpty()) {
+ Map<DexType, DexProgramClass> programClasses = builder.getProgramClasses().stream()
+ .collect(Collectors.toMap(
+ programClass -> programClass.type,
+ Function.identity()));
+ Collection<DexType> synthesized = new ArrayList<>();
+ for (DexType dexType : inputMainDexList) {
+ DexProgramClass programClass = programClasses.get(dexType);
+ if (programClass != null) {
+ synthesized.addAll(DexAnnotation.readAnnotationSynthesizedClassMap(
+ programClass, builder.dexItemFactory));
+ }
+ }
+ builder.addToMainDexList(synthesized);
+ }
+ }
+
+ private void clearSynthesizedClassMapping(Builder builder) {
+ for (DexProgramClass programClass : builder.getProgramClasses()) {
+ programClass.annotations =
+ programClass.annotations.getWithout(builder.dexItemFactory.annotationSynthesizedClassMap);
+ }
+ }
+
+ private void updateSynthesizedClassMapping(Builder builder) {
+ ListMultimap<DexProgramClass, DexProgramClass> originalToSynthesized =
+ ArrayListMultimap.create();
+ for (DexProgramClass synthesized : builder.getSynthesizedClasses()) {
+ for (DexProgramClass original : synthesized.getSynthesizedFrom()) {
+ originalToSynthesized.put(original, synthesized);
+ }
+ }
+
+ for (Map.Entry<DexProgramClass, Collection<DexProgramClass>> entry :
+ originalToSynthesized.asMap().entrySet()) {
+ DexProgramClass original = entry.getKey();
+ Set<DexType> synthesized = new HashSet<>();
+ entry.getValue()
+ .stream()
+ .map(dexProgramClass -> dexProgramClass.type)
+ .forEach(synthesized::add);
+ synthesized.addAll(
+ DexAnnotation.readAnnotationSynthesizedClassMap(original, builder.dexItemFactory));
+
+ DexAnnotation updatedAnnotation =
+ DexAnnotation.createAnnotationSynthesizedClassMap(synthesized, builder.dexItemFactory);
+
+ original.annotations = original.annotations.getWithAddedOrReplaced(updatedAnnotation);
+ }
+ }
+
private void convertClassesToDex(Iterable<DexProgramClass> classes,
ExecutorService executor) throws ExecutionException {
List<Future<?>> futures = new ArrayList<>();
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 31a1724..c03c3d6 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -124,6 +124,8 @@
// the code contains unsupported byte codes.
public boolean skipReadingDexCode = false;
+ public Path printMappingFile = null;
+
public void warningInvalidDebugInfo(DexEncodedMethod method, InvalidDebugInfoException e) {
warningInvalidDebugInfoCount++;
}
diff --git a/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
index 7a56e3c..a2e64e1 100644
--- a/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
@@ -6,14 +6,20 @@
import static com.android.tools.r8.dex.Constants.ANDROID_K_API;
import static com.android.tools.r8.dex.Constants.ANDROID_O_API;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+import static com.android.tools.r8.utils.FileUtils.ZIP_EXTENSION;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.utils.DexInspector;
import com.android.tools.r8.utils.OffOrAuto;
+import com.android.tools.r8.utils.OutputMode;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.function.UnaryOperator;
import org.hamcrest.core.CombinableMatcher;
import org.hamcrest.core.IsInstanceOf;
@@ -66,6 +72,10 @@
}
}
+ D8TestRunner withIntermediate(boolean intermediate) {
+ return withBuilderTransformation(builder -> builder.setIntermediate(intermediate));
+ }
+
@Override
D8TestRunner self() {
return this;
@@ -519,6 +529,133 @@
new Path[] {lib1Dex, lib3Dex, lib4Dex, testDex});
}
+
+ @Test
+ public void testLambdaDesugaringWithMainDexList1() throws Throwable {
+ // Minimal case: there are synthesized classes but not form the main dex class.
+ testIntermediateWithMainDexList(
+ "lambdadesugaring",
+ 1,
+ "lambdadesugaring.LambdaDesugaring$I");
+ }
+
+ @Test
+ public void testLambdaDesugaringWithMainDexList2() throws Throwable {
+ // Main dex class has many lambdas.
+ testIntermediateWithMainDexList("lambdadesugaring",
+ 33,
+ "lambdadesugaring.LambdaDesugaring$Refs$B");
+ }
+
+ @Test
+ public void testInterfaceDesugaringWithMainDexList1() throws Throwable {
+ // Main dex interface has one static method.
+ testIntermediateWithMainDexList(
+ "interfacemethods",
+ Paths.get(ToolHelper.EXAMPLES_ANDROID_N_BUILD_DIR, "interfacemethods" + JAR_EXTENSION),
+ 2,
+ "interfacemethods.I1");
+ }
+
+
+ @Test
+ public void testInterfaceDesugaringWithMainDexList2() throws Throwable {
+ // Main dex interface has one default method.
+ testIntermediateWithMainDexList(
+ "interfacemethods",
+ Paths.get(ToolHelper.EXAMPLES_ANDROID_N_BUILD_DIR, "interfacemethods" + JAR_EXTENSION),
+ 2,
+ "interfacemethods.I2");
+ }
+
+ private void testIntermediateWithMainDexList(
+ String packageName,
+ int expectedMainDexListSize,
+ String... mainDexClasses)
+ throws Throwable {
+ testIntermediateWithMainDexList(
+ packageName,
+ Paths.get(EXAMPLE_DIR, packageName + JAR_EXTENSION),
+ expectedMainDexListSize,
+ mainDexClasses);
+ }
+
+ private void testIntermediateWithMainDexList(
+ String packageName,
+ Path input,
+ int expectedMainDexListSize,
+ String... mainDexClasses)
+ throws Throwable {
+ int minApi = ANDROID_K_API;
+
+ // Full build, will be used as reference.
+ TestRunner<?> full =
+ test(packageName + "full", packageName, "N/A")
+ .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+ .withMinApiLevel(minApi)
+ .withOptionConsumer(option -> option.minimalMainDex = true)
+ .withMainDexClass(mainDexClasses);
+ Path fullDexes = temp.getRoot().toPath().resolve(packageName + "full" + ZIP_EXTENSION);
+ full.build(input, fullDexes);
+
+ // Builds with intermediate in both output mode.
+ Path dexesThroughIndexedIntermediate =
+ buildDexThroughIntermediate(packageName, input, OutputMode.Indexed, minApi, mainDexClasses);
+ Path dexesThroughFilePerInputClassIntermediate =
+ buildDexThroughIntermediate(packageName, input, OutputMode.FilePerInputClass, minApi,
+ mainDexClasses);
+
+ // Collect main dex types.
+ DexInspector fullInspector = getMainDexInspector(fullDexes);
+ DexInspector indexedIntermediateInspector =
+ getMainDexInspector(dexesThroughIndexedIntermediate);
+ DexInspector filePerInputClassIntermediateInspector =
+ getMainDexInspector(dexesThroughFilePerInputClassIntermediate);
+ Collection<String> fullMainClasses = new HashSet<>();
+ fullInspector.forAllClasses(
+ clazz -> fullMainClasses.add(clazz.getFinalDescriptor()));
+ Collection<String> indexedIntermediateMainClasses = new HashSet<>();
+ indexedIntermediateInspector.forAllClasses(
+ clazz -> indexedIntermediateMainClasses.add(clazz.getFinalDescriptor()));
+ Collection<String> filePerInputClassIntermediateMainClasses = new HashSet<>();
+ filePerInputClassIntermediateInspector.forAllClasses(
+ clazz -> filePerInputClassIntermediateMainClasses.add(clazz.getFinalDescriptor()));
+
+ // Check.
+ Assert.assertEquals(expectedMainDexListSize, fullMainClasses.size());
+ Assert.assertEquals(fullMainClasses, indexedIntermediateMainClasses);
+ Assert.assertEquals(fullMainClasses, filePerInputClassIntermediateMainClasses);
+ }
+
+ private Path buildDexThroughIntermediate(
+ String packageName,
+ Path input,
+ OutputMode outputMode,
+ int minApi,
+ String... mainDexClasses)
+ throws Throwable {
+ TestRunner<?> intermediate =
+ test(packageName + "intermediate", packageName, "N/A")
+ .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+ .withMinApiLevel(minApi)
+ .withOptionConsumer(option -> option.outputMode = outputMode)
+ .withIntermediate(true);
+ Path intermediateDex =
+ temp.getRoot().toPath().resolve(packageName + "intermediate" + ZIP_EXTENSION);
+ intermediate.build(input, intermediateDex);
+
+ TestRunner<?> end =
+ test(packageName + "dex", packageName, "N/A")
+ .withOptionConsumer(option -> option.minimalMainDex = true)
+ .withMainDexClass(mainDexClasses)
+ .withMinApiLevel(minApi);
+
+ Path dexesThroughIntermediate =
+ temp.getRoot().toPath().resolve(packageName + "dex" + ZIP_EXTENSION);
+ end.build(intermediateDex, dexesThroughIntermediate);
+ return dexesThroughIntermediate;
+ }
+
@Override
D8TestRunner test(String testName, String packageName, String mainClass) {
return new D8TestRunner(testName, packageName, mainClass);
diff --git a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
index 8b6926e..932a61f 100644
--- a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
+++ b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
@@ -1732,19 +1732,23 @@
// 1) t02
// java.lang.AssertionError: Failed to load serialization resource file: serialization/com/google/jctf/test/lib/java/lang/Byte/serialization/Byte_serialization_A01.golden.0.ser
- .put("lang.Byte.parseByteLjava_lang_StringI.Byte_parseByte_A02", any())
+ .put("lang.Byte.parseByteLjava_lang_StringI.Byte_parseByte_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t01
// java.lang.AssertionError: Parsed Byte instance from string:+1 radix:10
- .put("lang.Byte.valueOfLjava_lang_StringI.Byte_valueOf_A02", any())
+ .put("lang.Byte.valueOfLjava_lang_StringI.Byte_valueOf_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t01
// java.lang.AssertionError: Parsed Byte instance from string:+1 radix:10
- .put("lang.Byte.valueOfLjava_lang_String.Byte_ValueOf_A02", any())
+ .put("lang.Byte.valueOfLjava_lang_String.Byte_ValueOf_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t02
// java.lang.AssertionError: Parsed Byte instance from string:+1
- .put("lang.Byte.decodeLjava_lang_String.Byte_decode_A04", any())
+ .put("lang.Byte.decodeLjava_lang_String.Byte_decode_A04",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t01
// java.lang.AssertionError: Decoded Byte instance from string:+1
@@ -1760,11 +1764,13 @@
// 2) t02
// java.lang.AssertionError: Failed to load serialization resource file: serialization/com/google/jctf/test/lib/java/lang/ClassCastException/serialization/ClassCastException_serialization_A01.golden.0.ser
- .put("lang.Byte.ConstructorLjava_lang_String.Byte_Constructor_A02", any())
+ .put("lang.Byte.ConstructorLjava_lang_String.Byte_Constructor_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t02
// java.lang.AssertionError: Parsed Byte instance from string:+1
- .put("lang.Byte.parseByteLjava_lang_String.Byte_parseByte_A02", any())
+ .put("lang.Byte.parseByteLjava_lang_String.Byte_parseByte_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t02
// java.lang.AssertionError: Parsed Byte instance from string:+1
@@ -1833,7 +1839,8 @@
// 1) t02
// java.lang.AssertionError: Failed to load serialization resource file: serialization/com/google/jctf/test/lib/java/lang/Boolean/serialization/Boolean_serialization_A01.golden.0.ser
- .put("lang.Integer.valueOfLjava_lang_StringI.Integer_valueOf_A02", any())
+ .put("lang.Integer.valueOfLjava_lang_StringI.Integer_valueOf_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t07
// java.lang.AssertionError: NumberFormatException expected for input: +1 and radix: 10
@@ -1841,40 +1848,48 @@
// 1) t02
// java.lang.AssertionError: Failed to load serialization resource file: serialization/com/google/jctf/test/lib/java/lang/Integer/serialization/Integer_serialization_A01.golden.0.ser
- .put("lang.Integer.parseIntLjava_lang_String.Integer_parseInt_A02", any())
+ .put("lang.Integer.parseIntLjava_lang_String.Integer_parseInt_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t06
// java.lang.AssertionError: Expected exception: java.lang.NumberFormatException
- .put("lang.Integer.getIntegerLjava_lang_StringI.Integer_getInteger_A02", any())
+ .put("lang.Integer.getIntegerLjava_lang_StringI.Integer_getInteger_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t03
// java.lang.AssertionError: expected:<6031769> but was:<1>
- .put("lang.Integer.valueOfLjava_lang_String.Integer_valueOf_A02", any())
+ .put("lang.Integer.valueOfLjava_lang_String.Integer_valueOf_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t07
// java.lang.AssertionError: NumberFormatException expected for input: +1
- .put("lang.Integer.decodeLjava_lang_String.Integer_decode_A04", any())
+ .put("lang.Integer.decodeLjava_lang_String.Integer_decode_A04",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t06
// java.lang.AssertionError: Expected exception: java.lang.NumberFormatException
- .put("lang.Integer.parseIntLjava_lang_StringI.Integer_parseInt_A02", any())
+ .put("lang.Integer.parseIntLjava_lang_StringI.Integer_parseInt_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t06
// java.lang.AssertionError: Expected exception: java.lang.NumberFormatException
.put("lang.Integer.getIntegerLjava_lang_StringLjava_lang_Integer.Integer_getInteger_A02",
- any())
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t03
// java.lang.AssertionError: expected:<6031769> but was:<1>
- .put("lang.Integer.ConstructorLjava_lang_String.Integer_Constructor_A02", any())
+ .put("lang.Integer.ConstructorLjava_lang_String.Integer_Constructor_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t06
// java.lang.AssertionError: Expected exception: java.lang.NumberFormatException
- .put("lang.Integer.getIntegerLjava_lang_String.Integer_getInteger_A02", any())
+ .put("lang.Integer.getIntegerLjava_lang_String.Integer_getInteger_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t03
// java.lang.AssertionError: expected null, but was:<1>
- .put("lang.ref.PhantomReference.isEnqueued.PhantomReference_isEnqueued_A01", any())
+ .put("lang.ref.PhantomReference.isEnqueued.PhantomReference_isEnqueued_A01",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t04
// java.lang.AssertionError: reference is not enqueued after 2 sec
@@ -1898,7 +1913,8 @@
// 1) t03
// java.lang.AssertionError: expected null, but was:<[I@1b32f32>
- .put("lang.ref.WeakReference.isEnqueued.WeakReference_isEnqueued_A01", any())
+ .put("lang.ref.WeakReference.isEnqueued.WeakReference_isEnqueued_A01",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t03
// java.lang.AssertionError: reference is not enqueued after 2 sec
@@ -2003,11 +2019,13 @@
// 2) t04
// org.junit.ComparisonFailure: expected:<0.001[0]> but was:<0.001[]>
- .put("lang.Short.valueOfLjava_lang_StringI.Short_valueOf_A02", any())
+ .put("lang.Short.valueOfLjava_lang_StringI.Short_valueOf_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t03
// java.lang.AssertionError: Missing NumberFormatException for radix=10
- .put("lang.Short.valueOfLjava_lang_String.Short_valueOf_A02", any())
+ .put("lang.Short.valueOfLjava_lang_String.Short_valueOf_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t03
// java.lang.AssertionError: Missing NumberFormatException for arg="+1"
@@ -2015,15 +2033,18 @@
// 1) t02
// java.lang.AssertionError: Failed to load serialization resource file: serialization/com/google/jctf/test/lib/java/lang/Short/serialization/Short_serialization_A01.golden.0.ser
- .put("lang.Short.parseShortLjava_lang_String.Short_parseShort_A02", any())
+ .put("lang.Short.parseShortLjava_lang_String.Short_parseShort_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t01
// java.lang.AssertionError: Parsed Short instance from string:+1
- .put("lang.Short.decodeLjava_lang_String.Short_decode_A04", any())
+ .put("lang.Short.decodeLjava_lang_String.Short_decode_A04",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t01
// java.lang.AssertionError: Decoded Short instance from string:+1
- .put("lang.Short.ConstructorLjava_lang_String.Short_Constructor_A02", any())
+ .put("lang.Short.ConstructorLjava_lang_String.Short_Constructor_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t02
// java.lang.AssertionError: Created Short instance from string:+1
@@ -2042,7 +2063,8 @@
// 2) t02
// java.lang.AssertionError: Failed to load serialization resource file: serialization/com/google/jctf/test/lib/java/lang/annotation/AnnotationFormatError/serialization/AnnotationFormatError_serialization_A01.golden.0.ser
- .put("lang.Short.parseShortLjava_lang_StringI.Short_parseShort_A02", any())
+ .put("lang.Short.parseShortLjava_lang_StringI.Short_parseShort_A02",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t01
// java.lang.AssertionError: Parsed Short instance from string:+1 radix:10
@@ -2261,7 +2283,8 @@
// 1) t04
// java.lang.AssertionError: expected null, but was:<class com.google.jctf.test.lib.java.lang.Class.getDeclaringClass.Class_getDeclaringClass_A01>
- .put("lang.Class.getDeclaredFields.Class_getDeclaredFields_A01", any())
+ .put("lang.Class.getDeclaredFields.Class_getDeclaredFields_A01",
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t02
// java.lang.AssertionError: array lengths differed, expected.length=0 actual.length=2
@@ -2372,7 +2395,7 @@
// java.lang.AssertionError: Vague error message
.put("lang.Class.getClasses.Class_getClasses_A01",
- match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0)))
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_4_4_4)))
// 1) t03
// java.lang.AssertionError: Array lengths expected:<2> but was:<3>
@@ -2548,7 +2571,7 @@
// Caused by: java.lang.AssertionError: Unable to configure default providers
.put("lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A01",
- match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0)))
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_4_4_4)))
// 1) t04
// java.lang.AssertionError: expected:<interface com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A01$I1> but was:<interface com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String$Ljava_lang_Class.Class_getMethod_A01$I2>
@@ -2676,7 +2699,7 @@
// java.lang.AssertionError: Failed to load serialization resource file: serialization/com/google/jctf/test/lib/java/lang/String/CASE_INSENSITIVE_ORDER/serialization/String_serialization_A01.golden.0.ser
.put("lang.String.getBytesLjava_lang_String.String_getBytes_A14",
- match(runtimes(DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t07
// arrays first differed at element [0]; expected:<-2> but was:<-1>
// Caused by: java.lang.AssertionError: expected:<-2> but was:<-1>
@@ -2737,7 +2760,7 @@
// org.junit.ComparisonFailure: Incorrect double string returned expected:<0.001[0]> but was:<0.001[]>
.put("lang.String.getBytesLjava_nio_charset_Charset.String_getBytes_A14",
- match(runtimes(DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t07
// arrays first differed at element [0]; expected:<-2> but was:<-1>
// Caused by: java.lang.AssertionError: expected:<-2> but was:<-1>
@@ -3600,7 +3623,7 @@
.put(
"lang.reflect.Proxy.getInvocationHandlerLjava_lang_Object.Proxy_getInvocationHandler_A02",
- any())
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t02
// java.lang.Exception: Unexpected exception, expected<java.lang.IllegalArgumentException> but was<java.lang.NullPointerException>
// Caused by: java.lang.NullPointerException
@@ -3611,6 +3634,16 @@
// 2) t05
// java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference
+ .put("lang.reflect.Proxy.Class.Proxy_class_A02", match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t02
+ // java.lang.AssertionError: expected array was null
+ // 2) t04
+ // java.lang.AssertionError: expected array was null
+
+ .put("lang.reflect.Proxy.Class.Proxy_class_A03", match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t03
+ // java.lang.AbstractMethodError: abstract method not implemented
+
.put(
"lang.reflect.Proxy.getProxyClassLjava_lang_ClassLoader_Ljava_lang_Class.Proxy_getProxyClass_A01",
any())
@@ -3775,6 +3808,12 @@
// Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.reflect.Method.MissingParameterTypeMethod" on path: DexPathList[[dex file "/tmp/junit3534060116722105133/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]]
.put(
+ "lang.reflect.InvocationHandler.invokeLjava_lang_ObjectLjava_lang_reflect_Method_Ljava_lang_Object.InvocationHandler_invoke_A01",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t04
+ // java.lang.AssertionError: expected array was null
+
+ .put(
"lang.reflect.InvocationHandler.invokeLjava_lang_ObjectLjava_lang_reflect_Method_Ljava_lang_Object.InvocationHandler_invoke_A02",
any())
// 1) t04
@@ -3784,6 +3823,11 @@
// 1) t01
// java.lang.AssertionError: Expected exception: java.lang.TypeNotPresentException
+ .put("lang.reflect.Method.hashCode.Method_hashCode_A01",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // 1)
+ // java.lang.AssertionError: expected:<-1918826964> but was:<-1295482945>
+
.put("lang.reflect.Method.toString.Method_toString_A01", any())
// 1) t04
// org.junit.ComparisonFailure: expected:<public static final [synchronized ]native void com.goog...> but was:<public static final []native void com.goog...>
@@ -3838,10 +3882,20 @@
// 1) t02
// java.lang.AssertionError: Exception is not thrown: field: bytePublicField, object: com.google.jctf.test.lib.java.lang.reflect.Field.TestStaticFinalPrimitiveField@b1b0f3d
+ .put("lang.reflect.Field.setByteLjava_lang_ObjectB.Field_setByte_A02",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t01
+ // java.lang.AssertionError: Illegal exception is thrown: java.lang.IllegalAccessException: field is marked 'final', field: bytePublicField, class: class com.google.jctf.test.lib.java.lang.reflect.Field.TestFinalPrimitiveField
+
.put("lang.reflect.Field.setBooleanLjava_lang_ObjectZ.Field_setBoolean_A01", any())
// 1) t02
// java.lang.AssertionError: Exception is not thrown: field: booleanPublicField, object: com.google.jctf.test.lib.java.lang.reflect.Field.TestStaticFinalPrimitiveField@953cc4f
+ .put("lang.reflect.Field.setBooleanLjava_lang_ObjectZ.Field_setBoolean_A02",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t01
+ // java.lang.AssertionError: Illegal exception is thrown: java.lang.IllegalAccessException: field is marked 'final', field: booleanPublicField, class: class com.google.jctf.test.lib.java.lang.reflect.Field.TestFinalPrimitiveField
+
.put("lang.reflect.Field.setCharLjava_lang_ObjectC.Field_setChar_A05", any())
// 1) t01
// java.lang.Exception: Unexpected exception, expected<java.lang.ExceptionInInitializerError> but was<java.lang.NullPointerException>
@@ -3869,6 +3923,11 @@
// 1) t02
// java.lang.AssertionError: Exception is not thrown: field: charPublicField, object: com.google.jctf.test.lib.java.lang.reflect.Field.TestStaticFinalPrimitiveField@95271f1
+ .put("lang.reflect.Field.setCharLjava_lang_ObjectC.Field_setChar_A02",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t01
+ // java.lang.AssertionError: Illegal exception is thrown: java.lang.IllegalAccessException: field is marked 'final', field: charPublicField, class: class com.google.jctf.test.lib.java.lang.reflect.Field.TestFinalPrimitiveField
+
.put("lang.reflect.Field.getDoubleLjava_lang_Object.Field_getDouble_A05", any())
// 1) t01
// java.lang.Exception: Unexpected exception, expected<java.lang.ExceptionInInitializerError> but was<java.lang.NullPointerException>
@@ -3880,12 +3939,22 @@
// 1) t02
// java.lang.AssertionError: Exception is not thrown: field: floatPublicField, object: com.google.jctf.test.lib.java.lang.reflect.Field.TestStaticFinalPrimitiveField@3fca927
+ .put("lang.reflect.Field.setFloatLjava_lang_ObjectF.Field_setFloat_A02",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t01
+ // java.lang.AssertionError: Illegal exception is thrown: java.lang.IllegalAccessException: field is marked 'final', field: floatPublicField, class: class com.google.jctf.test.lib.java.lang.reflect.Field.TestFinalPrimitiveField
+
.put("lang.reflect.Field.getAnnotationLjava_lang_Class.Field_getAnnotation_A01", any())
// 1) t02
// java.lang.AssertionError: Misconfiguration: MissingAntn should not be accessible
// 2) t03
// java.lang.AssertionError: Misconfiguration: MissingAntn should not be accessible
+ .put("lang.reflect.Field.setIntLjava_lang_ObjectI.Field_setInt_A02",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t01
+ // java.lang.AssertionError: Illegal exception is thrown: java.lang.IllegalAccessException: field is marked 'final', field: intPublicField, class: class com.google.jctf.test.lib.java.lang.reflect.Field.TestFinalPrimitiveField
+
.put("lang.reflect.Field.getIntLjava_lang_Object.Field_getInt_A05", any())
// 1) t01
// java.lang.Exception: Unexpected exception, expected<java.lang.ExceptionInInitializerError> but was<java.lang.NullPointerException>
@@ -3950,6 +4019,11 @@
// 1) t02
// java.lang.AssertionError: Exception is not thrown: field: intPublicField, object: com.google.jctf.test.lib.java.lang.reflect.Field.TestStaticFinalPrimitiveField@94fbd35
+ .put("lang.reflect.Field.setDoubleLjava_lang_ObjectD.Field_setDouble_A02",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t01
+ // java.lang.AssertionError: Illegal exception is thrown: java.lang.IllegalAccessException: field is marked 'final', field: doublePublicField, class: class com.google.jctf.test.lib.java.lang.reflect.Field.TestFinalPrimitiveField
+
.put("lang.reflect.Field.setDoubleLjava_lang_ObjectD.Field_setDouble_A05", any())
// 1) t01
// java.lang.Exception: Unexpected exception, expected<java.lang.ExceptionInInitializerError> but was<java.lang.NullPointerException>
@@ -3961,6 +4035,11 @@
// 1) t02
// java.lang.AssertionError: Exception is not thrown: field: shortPublicField, object: com.google.jctf.test.lib.java.lang.reflect.Field.TestStaticFinalPrimitiveField@7887a47
+ .put("lang.reflect.Field.setLongLjava_lang_ObjectJ.Field_setLong_A02",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t01
+ // java.lang.AssertionError: Illegal exception is thrown: java.lang.IllegalAccessException: field is marked 'final', field: longPublicField, class: class com.google.jctf.test.lib.java.lang.reflect.Field.TestFinalPrimitiveField
+
.put("lang.reflect.Field.setLongLjava_lang_ObjectJ.Field_setLong_A05", any())
// 1) t01
// java.lang.Exception: Unexpected exception, expected<java.lang.ExceptionInInitializerError> but was<java.lang.NullPointerException>
@@ -3976,6 +4055,11 @@
// 1) t02
// java.lang.AssertionError: Exception is not thrown: field: doublePublicField, object: com.google.jctf.test.lib.java.lang.reflect.Field.TestStaticFinalPrimitiveField@4dd95e2
+ .put("lang.reflect.Field.setShortLjava_lang_ObjectS.Field_setShort_A02",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t01
+ // java.lang.AssertionError: Illegal exception is thrown: java.lang.IllegalAccessException: field is marked 'final', field: shortPublicField, class: class com.google.jctf.test.lib.java.lang.reflect.Field.TestFinalPrimitiveField
+
.put("lang.reflect.Field.setShortLjava_lang_ObjectS.Field_setShort_A05", any())
// 1) t01
// java.lang.Exception: Unexpected exception, expected<java.lang.ExceptionInInitializerError> but was<java.lang.NullPointerException>
@@ -3997,6 +4081,11 @@
// 2) t02
// java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference
+ .put("lang.reflect.Field.setLjava_lang_ObjectLjava_lang_Object.Field_set_A02",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t01
+ // java.lang.AssertionError: Illegal exception is thrown: java.lang.IllegalAccessException: field is marked 'final', field: bytePublicField, class: class com.google.jctf.test.lib.java.lang.reflect.Field.TestFinalPrimitiveField
+
.put("lang.reflect.Field.setLjava_lang_ObjectLjava_lang_Object.Field_set_A05", any())
// 1) t01
// java.lang.Exception: Unexpected exception, expected<java.lang.ExceptionInInitializerError> but was<java.lang.NullPointerException>
@@ -4365,7 +4454,7 @@
.put(
"util.concurrent.ConcurrentHashMap.serialization.ConcurrentHashMap_serialization_A01",
- any())
+ match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
// 1) t01
// java.lang.AssertionError: Unable to configure default providers
@@ -4438,57 +4527,57 @@
// java.lang.AssertionError: no IllegalThreadStateException 1
.put("lang.String.getBytesLjava_lang_String.String_getBytes_A02",
- match(runtimes(DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01(com.google.jctf.test.lib.java.lang.String.getBytesLjava_lang_String.String_getBytes_A02)
// java.lang.Exception: Unexpected exception, expected<java.lang.NullPointerException> but was<java.io.UnsupportedEncodingException>
.put(
"util.concurrent.CopyOnWriteArrayList.lastIndexOfLjava_lang_ObjectI.CopyOnWriteArrayList_lastIndexOf_A02",
- match(runtimes(DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// java.lang.AssertionError: Expected exception: java.lang.IndexOutOfBoundsException
.put(
"util.concurrent.CopyOnWriteArrayList.lastIndexOfLjava_lang_ObjectI.CopyOnWriteArrayList_lastIndexOf_A01",
- match(runtimes(DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01(com.google.jctf.test.lib.java.util.concurrent.CopyOnWriteArrayList.lastIndexOfLjava_lang_ObjectI.CopyOnWriteArrayList_lastIndexOf_A01)
// java.lang.AssertionError: expected:<3> but was:<1>
// 2) t02(com.google.jctf.test.lib.java.util.concurrent.CopyOnWriteArrayList.lastIndexOfLjava_lang_ObjectI.CopyOnWriteArrayList_lastIndexOf_A01)
// java.lang.ArrayIndexOutOfBoundsException: length=3; index=2147483647
.put("lang.StringBuffer.getCharsII_CI.StringBuffer_getChars_A03",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t03
// java.lang.NullPointerException: dst == null
.put("lang.StringBuffer.appendF.StringBuffer_append_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t02
// java.lang.AssertionError: Buffer is invalid length after append expected:<26> but was:<25>
.put("lang.StringBuffer.insertI_CII.StringBuffer_insert_A02",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.NullPointerException: Attempt to get length of null array
.put("lang.StrictMath.scalbDI.StrictMath_scalb_A03",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.AssertionError: Wrong result provided for argument: -1.7976931348623157E308 scaleFactor: 2147483647 expected:<-Infinity> but was:<-0.0>
.put("lang.StrictMath.scalbDI.StrictMath_scalb_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t03
// java.lang.AssertionError: Wrong result provided for argument: -2.2250738585072014E-308 scaleFactor: -2147483647 expected:<-0.0> but was:<-Infinity>
// 2) t04
// java.lang.AssertionError: Wrong result provided for argument: 1.7976931348623157E308 scaleFactor: -2046 expected:<2.2250738585072014E-308> but was:<2.225073858507201E-308>
.put("lang.StrictMath.scalbFI.StrictMath_scalb_A03",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.AssertionError: Wrong result provided for argument: -3.4028235E38 scaleFactor: 2147483647 expected:<-Infinity> but was:<-0.0>
.put("lang.StrictMath.scalbFI.StrictMath_scalb_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t02
// java.lang.AssertionError: Wrong result provided for argument: 3.4028235E38 scaleFactor: -254 expected:<1.1754943508222875E-38> but was:<1.1754942106924411E-38>
// 2) t03
@@ -4496,96 +4585,96 @@
.put(
"lang.Thread.ConstructorLjava_lang_ThreadGroupLjava_lang_RunnableLjava_lang_StringJ.Thread_Constructor_A07",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t02
// java.lang.AssertionError: wrong daemonism expected:<true> but was:<false>
.put(
"lang.Thread.ConstructorLjava_lang_ThreadGroupLjava_lang_RunnableLjava_lang_String.Thread_Constructor_A07",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t02
// java.lang.AssertionError: wrong daemonism expected:<true> but was:<false>
.put("lang.Thread.toString.Thread_toString_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t02
// java.lang.AssertionError
.put("lang.Thread.start.Thread_start_A02",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.IllegalThreadStateException: Thread group still contains threads: start
.put("lang.Thread.setPriorityI.Thread_setPriority_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t02
// java.lang.AssertionError: expected:<5> but was:<10>
.put("lang.ClassLoader.ConstructorLjava_lang_ClassLoader.ClassLoader_Constructor_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.NullPointerException: parentLoader == null && !nullAllowed
// 2) t03
// java.lang.NullPointerException: parentLoader == null && !nullAllowed
.put("lang.Enum.compareToLjava_lang_Enum.Enum_compareTo_A03",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.AssertionError: Expected exception: java.lang.ClassCastException
.put("lang.Enum.hashCode.Enum_hashCode_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t02
// java.lang.AssertionError
.put("lang.StackTraceElement.hashCode.StackTraceElement_hashCode_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t02
// java.lang.AssertionError
.put("lang.ProcessBuilder.environment.ProcessBuilder_environment_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.AssertionError: should throw ClassCastException.
.put("lang.ProcessBuilder.environment.ProcessBuilder_environment_A03",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.AssertionError: should throw ClassCastException.
.put("lang.Float.toStringF.Float_toString_A04",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t02
// org.junit.ComparisonFailure: Invalid string produced for bits: 4efffffa expected:<2.147482[88]E9> but was:<2.147482[9]E9>
.put("lang.Float.toStringF.Float_toString_A03",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t02
// org.junit.ComparisonFailure: expected:<-1.175494[35]E-38> but was:<-1.175494[4]E-38>
.put("lang.ThreadGroup.getMaxPriority.ThreadGroup_getMaxPriority_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.AssertionError: New value should be the same as we set expected:<2> but was:<1>
.put(
"lang.ThreadGroup.uncaughtExceptionLjava_lang_ThreadLjava_lang_Throwable.ThreadGroup_uncaughtException_A02",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t05
// java.lang.AssertionError: Non-informative exception info: java.lang.RuntimeException
.put("lang.ThreadGroup.list.ThreadGroup_list_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t04
// java.lang.IllegalThreadStateException: Thread group still contains threads: Test group(list)
.put("lang.ThreadGroup.setMaxPriorityI.ThreadGroup_setMaxPriority_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.IllegalThreadStateException: Thread group still contains threads: Test root(setMaxPriority)
.put("lang.ThreadGroup.setMaxPriorityI.ThreadGroup_setMaxPriority_A04",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.AssertionError: New value should be the same as we set expected:<2> but was:<1>
// 2) t02
@@ -4594,40 +4683,46 @@
// java.lang.AssertionError: expected:<7> but was:<1>
.put("lang.ThreadGroup.toString.ThreadGroup_toString_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// org.junit.ComparisonFailure: toString does not follow the RI expected:<... group(toString),max[pri]=10]> but was:<... group(toString),max[Priority]=10]>
.put("lang.Class.getFieldLjava_lang_String.Class_getField_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t04
// java.lang.AssertionError: expected:<interface com.google.jctf.test.lib.java.lang.Class.getFieldLjava_lang_String.Class_getField_A01$I1> but was:<class com.google.jctf.test.lib.java.lang.Class.getFieldLjava_lang_String.Class_getField_A01$S1>
.put("lang.String.replaceCC.String_replace_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t04
// java.lang.AssertionError: expected same:<aaaaaa> was not:<aaaaaa>
.put("lang.Package.isCompatibleWithLjava_lang_String.Package_isCompatibleWith_A02",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.AssertionError: NumberFormatException isn't thrown for desired . and current 1.0
// 2) t03
// java.lang.AssertionError: NumberFormatException isn't thrown for desired 1.0 and current .
.put("lang.StringBuilder.appendF.StringBuilder_append_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.AssertionError: Invalid length of created builder expected:<14> but was:<13>
.put("lang.StringBuilder.insertIF.StringBuilder_insert_A01",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.AssertionError: Invalid length of created builder expected:<14> but was:<13>
.put(
+ "lang.reflect.AccessibleObject.setAccessibleZ.AccessibleObject_setAccessible_A04",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // 1) t01
+ // java.lang.AssertionError: SecurityException expected.
+
+ .put(
"lang.reflect.AccessibleObject.setAccessible_Ljava_lang_reflect_AccessibleObjectZ.AccessibleObject_setAccessible_A04",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.AssertionError: SecurityException expected.
// 2) t02
@@ -4638,12 +4733,12 @@
// java.lang.AssertionError: SecurityException expected.
.put("lang.Character.UnicodeBlock.forName_java_lang_String.UnicodeBlock_forName_A03",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t01
// java.lang.AssertionError: Expected exception: java.lang.IllegalArgumentException
.put("lang.System.loadLjava_lang_String.System_load_A02",
- match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t03
// java.lang.AssertionError: Expected exception: java.lang.UnsatisfiedLinkError
@@ -4654,7 +4749,7 @@
// 2) t02
// java.lang.AssertionError: Wrong value returned for start: -0.0 direction: NaN expected:<-1.4E-45> but was:<NaN>
- .put("lang.Math.hypotDD.Math_hypot_A04", match(runtimes(DexVm.ART_5_1_1)))
+ .put("lang.Math.hypotDD.Math_hypot_A04", match(runtimes(DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t04
// java.lang.AssertionError
@@ -4698,6 +4793,12 @@
// 1) t02
// java.lang.AssertionError: java.lang.AssertionError: expected:<7> but was:<6>
+ .put("lang.ref.PhantomReference.isEnqueued.PhantomReference_isEnqueued_A01",
+ match(runtimes(DexVm.ART_4_4_4)))
+ .put("lang.ref.WeakReference.isEnqueued.WeakReference_isEnqueued_A01",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // Passes or fails randomly. Check that something is enqueued after 2 seconds.
+
.build(); // end of flakyWithArt
public static final Multimap<String, TestCondition> timeoutsWithArt =
diff --git a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
index 57bc26c..2de3624 100644
--- a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.shaking.ProguardRuleParserException;
+import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.io.File;
@@ -78,40 +79,48 @@
@Parameters(name = "{0}")
public static Collection<String[]> data() {
return Arrays.asList(new String[][]{
- {"arithmetic", "-1\n3\n2\n3\n3.0\n1\n0\n-131580\n-131580\n2\n4\n-2\n"},
- {"controlflow", "2\n1\n2\n1\n2\n1\n2\n1\n2\n1\n2\n1\n2\n"},
- {"fibonacci", "55\n55\n55\n55\n"},
+ {"arithmetic",
+ StringUtils.lines("-1", "3", "2", "3", "3.0", "1", "0", "-131580", "-131580", "2", "4",
+ "-2")},
+ {"controlflow",
+ StringUtils.lines("2", "1", "2", "1", "2", "1", "2", "1", "2", "1", "2", "1", "2")},
+ {"fibonacci", StringUtils.lines("55", "55", "55", "55")},
{"fill-array-data", "[1, 2, 3][4, 5, 6]"},
{"filled-new-array", "[1, 2, 3][4, 5, 6][1, 2, 3, 4, 5, 6][6, 5, 4, 3, 2, 1]"},
{"packed-switch", "12345"},
{"sparse-switch", "12345"},
{"unreachable-code-1", "777"},
- {"multiple-returns", "TFtf\n1\n4611686018427387904\ntrue\nfalse\n"},
+ {"multiple-returns",
+ StringUtils.lines("TFtf", "1", "4611686018427387904", "true", "false")},
{"try-catch", ""},
- {"phi-removal-regression", "returnBoolean\n"},
- {"overlapping-long-registers", "-9151314442816847872\n-9151314442816319488\n"},
- {"type-confusion-regression", "java.lang.RuntimeException: Test.<init>()\n"},
+ {"phi-removal-regression", StringUtils.lines("returnBoolean")},
+ {"overlapping-long-registers",
+ StringUtils.lines("-9151314442816847872", "-9151314442816319488")},
+ {"type-confusion-regression",
+ StringUtils.lines("java.lang.RuntimeException: Test.<init>()")},
{"type-confusion-regression2",
- "java.lang.NullPointerException: Attempt to read from null array\n"},
+ StringUtils.lines("java.lang.NullPointerException: Attempt to read from null array")},
{"type-confusion-regression3",
- "java.lang.NullPointerException: Attempt to read from field 'byte[] Test.a'" +
- " on a null object reference\n"},
+ StringUtils.lines(
+ "java.lang.NullPointerException: Attempt to read from field 'byte[] Test.a'" +
+ " on a null object reference")},
{"type-confusion-regression4", ""},
- {"type-confusion-regression5", "java.lang.RuntimeException: getId()I\n"},
- {"chain-of-loops", "java.lang.RuntimeException: f(II)\n"},
- {"new-instance-and-init", "Test(0)\nTest(0)\nTest(0)\n"},
+ {"type-confusion-regression5", StringUtils.lines("java.lang.RuntimeException: getId()I")},
+ {"chain-of-loops", StringUtils.lines("java.lang.RuntimeException: f(II)")},
+ {"new-instance-and-init", StringUtils.lines("Test(0)", "Test(0)", "Test(0)")},
{"bad-codegen",
- "java.lang.NullPointerException: Attempt to read from field " +
- "'Test Test.a' on a null object reference\n"},
- {"merge-blocks-regression", "java.lang.NullPointerException: Attempt to invoke virtual"
- + " method 'Test Test.bW_()' on a null object reference\n"},
- {"self-is-catch-block", "100\n-1\n"},
+ StringUtils.lines("java.lang.NullPointerException: Attempt to read from field " +
+ "'Test Test.a' on a null object reference")},
+ {"merge-blocks-regression",
+ StringUtils.lines("java.lang.NullPointerException: Attempt to invoke virtual"
+ + " method 'Test Test.bW_()' on a null object reference")},
+ {"self-is-catch-block", StringUtils.lines("100", "-1")},
{"infinite-loop", ""},
{"regression/33336471",
- "START\n0\n2\nLOOP\n1\n2\nLOOP\n2\n2\nDONE\n" +
- "START\n0\n2\nLOOP\n1\n2\nLOOP\n2\n2\nDONE\n"},
+ StringUtils.lines("START", "0", "2", "LOOP", "1", "2", "LOOP", "2", "2", "DONE",
+ "START", "0", "2", "LOOP", "1", "2", "LOOP", "2", "2", "DONE")},
{"regression/33846227", ""},
- {"illegal-invokes", "ICCE\nICCE\n"},
+ {"illegal-invokes", StringUtils.lines("ICCE", "ICCE")},
});
}
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
index 7a0e793..0e0fd9d 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
@@ -12,17 +12,20 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.DexInspector;
import com.android.tools.r8.utils.DexInspector.FoundClassSubject;
import com.android.tools.r8.utils.DexInspector.FoundMethodSubject;
import com.android.tools.r8.utils.DexInspector.InstructionSubject;
import com.android.tools.r8.utils.DexInspector.InvokeInstructionSubject;
+import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OffOrAuto;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.io.ByteStreams;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
@@ -30,10 +33,13 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
@@ -94,6 +100,10 @@
return self();
}
+ C withMainDexClass(String... classes) {
+ return withBuilderTransformation(builder -> builder.addMainDexClasses(classes));
+ }
+
C withInterfaceMethodDesugaring(OffOrAuto behavior) {
return withOptionConsumer(o -> o.interfaceMethodDesugaring = behavior);
}
@@ -386,8 +396,18 @@
"JVM output does not match art output.\n\tjvm: "
+ javaResult.stdout
+ "\n\tart: "
- + output,
- output.equals(javaResult.stdout));
+ + output.replace("\r", ""),
+ output.equals(javaResult.stdout.replace("\r", "")));
+ }
+ }
+
+ protected DexInspector getMainDexInspector(Path zip)
+ throws ZipException, IOException, ExecutionException {
+ try (ZipFile zipFile = new ZipFile(zip.toFile())) {
+ try (InputStream in =
+ zipFile.getInputStream(zipFile.getEntry(FileUtils.DEFAULT_DEX_FILENAME))) {
+ return new DexInspector(AndroidApp.fromDexProgramData(ByteStreams.toByteArray(in)));
+ }
}
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 2271a02..94d52f0 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -27,6 +27,7 @@
import com.google.common.collect.Lists;
import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -60,6 +61,7 @@
public static final String SMALI_BUILD_DIR = BUILD_DIR + "test/smali/";
public static final String LINE_SEPARATOR = StringUtils.LINE_SEPARATOR;
+ public final static String PATH_SEPARATOR = File.pathSeparator;
private static final String ANDROID_JAR_PATTERN = "third_party/android_jar/lib-v%d/android.jar";
private static final int DEFAULT_MIN_SDK = Constants.ANDROID_I_API;
@@ -601,7 +603,7 @@
public static ProcessResult runJava(List<String> classpath, String mainClass) throws IOException {
ProcessBuilder builder = new ProcessBuilder(
- getJavaExecutable(), "-cp", String.join(":", classpath), mainClass);
+ getJavaExecutable(), "-cp", String.join(PATH_SEPARATOR, classpath), mainClass);
return runProcess(builder);
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/longcompare/LongCompare.java b/src/test/java/com/android/tools/r8/rewrite/longcompare/LongCompare.java
index 5fb3007..d5642f8 100644
--- a/src/test/java/com/android/tools/r8/rewrite/longcompare/LongCompare.java
+++ b/src/test/java/com/android/tools/r8/rewrite/longcompare/LongCompare.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.utils.DexInspector.InstructionSubject;
import com.android.tools.r8.utils.DexInspector.InvokeInstructionSubject;
import com.android.tools.r8.utils.DexInspector.MethodSubject;
+import com.android.tools.r8.utils.StringUtils;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -43,7 +44,9 @@
builder.setMainClass("rewrite.LongCompare");
try {
String output = ToolHelper.runArt(builder);
- Assert.assertEquals("-1\n1\n-1\n0\ntrue\nfalse\nfalse\nfalse\n", output);
+ Assert
+ .assertEquals(StringUtils.lines("-1", "1", "-1", "0", "true", "false", "false", "false"),
+ output);
} catch (IOException e) {
Assert.fail();
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/staticvalues/StaticValuesTest.java b/src/test/java/com/android/tools/r8/rewrite/staticvalues/StaticValuesTest.java
index b8d8e58..9e5a839 100644
--- a/src/test/java/com/android/tools/r8/rewrite/staticvalues/StaticValuesTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/staticvalues/StaticValuesTest.java
@@ -7,6 +7,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.Sput;
import com.android.tools.r8.code.SputObject;
@@ -26,6 +27,7 @@
import com.android.tools.r8.utils.DexInspector;
import com.android.tools.r8.utils.DexInspector.MethodSubject;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringUtils;
import org.junit.Test;
public class StaticValuesTest extends SmaliTestBase {
@@ -146,7 +148,7 @@
String result = runArt(processedApplication, options);
- assertEquals("true\n1\n2\n3\n4\n5.0\n6.0\n7\n8\n", result);
+ assertEquals(StringUtils.lines("true", "1", "2", "3", "4", "5.0", "6.0", "7", "8"), result);
}
@Test
@@ -185,7 +187,7 @@
String result = runArt(processedApplication, options);
- assertEquals("0\n1\n", result);
+ assertEquals(StringUtils.lines("0", "1"), result);
}
@Test
@@ -227,7 +229,7 @@
String result = runArt(processedApplication, options);
- assertEquals("null\nnull\nnull\n", result);
+ assertEquals(StringUtils.lines("null", "null", "null"), result);
}
@Test
@@ -270,7 +272,7 @@
String result = runArt(processedApplication, options);
- assertEquals("Value1\nValue2\nValue2\n", result);
+ assertEquals(StringUtils.lines("Value1", "Value2", "Value2"), result);
}
@Test
@@ -332,7 +334,7 @@
String result = runArt(processedApplication, options);
- assertEquals("3\n7\n", result);
+ assertEquals(StringUtils.lines("3", "7") , result);
}
@@ -416,7 +418,7 @@
String result = runArt(processedApplication, options);
- assertEquals("3\n7\n", result);
+ assertEquals(StringUtils.lines("3", "7"), result);
}
@Test
@@ -484,8 +486,8 @@
String result = runArt(processedApplication, options, className);
- assertEquals(
- "Test\n" + className + "\nTest\n" + className + "\nTest\n" + className + "\n", result);
+ assertEquals(StringUtils.lines("Test", className, "Test", className, "Test", className),
+ result);
}
@Test
@@ -532,7 +534,7 @@
String result = runArt(processedApplication, options, className);
- assertEquals("Test2\norg.example.Test2\n", result);
+ assertEquals(StringUtils.lines("Test2", "org.example.Test2"), result);
}
@Test
@@ -567,7 +569,7 @@
String result = runArt(processedApplication, options);
- assertEquals("2\n", result);
+ assertEquals(StringUtils.lines("2"), result);
}
}
diff --git a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
index a1d8e2a..b285ac0 100644
--- a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.utils.DexInspector.InstructionSubject;
import com.android.tools.r8.utils.DexInspector.MethodSubject;
import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
@@ -493,53 +494,59 @@
}
private static void assumenosideeffects1CheckOutput(String output1, String output2) {
- Assert.assertEquals("noSideEffectVoid\nnoSideEffectInt\n", output1);
+ Assert.assertEquals(StringUtils.lines("noSideEffectVoid", "noSideEffectInt"), output1);
Assert.assertEquals("", output2);
}
private static void assumenosideeffects2CheckOutput(String output1, String output2) {
- Assert.assertEquals("Hello, world!\n", output1);
+ Assert.assertEquals(StringUtils.lines("Hello, world!"), output1);
Assert.assertEquals("", output2);
}
private static void assumenosideeffects3CheckOutput(String output1, String output2) {
- Assert.assertEquals("0\n1\n0L\n1L\n", output1);
- Assert.assertEquals("1\n0\n1L\n0L\n", output2);
+ Assert.assertEquals(StringUtils.lines("0", "1", "0L", "1L"), output1);
+ Assert.assertEquals(StringUtils.lines("1", "0", "1L", "0L"), output2);
}
private static void assumenosideeffects4CheckOutput(String output1, String output2) {
- Assert.assertEquals("method0\n0\nmethod1\n1\nmethod0L\n0L\nmethod1L\n1L\n", output1);
- Assert.assertEquals("1\n0\n1L\n0L\n", output2);
+ Assert.assertEquals(
+ StringUtils.lines("method0", "0", "method1", "1", "method0L", "0L", "method1L", "1L"),
+ output1);
+ Assert.assertEquals(StringUtils.lines("1", "0", "1L", "0L"), output2);
}
private static void assumenosideeffects5CheckOutput(String output1, String output2) {
- Assert.assertEquals("methodTrue\ntrue\nmethodFalse\nfalse\n", output1);
- Assert.assertEquals("false\ntrue\n", output2);
+ Assert.assertEquals(StringUtils.lines("methodTrue", "true", "methodFalse", "false"), output1);
+ Assert.assertEquals(StringUtils.lines("false", "true"), output2);
}
private static void assumevalues1CheckOutput(String output1, String output2) {
- Assert.assertEquals("3\n3L\n", output1);
- Assert.assertEquals("1\n1L\n", output2);
+ Assert.assertEquals(StringUtils.lines("3", "3L"), output1);
+ Assert.assertEquals(StringUtils.lines("1", "1L"), output2);
}
private static void assumevalues2CheckOutput(String output1, String output2) {
- Assert.assertEquals("1\n2\n3\n4\n1L\n2L\n3L\n4L\n", output1);
- Assert.assertEquals("2\n3\n2L\n3L\n", output2);
+ Assert.assertEquals(StringUtils.lines("1", "2", "3", "4", "1L", "2L", "3L", "4L"), output1);
+ Assert.assertEquals(StringUtils.lines("2", "3", "2L", "3L"), output2);
}
private static void assumevalues3CheckOutput(String output1, String output2) {
- Assert.assertEquals("3\n3L\n", output1);
- Assert.assertEquals("1\n1L\n", output2);
+ Assert.assertEquals(StringUtils.lines("3", "3L"), output1);
+ Assert.assertEquals(StringUtils.lines("1", "1L"), output2);
}
private static void assumevalues4CheckOutput(String output1, String output2) {
- Assert.assertEquals("method0\n0\nmethod1\n1\nmethod0L\n0L\nmethod1L\n1L\n", output1);
- Assert.assertEquals("method0\n1\nmethod1\n0\nmethod0L\n1L\nmethod1L\n0L\n", output2);
+ Assert.assertEquals(
+ StringUtils.lines("method0", "0", "method1", "1", "method0L", "0L", "method1L", "1L"),
+ output1);
+ Assert.assertEquals(
+ StringUtils.lines("method0", "1", "method1", "0", "method0L", "1L", "method1L", "0L"),
+ output2);
}
private static void assumevalues5CheckOutput(String output1, String output2) {
- Assert.assertEquals("methodTrue\ntrue\nmethodFalse\nfalse\n", output1);
- Assert.assertEquals("methodTrue\nfalse\nmethodFalse\ntrue\n", output2);
+ Assert.assertEquals(StringUtils.lines("methodTrue", "true", "methodFalse", "false"), output1);
+ Assert.assertEquals(StringUtils.lines("methodTrue", "false", "methodFalse", "true"), output2);
}
private static void annotationRemovalHasAllInnerClassAnnotations(DexInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/smali/JumboStringTest.java b/src/test/java/com/android/tools/r8/smali/JumboStringTest.java
index 56c041c..8d4b841 100644
--- a/src/test/java/com/android/tools/r8/smali/JumboStringTest.java
+++ b/src/test/java/com/android/tools/r8/smali/JumboStringTest.java
@@ -6,6 +6,7 @@
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
@@ -18,20 +19,23 @@
public void test() throws Exception {
StringBuilder builder = new StringBuilder();
StringBuilder expectedBuilder = new StringBuilder();
- builder.append(" new-instance v0, Ljava/lang/StringBuilder;\n");
- builder.append(" invoke-direct { v0 }, Ljava/lang/StringBuilder;-><init>()V\n");
+ builder.append(StringUtils.lines(" new-instance v0, Ljava/lang/StringBuilder;"));
+ builder.append(StringUtils.lines(" invoke-direct { v0 }, Ljava/lang/StringBuilder;"
+ + "-><init>()V"));
for (int i = 0; i <= 0xffff + 2; i++) {
String prefixed = StringUtils.zeroPrefix(i, 5);
expectedBuilder.append(prefixed);
- expectedBuilder.append("\n");
- builder.append(" const-string v1, \"" + prefixed + "\\n\"\n");
+ expectedBuilder.append(StringUtils.lines(""));
+ builder.append(StringUtils.lines(" const-string v1, \"" + prefixed + "\\n\""));
builder.append(
- " invoke-virtual { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;\n");
+ StringUtils.lines(" invoke-virtual { v0, v1 }, Ljava/lang/StringBuilder;"
+ + "->append(Ljava/lang/String;)Ljava/lang/StringBuilder;"));
}
builder.append(
- " invoke-virtual { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;\n");
- builder.append(" move-result-object v0\n");
- builder.append(" return-object v0\n");
+ StringUtils.lines(" invoke-virtual { v0 }, Ljava/lang/StringBuilder;"
+ + "->toString()Ljava/lang/String;"));
+ builder.append(StringUtils.lines(" move-result-object v0"));
+ builder.append(StringUtils.lines(" return-object v0"));
SmaliBuilder smaliBuilder = new SmaliBuilder(DEFAULT_CLASS_NAME);
diff --git a/src/test/java/com/android/tools/r8/smali/Regress38014736.java b/src/test/java/com/android/tools/r8/smali/Regress38014736.java
index c97d412..bf89f7f 100644
--- a/src/test/java/com/android/tools/r8/smali/Regress38014736.java
+++ b/src/test/java/com/android/tools/r8/smali/Regress38014736.java
@@ -5,8 +5,10 @@
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringUtils;
import org.junit.Test;
public class Regress38014736 extends SmaliTestBase {
@@ -52,7 +54,7 @@
String result = runArt(processedApplication, options);
// The art runtime changed the way exceptions are printed. Therefore, we only check
// for the type of the exception and that the message mentions null.
- assertTrue(result.startsWith("0\njava.lang.NumberFormatException:"));
+ assertTrue(result.startsWith(StringUtils.joinLines("0", "java.lang.NumberFormatException:")));
assertTrue(result.contains("null"));
}
}
diff --git a/src/test/java/com/android/tools/r8/smali/RunArtSmokeTest.java b/src/test/java/com/android/tools/r8/smali/RunArtSmokeTest.java
index e1dc5c4..6a39c6d 100644
--- a/src/test/java/com/android/tools/r8/smali/RunArtSmokeTest.java
+++ b/src/test/java/com/android/tools/r8/smali/RunArtSmokeTest.java
@@ -7,6 +7,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.code.ConstString;
import com.android.tools.r8.code.InvokeVirtual;
import com.android.tools.r8.code.ReturnVoid;
@@ -15,6 +16,7 @@
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.Iterables;
import org.junit.Test;
@@ -49,6 +51,6 @@
// Run the generated code in Art.
String result = runArt(processedApplication, options);
- assertEquals("Hello, world!\n", result);
+ assertEquals(StringUtils.lines("Hello, world!"), result);
}
}