Introduce tests about option -overloadaggressively.
Bug: 72858955
Change-Id: I463ee2532aaab68adc4b25e487d00fb0847b8656
diff --git a/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java b/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java
index 50b95ea..b2560ff 100644
--- a/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java
+++ b/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java
@@ -5,12 +5,14 @@
package com.android.tools.r8;
import com.android.tools.r8.origin.EmbeddedOrigin;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.util.List;
public class CompatProguardCommandBuilder extends R8Command.Builder {
- private static final List<String> REFLECTIONS = ImmutableList.of(
+ @VisibleForTesting
+ public static final List<String> REFLECTIONS = ImmutableList.of(
"-identifiernamestring public class java.lang.Class {",
" public static java.lang.Class forName(java.lang.String);",
" public java.lang.reflect.Field getField(java.lang.String);",
diff --git a/src/test/java/com/android/tools/r8/AsmTestBase.java b/src/test/java/com/android/tools/r8/AsmTestBase.java
index c451402..b1b572f 100644
--- a/src/test/java/com/android/tools/r8/AsmTestBase.java
+++ b/src/test/java/com/android/tools/r8/AsmTestBase.java
@@ -10,20 +10,12 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.ProguardRuleParserException;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
-import java.io.File;
import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
import org.junit.Assert;
public class AsmTestBase extends TestBase {
@@ -104,15 +96,6 @@
ensureSameOutput(main, mergedApp, classes);
}
- protected AndroidApp buildAndroidApp(byte[]... classes) throws IOException {
- AndroidApp.Builder builder = AndroidApp.builder();
- for (byte[] clazz : classes) {
- builder.addClassProgramData(clazz, Origin.unknown());
- }
- builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.N.getLevel()));
- return builder.build();
- }
-
protected static AndroidApp readClassesAndAsmDump(List<Class> classes, List<byte[]> asmClasses)
throws IOException {
AndroidApp.Builder builder = AndroidApp.builder();
@@ -130,32 +113,6 @@
assertTrue(result.stderr, result.stderr.contains(exception.getCanonicalName()));
}
- protected ProcessResult runOnJava(String main, byte[]... classes) throws IOException {
- Path file = writeToZip(classes);
- return ToolHelper.runJavaNoVerify(file, main);
- }
-
- private Path writeToZip(byte[]... classes) throws IOException {
- DumpLoader dumpLoader = new DumpLoader();
- File result = temp.newFile();
- try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(result.toPath(),
- StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
- for (byte[] clazz : classes) {
- String name = dumpLoader.loadClass(clazz).getTypeName();
- ZipEntry zipEntry = new ZipEntry(DescriptorUtils.getPathFromJavaType(name));
- zipEntry.setSize(clazz.length);
- out.putNextEntry(zipEntry);
- out.write(clazz);
- out.closeEntry();
- }
- }
- return result.toPath();
- }
-
- protected static Class loadClassFromDump(byte[] dump) {
- return new DumpLoader().loadClass(dump);
- }
-
@FunctionalInterface
protected interface AsmDump {
@@ -164,7 +121,7 @@
protected static Class loadClassFromAsmClass(AsmDump asmDump) {
try {
- return new DumpLoader().loadClass(asmDump.dump());
+ return loadClassFromDump(asmDump.dump());
} catch (Exception e) {
throw new ClassFormatError(e.toString());
}
@@ -177,13 +134,4 @@
throw new ClassFormatError(e.toString());
}
}
-
- private static class DumpLoader extends ClassLoader {
-
- @SuppressWarnings("deprecation")
- public Class loadClass(byte[] clazz) {
- return defineClass(clazz, 0, clazz.length);
- }
- }
-
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index f02aa2b..500b55c 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -7,6 +7,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.graph.DexCode;
@@ -33,6 +34,7 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
@@ -44,6 +46,7 @@
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
@@ -62,6 +65,18 @@
}
/**
+ * Build an AndroidApp with the specified test classes as byte array.
+ */
+ protected AndroidApp buildAndroidApp(byte[]... classes) throws IOException {
+ AndroidApp.Builder builder = AndroidApp.builder();
+ for (byte[] clazz : classes) {
+ builder.addClassProgramData(clazz, Origin.unknown());
+ }
+ builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.N.getLevel()));
+ return builder.build();
+ }
+
+ /**
* Build an AndroidApp with the specified test classes.
*/
protected static AndroidApp readClasses(Class... classes) throws IOException {
@@ -367,12 +382,20 @@
}
/**
+ * Run application on the specified version of Art with the specified main class.
+ */
+ protected ProcessResult runOnArtRaw(AndroidApp app, String mainClass, DexVm version)
+ throws IOException {
+ Path out = File.createTempFile("junit", ".zip", temp.getRoot()).toPath();
+ app.writeToZip(out, OutputMode.DexIndexed);
+ return ToolHelper.runArtRaw(ImmutableList.of(out.toString()), mainClass, null, version);
+ }
+
+ /**
* Run application on Art with the specified main class.
*/
protected ProcessResult runOnArtRaw(AndroidApp app, String mainClass) throws IOException {
- Path out = File.createTempFile("junit", ".zip", temp.getRoot()).toPath();
- app.writeToZip(out, OutputMode.DexIndexed);
- return ToolHelper.runArtRaw(ImmutableList.of(out.toString()), mainClass, null);
+ return runOnArtRaw(app, mainClass, null);
}
/**
@@ -406,7 +429,17 @@
/**
* Run application on Art with the specified main class and provided arguments.
*/
- protected String runOnArt(AndroidApp app, String mainClass, List<String> args) throws IOException {
+ protected String runOnArt(AndroidApp app, String mainClass, List<String> args)
+ throws IOException {
+ return runOnArt(app, mainClass, args, null);
+ }
+
+ /**
+ * Run application on Art with the specified main class, provided arguments, and specified VM
+ * version.
+ */
+ protected String runOnArt(AndroidApp app, String mainClass, List<String> args, DexVm dexVm)
+ throws IOException {
Path out = File.createTempFile("junit", ".zip", temp.getRoot()).toPath();
app.writeToZip(out, OutputMode.DexIndexed);
return ToolHelper.runArtNoVerificationErrors(
@@ -416,7 +449,8 @@
for (String arg : args) {
builder.appendProgramArgument(arg);
}
- });
+ },
+ dexVm);
}
/**
@@ -448,6 +482,38 @@
return result.stdout;
}
+ protected ProcessResult runOnJava(String main, byte[]... classes) throws IOException {
+ Path file = writeToZip(classes);
+ return ToolHelper.runJavaNoVerify(file, main);
+ }
+
+ private Path writeToZip(byte[]... classes) throws IOException {
+ File result = temp.newFile();
+ try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(result.toPath(),
+ StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
+ for (byte[] clazz : classes) {
+ String name = loadClassFromDump(clazz).getTypeName();
+ ZipEntry zipEntry = new ZipEntry(DescriptorUtils.getPathFromJavaType(name));
+ zipEntry.setSize(clazz.length);
+ out.putNextEntry(zipEntry);
+ out.write(clazz);
+ out.closeEntry();
+ }
+ }
+ return result.toPath();
+ }
+
+ protected static Class loadClassFromDump(byte[] dump) {
+ return new DumpLoader().loadClass(dump);
+ }
+
+ private static class DumpLoader extends ClassLoader {
+
+ @SuppressWarnings("deprecation")
+ public Class loadClass(byte[] clazz) {
+ return defineClass(clazz, 0, clazz.length);
+ }
+ }
/**
* Disassemble the content of an application. Only works for an application with only dex code.
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
index 0cc7c93..62a9c49 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
@@ -7,7 +7,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.AsmTestBase;
+import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfo;
@@ -41,7 +41,7 @@
import java.util.function.BiConsumer;
import org.junit.Test;
-public class NullabilityTest extends AsmTestBase {
+public class NullabilityTest extends TestBase {
private static final InternalOptions TEST_OPTIONS = new InternalOptions();
private void buildAndTest(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullMarkerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullMarkerTest.java
index f6c5fbf..b139f32 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullMarkerTest.java
@@ -7,7 +7,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.AsmTestBase;
+import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfo;
@@ -31,7 +31,7 @@
import java.util.function.Consumer;
import org.junit.Test;
-public class NonNullMarkerTest extends AsmTestBase {
+public class NonNullMarkerTest extends TestBase {
private static final InternalOptions TEST_OPTIONS = new InternalOptions();
private void buildAndTest(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java
index b8105db..4fc51b5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java
@@ -5,7 +5,7 @@
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.AsmTestBase;
+import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.code.Format21t;
import com.android.tools.r8.code.Format22t;
@@ -23,7 +23,7 @@
import java.util.List;
import org.junit.Test;
-public class SimplifyIfNotNullTest extends AsmTestBase {
+public class SimplifyIfNotNullTest extends TestBase {
private static boolean isIf(Instruction instruction) {
return instruction instanceof Format21t || instruction instanceof Format22t;
}
diff --git a/src/test/java/com/android/tools/r8/naming/overloadaggressively/A.java b/src/test/java/com/android/tools/r8/naming/overloadaggressively/A.java
new file mode 100644
index 0000000..af4c4b2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/overloadaggressively/A.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2018, 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.naming.overloadaggressively;
+
+public class A {
+ volatile int f1;
+ volatile Object f2;
+ volatile B f3;
+}
diff --git a/src/test/java/com/android/tools/r8/naming/overloadaggressively/B.java b/src/test/java/com/android/tools/r8/naming/overloadaggressively/B.java
new file mode 100644
index 0000000..78f5a24
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/overloadaggressively/B.java
@@ -0,0 +1,9 @@
+// Copyright (c) 2018, 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.naming.overloadaggressively;
+
+public class B {
+ volatile int f1;
+ volatile Object f2;
+}
diff --git a/src/test/java/com/android/tools/r8/naming/overloadaggressively/Main.java b/src/test/java/com/android/tools/r8/naming/overloadaggressively/Main.java
new file mode 100644
index 0000000..956b198
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/overloadaggressively/Main.java
@@ -0,0 +1,37 @@
+// Copyright (c) 2018, 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.naming.overloadaggressively;
+
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+public class Main {
+ @SuppressWarnings("unchecked")
+ public static void main(String[] args) throws Exception {
+ A a = new A();
+ B b = new B();
+ AtomicReferenceFieldUpdater f3Updater =
+ AtomicReferenceFieldUpdater.newUpdater(A.class, B.class, "f3");
+ f3Updater.set(a, b);
+ AtomicReferenceFieldUpdater f2Updater =
+ AtomicReferenceFieldUpdater.newUpdater(A.class, Object.class, "f2");
+ f2Updater.set(a, b);
+ assert a.f2 instanceof B;
+ assert a.f2 == a.f3;
+ ((B) a.f2).f2 = a;
+ assert b.f2 instanceof A;
+ assert ((A) b.f2).f2 == b;
+
+ Random random = new Random();
+ int next = random.nextInt();
+ AtomicIntegerFieldUpdater f1Updater =
+ AtomicIntegerFieldUpdater.newUpdater(A.class, "f1");
+ f1Updater.set(a, next);
+ B viaF3 = a.f3;
+ viaF3.f1 = next;
+ int diff = viaF3.f1 - a.f1;
+ System.out.println("diff: " + diff);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java b/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java
new file mode 100644
index 0000000..d0cdb28
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java
@@ -0,0 +1,112 @@
+// Copyright (c) 2018, 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.naming.overloadaggressively;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.CompatProguardCommandBuilder;
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.ToolHelper.DexVm.Kind;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.DexInspector;
+import com.android.tools.r8.utils.DexInspector.ClassSubject;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class OverloadAggressivelyTest extends TestBase {
+ private final DexVm dexVm;
+ private final boolean overloadaggressively;
+
+ public OverloadAggressivelyTest(DexVm dexVm, boolean overloadaggressively) {
+ this.dexVm = dexVm;
+ this.overloadaggressively = overloadaggressively;
+ }
+
+ @Parameters(name = "vm: {0}, overloadaggressively: {1}")
+ public static Collection<Object[]> data() {
+ List<Object[]> testCases = new ArrayList<>();
+ for (DexVm version : DexVm.values()) {
+ if (version.getKind() == Kind.HOST) {
+ testCases.add(new Object[]{version, true});
+ testCases.add(new Object[]{version, false});
+ }
+ }
+ return testCases;
+ }
+
+ @Test
+ public void overloadAggressivelyTest() throws Exception {
+ Assume.assumeTrue(ToolHelper.artSupported());
+ byte[][] classes = {
+ ToolHelper.getClassAsBytes(Main.class),
+ ToolHelper.getClassAsBytes(A.class),
+ ToolHelper.getClassAsBytes(B.class)
+ };
+ AndroidApp originalApp = buildAndroidApp(classes);
+ Path out = temp.getRoot().toPath();
+ R8Command command =
+ ToolHelper.addProguardConfigurationConsumer(
+ ToolHelper.prepareR8CommandBuilder(originalApp),
+ pgConfig -> {
+ pgConfig.setPrintMapping(true);
+ pgConfig.setPrintMappingFile(out.resolve(ToolHelper.DEFAULT_PROGUARD_MAP_FILE));
+ })
+ .addProguardConfiguration(
+ ImmutableList.copyOf(Iterables.concat(ImmutableList.of(
+ keepMainProguardConfiguration(Main.class),
+ overloadaggressively ? "-overloadaggressively" : ""),
+ CompatProguardCommandBuilder.REFLECTIONS)),
+ Origin.unknown())
+ .setOutput(out, OutputMode.DexIndexed)
+ .build();
+ AndroidApp processedApp = ToolHelper.runR8(command);
+
+ DexInspector dexInspector = new DexInspector(
+ out.resolve(ToolHelper.DEFAULT_DEX_FILENAME),
+ out.resolve(ToolHelper.DEFAULT_PROGUARD_MAP_FILE).toString());
+ ClassSubject a = dexInspector.clazz(A.class.getCanonicalName());
+ DexEncodedField f1 = a.field("int", "f1").getField();
+ assertNotNull(f1);
+ DexEncodedField f2 = a.field("java.lang.Object", "f2").getField();
+ assertNotNull(f2);
+ assertEquals(overloadaggressively, f1.field.name == f2.field.name);
+ DexEncodedField f3 = a.field(B.class.getCanonicalName(), "f3").getField();
+ assertNotNull(f3);
+ assertEquals(overloadaggressively, f1.field.name == f3.field.name);
+ assertEquals(overloadaggressively, f2.field.name == f3.field.name);
+
+ ProcessResult javaOutput = runOnJava(Main.class.getCanonicalName(), classes);
+ ProcessResult artOutput = runOnArtRaw(processedApp, Main.class.getCanonicalName(), dexVm);
+ if (overloadaggressively) {
+ assertNotEquals(0, artOutput.exitCode);
+ assertTrue(artOutput.stderr.contains("ClassCastException"));
+ } else {
+ assertEquals(0, javaOutput.exitCode);
+ assertEquals(0, artOutput.exitCode);
+ assertEquals(javaOutput.stdout.trim(), artOutput.stdout.trim());
+ // ART may dump its own debugging info through stderr.
+ // assertEquals(javaOutput.stderr.trim(), artOutput.stderr.trim());
+ }
+ }
+}