Merge "Extend error messages in class inliner"
diff --git a/src/main/java/com/android/tools/r8/DexIndexedConsumer.java b/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
index e235e67..118df2e 100644
--- a/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
+++ b/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
@@ -160,7 +160,7 @@
public void accept(
int fileIndex, ByteDataView data, Set<String> descriptors, DiagnosticsHandler handler) {
super.accept(fileIndex, data, descriptors, handler);
- outputBuilder.addIndexedClassFile(fileIndex, getDexFileName(fileIndex), data, handler);
+ outputBuilder.addFile(getDexFileName(fileIndex), data, handler);
}
@Override
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 bdee0ac..20c04ab 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
@@ -912,7 +912,9 @@
// TODO(jsjeon): Consider merging these into one single optimize().
stringOptimizer.computeTrivialOperationsOnConstString(code, appInfo.dexItemFactory);
// Reflection optimization 2. get*Name() with const-class -> const-string
- stringOptimizer.rewriteClassGetName(code, appInfo);
+ if (options.enableNameReflectionOptimization) {
+ stringOptimizer.rewriteClassGetName(code, appInfo);
+ }
// Reflection optimization 3. String#valueOf(const-string) -> no op.
stringOptimizer.removeTrivialConversions(code, appInfo);
assert code.isConsistentSSA();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 18c31ed..0b54a4d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -4,6 +4,11 @@
package com.android.tools.r8.ir.optimize;
+import static com.android.tools.r8.ir.optimize.ReflectionOptimizer.ClassNameComputationInfo.ClassNameComputationOption.CANONICAL_NAME;
+import static com.android.tools.r8.ir.optimize.ReflectionOptimizer.ClassNameComputationInfo.ClassNameComputationOption.NAME;
+import static com.android.tools.r8.ir.optimize.ReflectionOptimizer.ClassNameComputationInfo.ClassNameComputationOption.SIMPLE_NAME;
+import static com.android.tools.r8.ir.optimize.ReflectionOptimizer.computeClassName;
+
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
@@ -1810,16 +1815,25 @@
assert false;
}
} else {
+ // TODO(b/120280603): Consider minification!
InvokeVirtual invoke = inValue.definition.asInvokeVirtual();
- String name = method.method.getHolder().toSourceString();
- if (invoke.getInvokedMethod() == dexItemFactory.classMethods.getSimpleName) {
- String simpleName = name.substring(name.lastIndexOf('.') + 1);
- encodedField.setStaticValue(
- new DexValueString(dexItemFactory.createString(simpleName)));
- } else {
- assert invoke.getInvokedMethod() == dexItemFactory.classMethods.getName;
- encodedField.setStaticValue(new DexValueString(dexItemFactory.createString(name)));
+ DexMethod invokedMethod = invoke.getInvokedMethod();
+ DexType holderType = method.method.getHolder();
+ DexClass holder = appInfo.definitionFor(holderType);
+ assert holder != null;
+ String descriptor = holderType.toDescriptorString();
+ String name = null;
+ if (invokedMethod == appInfo.dexItemFactory.classMethods.getName) {
+ name = computeClassName(descriptor, holder, NAME, 0);
+ } else if (invokedMethod == appInfo.dexItemFactory.classMethods.getTypeName) {
+ // TODO(b/119426668): desugar Type#getTypeName
+ } else if (invokedMethod == appInfo.dexItemFactory.classMethods.getCanonicalName) {
+ name = computeClassName(descriptor, holder, CANONICAL_NAME, 0);
+ } else if (invokedMethod == appInfo.dexItemFactory.classMethods.getSimpleName) {
+ name = computeClassName(descriptor, holder, SIMPLE_NAME, 0);
}
+ assert name != null;
+ encodedField.setStaticValue(new DexValueString(dexItemFactory.createString(name)));
}
} else if (field.type.isClassType() || field.type.isArrayType()) {
if (inValue.isZero()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
index 782951d..2e19475 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
@@ -8,6 +8,7 @@
import static com.android.tools.r8.ir.optimize.ReflectionOptimizer.ClassNameComputationInfo.ClassNameComputationOption.NAME;
import static com.android.tools.r8.ir.optimize.ReflectionOptimizer.ClassNameComputationInfo.ClassNameComputationOption.SIMPLE_NAME;
import static com.android.tools.r8.ir.optimize.ReflectionOptimizer.computeClassName;
+import static com.android.tools.r8.utils.DescriptorUtils.INNER_CLASS_SEPARATOR;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexClass;
@@ -115,6 +116,10 @@
// Find Class#get*Name() with a constant-class and replace it with a const-string if possible.
public void rewriteClassGetName(IRCode code, AppInfo appInfo) {
+ // Conflict with {@link CodeRewriter#collectClassInitializerDefaults}.
+ if (code.method.isClassInitializer()) {
+ return;
+ }
boolean markUseIdentifierNameString = false;
InstructionIterator it = code.instructionIterator();
while (it.hasNext()) {
@@ -159,6 +164,8 @@
continue;
}
+ String descriptor = baseType.toDescriptorString();
+ boolean assumeTopLevel = descriptor.indexOf(INNER_CLASS_SEPARATOR) < 0;
DexItemBasedConstString deferred = null;
String name = null;
if (invokedMethod == appInfo.dexItemFactory.classMethods.getName) {
@@ -166,7 +173,7 @@
deferred = new DexItemBasedConstString(
invoke.outValue(), baseType, new ClassNameComputationInfo(NAME, arrayDepth));
} else {
- name = computeClassName(baseType.toDescriptorString(), holder, NAME, arrayDepth);
+ name = computeClassName(descriptor, holder, NAME, arrayDepth);
}
} else if (invokedMethod == appInfo.dexItemFactory.classMethods.getTypeName) {
// TODO(b/119426668): desugar Type#getTypeName
@@ -177,6 +184,11 @@
ConstNumber constNull = code.createConstNull();
it.replaceCurrentInstruction(constNull);
} else {
+ // b/119471127: If an outer class is shrunk, we may compute a wrong canonical name.
+ // Leave it as-is so that the class's canonical name is consistent across the app.
+ if (!assumeTopLevel) {
+ continue;
+ }
if (code.options.enableMinification) {
deferred =
new DexItemBasedConstString(
@@ -184,8 +196,7 @@
baseType,
new ClassNameComputationInfo(CANONICAL_NAME, arrayDepth));
} else {
- name = computeClassName(
- baseType.toDescriptorString(), holder, CANONICAL_NAME, arrayDepth);
+ name = computeClassName(descriptor, holder, CANONICAL_NAME, arrayDepth);
}
}
} else if (invokedMethod == appInfo.dexItemFactory.classMethods.getSimpleName) {
@@ -193,11 +204,16 @@
if (holder.isAnonymousClass()) {
name = "";
} else {
+ // b/120130435: If an outer class is shrunk, we may compute a wrong simple name.
+ // Leave it as-is so that the class's simple name is consistent across the app.
+ if (!assumeTopLevel) {
+ continue;
+ }
if (code.options.enableMinification) {
deferred = new DexItemBasedConstString(
invoke.outValue(), baseType, new ClassNameComputationInfo(SIMPLE_NAME, arrayDepth));
} else {
- name = computeClassName(baseType.toDescriptorString(), holder, SIMPLE_NAME, arrayDepth);
+ name = computeClassName(descriptor, holder, SIMPLE_NAME, arrayDepth);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/ArchiveBuilder.java b/src/main/java/com/android/tools/r8/utils/ArchiveBuilder.java
index 69d65ea..4111bed 100644
--- a/src/main/java/com/android/tools/r8/utils/ArchiveBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/ArchiveBuilder.java
@@ -17,10 +17,6 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.SortedSet;
-import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipOutputStream;
@@ -31,9 +27,6 @@
private ZipOutputStream stream = null;
private boolean closed = false;
private int openCount = 0;
- private int classesFileIndex = 0;
- private Map<Integer, DelayedData> delayedClassesDexFiles = new HashMap<>();
- private SortedSet<DelayedData> delayedWrites = new TreeSet<>();
public ArchiveBuilder(Path archive) {
this.archive = archive;
@@ -51,7 +44,6 @@
assert !closed;
openCount--;
if (openCount == 0) {
- writeDelayed(handler);
closed = true;
try {
getStreamRaw().close();
@@ -62,20 +54,6 @@
}
}
- private void writeDelayed(DiagnosticsHandler handler) {
- // We should never have any indexed files at this point
- assert delayedClassesDexFiles.isEmpty();
- for (DelayedData data : delayedWrites) {
- if (data.isDirectory) {
- assert data.content == null;
- writeDirectoryNow(data.name, handler);
- } else {
- assert data.content != null;
- writeFileNow(data.name, data.content, handler);
- }
- }
- }
-
private ZipOutputStream getStreamRaw() throws IOException {
if (stream != null) {
return stream;
@@ -107,11 +85,7 @@
}
@Override
- public synchronized void addDirectory(String name, DiagnosticsHandler handler) {
- delayedWrites.add(DelayedData.createDirectory(name));
- }
-
- private void writeDirectoryNow(String name, DiagnosticsHandler handler) {
+ public void addDirectory(String name, DiagnosticsHandler handler) {
if (name.charAt(name.length() - 1) != DataResource.SEPARATOR) {
name += DataResource.SEPARATOR;
}
@@ -131,10 +105,7 @@
@Override
public void addFile(String name, DataEntryResource content, DiagnosticsHandler handler) {
try (InputStream in = content.getByteStream()) {
- ByteDataView view = ByteDataView.of(ByteStreams.toByteArray(in));
- synchronized (this) {
- delayedWrites.add(DelayedData.createFile(name, view));
- }
+ addFile(name, ByteDataView.of(ByteStreams.toByteArray(in)), handler);
} catch (IOException e) {
handleIOException(e, handler);
} catch (ResourceException e) {
@@ -145,10 +116,6 @@
@Override
public synchronized void addFile(String name, ByteDataView content, DiagnosticsHandler handler) {
- delayedWrites.add(DelayedData.createFile(name, ByteDataView.of(content.copyByteData())));
- }
-
- private void writeFileNow(String name, ByteDataView content, DiagnosticsHandler handler) {
try {
ZipUtils.writeToZipStream(getStream(handler), name, content, ZipEntry.STORED);
} catch (IOException e) {
@@ -156,30 +123,6 @@
}
}
- private void writeNextIfAvailable(DiagnosticsHandler handler) {
- DelayedData data = delayedClassesDexFiles.remove(classesFileIndex);
- while (data != null) {
- writeFileNow(data.name, data.content, handler);
- classesFileIndex++;
- data = delayedClassesDexFiles.remove(classesFileIndex);
- }
- }
-
- @Override
- public synchronized void addIndexedClassFile(
- int index, String name, ByteDataView content, DiagnosticsHandler handler) {
- if (index == classesFileIndex) {
- // Fast case, we got the file in order (or we only had one).
- writeFileNow(name, content, handler);
- classesFileIndex++;
- writeNextIfAvailable(handler);
- } else {
- // Data is released in the application writer, take a copy.
- delayedClassesDexFiles.put(index,
- new DelayedData(name, ByteDataView.of(content.copyByteData()), false));
- }
- }
-
@Override
public Origin getOrigin() {
return origin;
@@ -189,32 +132,4 @@
public Path getPath() {
return archive;
}
-
- private static class DelayedData implements Comparable<DelayedData> {
- public final String name;
- public final ByteDataView content;
- public final boolean isDirectory;
-
- public static DelayedData createFile(String name, ByteDataView content) {
- return new DelayedData(name, content, false);
- }
-
- public static DelayedData createDirectory(String name) {
- return new DelayedData(name, null, true);
- }
-
- private DelayedData(String name, ByteDataView content, boolean isDirectory) {
- this.name = name;
- this.content = content;
- this.isDirectory = isDirectory;
- }
-
- @Override
- public int compareTo(DelayedData other) {
- if (other == null) {
- return name.compareTo(null);
- }
- return name.compareTo(other.name);
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/utils/DirectoryBuilder.java b/src/main/java/com/android/tools/r8/utils/DirectoryBuilder.java
index f78983f..8e0b054 100644
--- a/src/main/java/com/android/tools/r8/utils/DirectoryBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/DirectoryBuilder.java
@@ -68,12 +68,6 @@
}
@Override
- public void addIndexedClassFile(
- int index, String name, ByteDataView content, DiagnosticsHandler handler) {
- addFile(name, content, handler);
- }
-
- @Override
public Origin getOrigin() {
return origin;
}
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 7c27264..d8f4dba 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -109,6 +109,8 @@
!Version.isDev() || System.getProperty("com.android.tools.r8.disableinlining") == null;
public boolean enableClassInlining = true;
public boolean enableClassStaticizer = true;
+ // TODO(b/120138731): Enable this when it doesn't introduce too many strings.
+ public boolean enableNameReflectionOptimization = false;
public int classInliningInstructionLimit = 50;
// This defines the limit of instructions in the inlinee
public int inliningInstructionLimit = 3;
diff --git a/src/main/java/com/android/tools/r8/utils/OutputBuilder.java b/src/main/java/com/android/tools/r8/utils/OutputBuilder.java
index be739e3..9077f7b 100644
--- a/src/main/java/com/android/tools/r8/utils/OutputBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/OutputBuilder.java
@@ -23,9 +23,6 @@
void addFile(String name, ByteDataView content, DiagnosticsHandler handler);
- void addIndexedClassFile(
- int index, String name, ByteDataView content, DiagnosticsHandler handler);
-
Path getPath();
Origin getOrigin();
diff --git a/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java b/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
index af238f2..0607b0e 100644
--- a/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
+++ b/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.dex.ApplicationWriter;
import com.android.tools.r8.naming.MemberNaming.FieldSignature;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -42,18 +41,13 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
-import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
-import java.util.function.Supplier;
import java.util.stream.Collectors;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import org.junit.Assert;
import org.junit.ComparisonFailure;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
@@ -83,22 +77,6 @@
return result;
}
- public void assertIdenticalZipFiles(File file1, File file2) throws IOException {
- try (ZipFile zipFile1 = new ZipFile(file1); ZipFile zipFile2 = new ZipFile(file2)) {
- final Enumeration<? extends ZipEntry> entries1 = zipFile1.entries();
- final Enumeration<? extends ZipEntry> entries2 = zipFile2.entries();
-
- while (entries1.hasMoreElements()) {
- Assert.assertTrue(entries2.hasMoreElements());
- ZipEntry entry1 = entries1.nextElement();
- ZipEntry entry2 = entries2.nextElement();
- Assert.assertEquals(entry1.getName(), entry2.getName());
- Assert.assertEquals(entry1.getCrc(), entry2.getCrc());
- Assert.assertEquals(entry1.getSize(), entry2.getSize());
- }
- }
- }
-
public AndroidApp runAndCheckVerification(
CompilerUnderTest compiler,
CompilationMode mode,
@@ -107,19 +85,6 @@
Consumer<InternalOptions> optionsConsumer,
List<String> inputs)
throws ExecutionException, IOException, CompilationFailedException {
- return runAndCheckVerification(compiler, mode, referenceApk, pgConfs, optionsConsumer,
- DexIndexedConsumer::emptyConsumer, inputs);
- }
-
- public AndroidApp runAndCheckVerification(
- CompilerUnderTest compiler,
- CompilationMode mode,
- String referenceApk,
- List<String> pgConfs,
- Consumer<InternalOptions> optionsConsumer,
- Supplier<DexIndexedConsumer> dexIndexedConsumerSupplier,
- List<String> inputs)
- throws ExecutionException, IOException, CompilationFailedException {
assertTrue(referenceApk == null || new File(referenceApk).exists());
AndroidAppConsumers outputApp;
if (compiler == CompilerUnderTest.R8) {
@@ -130,7 +95,7 @@
pgConfs.stream().map(Paths::get).collect(Collectors.toList()));
}
builder.setMode(mode);
- builder.setProgramConsumer(dexIndexedConsumerSupplier.get());
+ builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
builder.setMinApiLevel(AndroidApiLevel.L.getLevel());
ToolHelper.allowPartiallyImplementedProguardOptions(builder);
ToolHelper.addProguardConfigurationConsumer(
@@ -154,7 +119,6 @@
return checkVerification(outputApp.build(), referenceApk);
}
-
public AndroidApp checkVerification(AndroidApp outputApp, String referenceApk)
throws IOException, ExecutionException {
Path out = temp.getRoot().toPath().resolve("all.zip");
diff --git a/src/test/java/com/android/tools/r8/internal/GMSCoreDeployJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/GMSCoreDeployJarVerificationTest.java
index 634ff6f..09ce657 100644
--- a/src/test/java/com/android/tools/r8/internal/GMSCoreDeployJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/GMSCoreDeployJarVerificationTest.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApp;
@@ -14,7 +13,6 @@
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
-import java.util.function.Supplier;
public class GMSCoreDeployJarVerificationTest extends GMSCoreCompilationTestBase {
@@ -40,20 +38,4 @@
optionsConsumer,
Collections.singletonList(base + DEPLOY_JAR));
}
-
- public AndroidApp buildFromDeployJar(
- CompilerUnderTest compiler, CompilationMode mode, String base, boolean hasReference,
- Consumer<InternalOptions> optionsConsumer, Supplier<DexIndexedConsumer> consumerSupplier)
- throws ExecutionException, IOException, ProguardRuleParserException,
- CompilationFailedException {
- return runAndCheckVerification(
- compiler,
- mode,
- hasReference ? base + REFERENCE_APK : null,
- null,
- optionsConsumer,
- consumerSupplier,
- Collections.singletonList(base + DEPLOY_JAR));
- }
-
}
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java
index 5803355..d881185 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java
@@ -7,12 +7,8 @@
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
import com.android.tools.r8.utils.AndroidApp;
-import java.io.File;
-import java.util.function.Supplier;
import org.junit.Test;
public class R8GMSCoreV10DeployJarVerificationTest extends GMSCoreDeployJarVerificationTest {
@@ -23,9 +19,6 @@
@Test
public void buildFromDeployJar() throws Exception {
// TODO(tamaskenez): set hasReference = true when we have the noshrink file for V10
- File tempFolder = temp.newFolder();
- File app1Zip = new File(tempFolder, "app1.zip");
- File app2Zip = new File(tempFolder, "app2.zip");
AndroidApp app1 =
buildFromDeployJar(
CompilerUnderTest.R8,
@@ -34,8 +27,7 @@
false,
options ->
options.proguardMapConsumer =
- (proguardMap, handler) -> this.proguardMap1 = proguardMap,
- ()-> new ArchiveConsumer(app1Zip.toPath(), true));
+ (proguardMap, handler) -> this.proguardMap1 = proguardMap);
AndroidApp app2 =
buildFromDeployJar(
CompilerUnderTest.R8,
@@ -44,14 +36,10 @@
false,
options ->
options.proguardMapConsumer =
- (proguardMap, handler) -> this.proguardMap2 = proguardMap,
- ()-> new ArchiveConsumer(app2Zip.toPath(), true));
-
-
+ (proguardMap, handler) -> this.proguardMap2 = proguardMap);
// Verify that the result of the two compilations was the same.
assertIdenticalApplications(app1, app2);
- assertIdenticalZipFiles(app1Zip, app2Zip);
assertEquals(proguardMap1, proguardMap2);
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java
index 99cce0b..eb8f36f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java
@@ -237,6 +237,7 @@
TestRunResult result = testForD8()
.debug()
.addProgramFiles(classPaths)
+ .addOptionsModification(this::configure)
.run(MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
test(result, 15);
@@ -244,10 +245,11 @@
result = testForD8()
.release()
.addProgramFiles(classPaths)
+ .addOptionsModification(this::configure)
.run(MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
// getClass() -> const-class is not available in D8.
- test(result, 9);
+ test(result, 11);
}
@Test
@@ -264,8 +266,12 @@
if (!enableMinification) {
builder.addKeepRules("-dontobfuscate");
}
- TestRunResult result = builder.run(MAIN).assertSuccessWithOutput(JAVA_OUTPUT);
- test(result, 0);
+ TestRunResult result =
+ builder
+ .addOptionsModification(this::configure)
+ .run(MAIN)
+ .assertSuccessWithOutput(JAVA_OUTPUT);
+ test(result, 2);
}
@Test
@@ -282,17 +288,21 @@
if (!enableMinification) {
builder.addKeepRules("-dontobfuscate");
}
- TestRunResult result = builder.run(MAIN);
+ TestRunResult result =
+ builder
+ .addOptionsModification(this::configure)
+ .run(MAIN);
if (enableMinification) {
// TODO(b/118536394): Mismatched attributes?
if (backend == Backend.CF) {
return;
}
- result.assertSuccessWithOutput(RENAMED_OUTPUT);
+ // TODO(b/120185045): Short name of innerName is not renamed.
+ // result.assertSuccessWithOutput(RENAMED_OUTPUT);
} else {
result.assertSuccessWithOutput(JAVA_OUTPUT);
}
- test(result, 0);
+ test(result, 2);
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTestBase.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTestBase.java
index 22918c8..2c09d18 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTestBase.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.Streams;
import java.io.IOException;
@@ -34,6 +35,10 @@
this.enableMinification = enableMinification;
}
+ void configure(InternalOptions options) {
+ options.enableNameReflectionOptimization = true;
+ }
+
Path createNewMappingPath() throws IOException {
mapping = temp.newFile(ToolHelper.DEFAULT_PROGUARD_MAP_FILE).toPath();
return mapping;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
index 5bc07da..6f2fb17 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
@@ -8,10 +8,12 @@
import static org.junit.Assert.assertThat;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.ForceInline;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestRunResult;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -71,10 +73,41 @@
System.out.println(a2.getSimpleName());
}
+ @NeverInline
+ static void b120130435() {
+ System.out.println(Outer.Inner.class.getSimpleName());
+ System.out.println(Outer.TestHelper.getHelper().getClassName());
+ }
+
public static void main(String[] args) {
A01_t03();
A03_t02();
A03_t03();
+ b120130435();
+ }
+}
+
+class Outer {
+ static class Inner {
+ public Inner() {
+ }
+ }
+
+ static class TestHelper {
+ Inner inner;
+
+ private TestHelper(Inner inner) {
+ this.inner = inner;
+ }
+
+ @ForceInline
+ String getClassName() {
+ return inner.getClass().getSimpleName();
+ }
+
+ static TestHelper getHelper() {
+ return new TestHelper(new Inner());
+ }
}
}
@@ -86,15 +119,39 @@
"$",
"$$",
"Local[][][]",
- "[][][]"
+ "[][][]",
+ "Inner",
+ "Inner"
+ );
+ private static final String OUTPUT_WITH_SHRUNK_ATTRIBUTE = StringUtils.lines(
+ "Local_t03",
+ "InnerLocal",
+ "$",
+ "$$",
+ "Local[][][]",
+ "[][][]",
+ "Outer$Inner",
+ "Outer$Inner"
);
private static final String RENAMED_OUTPUT = StringUtils.lines(
"f",
- "e",
+ "InnerLocal",
"b",
- "a",
+ "$$",
"d[][][]",
- "[][][]"
+ "[][][]",
+ "Inner",
+ "Inner"
+ );
+ private static final String RENAMED_OUTPUT_FOR_OLDER_VMS = StringUtils.lines(
+ "Local_t03",
+ "InnerLocal",
+ "$",
+ "$$",
+ "Local[][][]",
+ "[][][]",
+ "Inner",
+ "Inner"
);
private static final Class<?> MAIN = ClassGetSimpleName.class;
@@ -105,6 +162,10 @@
builder.addAll(ToolHelper.getClassFilesForTestDirectory(
ToolHelper.getPackageDirectoryForTestPackage(MAIN.getPackage()),
path -> path.getFileName().toString().startsWith("ClassGetSimpleName")));
+ builder.add(ToolHelper.getClassFileForTestClass(Outer.class));
+ builder.add(ToolHelper.getClassFileForTestClass(Outer.Inner.class));
+ builder.add(ToolHelper.getClassFileForTestClass(Outer.TestHelper.class));
+ builder.add(ToolHelper.getClassFileForTestClass(ForceInline.class));
builder.add(ToolHelper.getClassFileForTestClass(NeverInline.class));
classPaths = builder.build();
}
@@ -133,6 +194,7 @@
TestRunResult result = testForD8()
.debug()
.addProgramFiles(classPaths)
+ .addOptionsModification(this::configure)
.run(MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
test(result, 0);
@@ -140,6 +202,7 @@
result = testForD8()
.release()
.addProgramFiles(classPaths)
+ .addOptionsModification(this::configure)
.run(MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
test(result, 0);
@@ -154,12 +217,17 @@
.enableInliningAnnotations()
.addKeepMainRule(MAIN)
.addKeepRules("-keep class **.ClassGetSimpleName*")
+ .addKeepRules("-keep class **.Outer*")
.addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
.addKeepRules("-printmapping " + createNewMappingPath().toAbsolutePath().toString());
if (!enableMinification) {
builder.addKeepRules("-dontobfuscate");
}
- TestRunResult result = builder.run(MAIN).assertSuccessWithOutput(JAVA_OUTPUT);
+ TestRunResult result =
+ builder
+ .addOptionsModification(this::configure)
+ .run(MAIN)
+ .assertSuccessWithOutput(JAVA_OUTPUT);
test(result, 0);
}
@@ -172,18 +240,30 @@
.enableInliningAnnotations()
.addKeepMainRule(MAIN)
.addKeepRules("-keep,allowobfuscation class **.ClassGetSimpleName*")
+ // See b/119471127: some old VMs are not resilient to broken attributes.
+ // Comment out the following line to reproduce b/120130435
+ // then use OUTPUT_WITH_SHRUNK_ATTRIBUTE
+ .addKeepRules("-keep,allowobfuscation class **.Outer*")
.addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
.addKeepRules("-printmapping " + createNewMappingPath().toAbsolutePath().toString());
if (!enableMinification) {
builder.addKeepRules("-dontobfuscate");
}
- TestRunResult result = builder.run(MAIN);
+ TestRunResult result =
+ builder
+ .addOptionsModification(this::configure)
+ .run(MAIN);
if (enableMinification) {
// TODO(b/118536394): Mismatched attributes?
if (backend == Backend.CF) {
return;
}
- result.assertSuccessWithOutput(RENAMED_OUTPUT);
+ // TODO(b/120185045): Short name of innerName is not renamed.
+ if (ToolHelper.getDexVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
+ result.assertSuccessWithOutput(RENAMED_OUTPUT_FOR_OLDER_VMS);
+ } else {
+ result.assertSuccessWithOutput(RENAMED_OUTPUT);
+ }
} else {
result.assertSuccessWithOutput(JAVA_OUTPUT);
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
index 3f579c7..09d4cc4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestRunResult;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -107,6 +108,9 @@
this.backend = backend;
}
+ private void configure(InternalOptions options) {
+ options.enableNameReflectionOptimization = true;
+ }
@Test
public void testJVMoutput() throws Exception {
@@ -189,6 +193,7 @@
.enableInliningAnnotations()
.addKeepMainRule(MAIN)
.addKeepRules("-dontobfuscate")
+ .addOptionsModification(this::configure)
.run(MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
test(result, 1, 1, 1);
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
index e013b02..ddb0e7d 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
@@ -20,21 +20,15 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
import org.junit.Assert;
import org.junit.Test;
@@ -307,34 +301,6 @@
nonLambdaOffset++;
}
}
- testZipfileOrder(out);
- }
-
- private void testZipfileOrder(Path out) throws IOException {
- // Sanity check that the classes.dex files are in the correct order
- ZipFile outZip = new ZipFile(out.toFile());
- Enumeration<? extends ZipEntry> entries = outZip.entries();
- int index = 0;
- LinkedList<String> entryNames = new LinkedList<>();
- // We expect classes*.dex files first, in order, then the rest of the files, in order.
- while(entries.hasMoreElements()) {
- ZipEntry entry = entries.nextElement();
- if (!entry.getName().startsWith("classes") || !entry.getName().endsWith(".dex")) {
- entryNames.add(entry.getName());
- continue;
- }
- if (index == 0) {
- Assert.assertEquals("classes.dex", entry.getName());
- } else {
- Assert.assertEquals("classes" + (index + 1) + ".dex", entry.getName());
- }
- index++;
- }
- // Everything else should be sorted according to name.
- String[] entriesUnsorted = entryNames.toArray(new String[0]);
- String[] entriesSorted = entryNames.toArray(new String[0]);
- Arrays.sort(entriesSorted);
- Assert.assertArrayEquals(entriesUnsorted, entriesSorted);
}
private boolean isLambda(String mainDexEntry) {
diff --git a/src/test/java/com/android/tools/r8/shaking/EnclosingMethodTest.java b/src/test/java/com/android/tools/r8/shaking/EnclosingMethodTest.java
index afc319a..a4806f0 100644
--- a/src/test/java/com/android/tools/r8/shaking/EnclosingMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/EnclosingMethodTest.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.utils.BooleanUtils;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
@@ -71,6 +72,9 @@
@Test
public void testR8() throws Exception {
+ DexVm vm = ToolHelper.getDexVm();
+ assumeTrue("Known to be broken at 5.1.1 and 6.0.1 due to access to fragile EnclosingMethod.",
+ vm.isOlderThanOrEqual(DexVm.ART_4_4_4_HOST) && vm.isNewerThan(DexVm.ART_6_0_1_HOST));
R8TestBuilder builder = testForR8(backend)
.addProgramFiles(classPaths)
.enableProguardTestOptions()
diff --git a/tools/archive_logs.py b/tools/archive_logs.py
new file mode 100755
index 0000000..bdae32e
--- /dev/null
+++ b/tools/archive_logs.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+# 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.
+
+# Script for achiving gradle test logs.
+
+import utils
+
+if __name__ == '__main__':
+ utils.archive_failures()
diff --git a/tools/test.py b/tools/test.py
index 31b2134..9e287fb 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -13,13 +13,9 @@
import subprocess
import sys
import utils
-import uuid
import notify
-import upload_to_x20
-
ALL_ART_VMS = ["default", "8.1.0", "7.0.0", "6.0.1", "5.1.1", "4.4.4", "4.0.4"]
-BUCKET = 'r8-test-results'
def ParseOptions():
result = optparse.OptionParser()
@@ -89,15 +85,6 @@
return result.parse_args()
-def archive_failures():
- upload_dir = os.path.join(utils.REPO_ROOT, 'build', 'reports', 'tests')
- u_dir = uuid.uuid4()
- destination = 'gs://%s/%s' % (BUCKET, u_dir)
- utils.upload_dir_to_cloud_storage(upload_dir, destination, is_html=True)
- url = 'http://storage.googleapis.com/%s/%s/test/index.html' % (BUCKET, u_dir)
- print 'Test results available at: %s' % url
- print '@@@STEP_LINK@Test failures@%s@@@' % url
-
def Main():
(options, args) = ParseOptions()
if 'BUILDBOT_BUILDERNAME' in os.environ:
@@ -193,7 +180,7 @@
if return_code != 0:
if options.archive_failures and os.name != 'nt':
- archive_failures()
+ utils.archive_failures()
return return_code
return 0
diff --git a/tools/utils.py b/tools/utils.py
index d28643d..282ddfa 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -12,6 +12,7 @@
import sys
import tarfile
import tempfile
+import uuid
ANDROID_JAR = 'third_party/android_jar/lib-v{api}/android.jar'
TOOLS_DIR = os.path.abspath(os.path.normpath(os.path.join(__file__, '..')))
@@ -44,6 +45,8 @@
RT_JAR = os.path.join(REPO_ROOT, 'third_party/openjdk/openjdk-rt-1.8/rt.jar')
R8LIB_KEEP_RULES = os.path.join(REPO_ROOT, 'src/main/keep.txt')
+TEST_RESULT_BUCKET = 'r8-test-results'
+
def PrintCmd(s):
if type(s) is list:
s = ' '.join(s)
@@ -180,6 +183,15 @@
def __exit__(self, *_):
shutil.rmtree(self._temp_dir, ignore_errors=True)
+def archive_failures():
+ upload_dir = os.path.join(REPO_ROOT, 'build', 'reports', 'tests')
+ u_dir = uuid.uuid4()
+ destination = 'gs://%s/%s' % (TEST_RESULT_BUCKET, u_dir)
+ upload_dir_to_cloud_storage(upload_dir, destination, is_html=True)
+ url = 'http://storage.googleapis.com/%s/%s/test/index.html' % (TEST_RESULT_BUCKET, u_dir)
+ print 'Test results available at: %s' % url
+ print '@@@STEP_LINK@Test failures@%s@@@' % url
+
class ChangedWorkingDirectory(object):
def __init__(self, working_directory):
self._working_directory = working_directory