Merge "Add cache for getting the clinit method on a DexClass"
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 88c1b0a..6a6cd08 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
@@ -916,7 +916,7 @@
previous = printMethod(code, "IR after disable assertions (SSA)", previous);
- if (options.enableNonNullTracking && nonNullTracker != null) {
+ if (nonNullTracker != null) {
nonNullTracker.addNonNull(code);
assert code.isConsistentSSA();
}
@@ -975,7 +975,7 @@
invertConditionalsForTesting(code);
}
- if (options.enableNonNullTracking && nonNullTracker != null) {
+ if (nonNullTracker != null) {
// Computation of non-null parameters on normal exits rely on the existence of non-null IRs.
nonNullTracker.computeNonNullParamOnNormalExits(feedback, code);
nonNullTracker.cleanupNonNull(code);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
index ec338ca..489891a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
@@ -120,14 +120,28 @@
knownToBeNonNullValues.add(knownToBeNonNullValue);
}
}
- if (current.isInvokeMethod()
- && !current.isInvokePolymorphic()
- && appView.appInfo().hasLiveness()) {
- DexEncodedMethod singleTarget =
- current
- .asInvokeMethod()
- .lookupSingleTarget(
- appView.appInfo().withLiveness(), code.method.method.holder);
+ if (current.isInvokeMethod() && !current.isInvokePolymorphic()) {
+ DexEncodedMethod singleTarget = null;
+ if (appView.enableWholeProgramOptimizations()) {
+ assert appView.appInfo().hasLiveness();
+ singleTarget =
+ current
+ .asInvokeMethod()
+ .lookupSingleTarget(
+ appView.appInfo().withLiveness(), code.method.method.holder);
+ } else {
+ // Even in D8, invoke-{direct|static} can be resolved without liveness.
+ // Due to the incremental compilation, though, it is allowed only if the holder of the
+ // invoked method is same as that of the method we are processing now.
+ DexMethod invokedMethod = current.asInvokeMethod().getInvokedMethod();
+ if (invokedMethod.holder == code.method.method.holder) {
+ if (current.isInvokeDirect()) {
+ singleTarget = appView.appInfo().lookupDirectTarget(invokedMethod);
+ } else if (current.isInvokeStatic()) {
+ singleTarget = appView.appInfo().lookupStaticTarget(invokedMethod);
+ }
+ }
+ }
if (singleTarget != null
&& singleTarget.getOptimizationInfo().getNonNullParamOnNormalExits() != null) {
BitSet facts = singleTarget.getOptimizationInfo().getNonNullParamOnNormalExits();
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 2bc4483..64624d3 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -414,6 +414,10 @@
continue;
}
DexDefinition dependentDefinition = appView.definitionFor(dependentItem);
+ if (dependentDefinition == null) {
+ assert false;
+ continue;
+ }
if (!dependentDefinition.isStaticMember()) {
enqueueRootItem(holder, entry.getValue());
// Enough to enqueue the known holder once.
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index 5a71add..52952a5 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -1848,9 +1848,54 @@
}
}
+ private static class VmErrors {
+ private final Set<TestRuntime> failedVms = new HashSet<>();
+ private StringBuilder message;
+
+ private void addShouldHaveFailedError(CompilerUnderTest compilerUnderTest, TestRuntime vm) {
+ addFailure(vm);
+ message.append(
+ "FAILURE: Test should have failed on "
+ + vm
+ + " after compiling with "
+ + compilerUnderTest
+ + ".\n");
+ }
+
+ private void addFailedOnRunError(
+ CompilerUnderTest compilerUnderTest, TestRuntime vm, AssertionError error) {
+ addFailure(vm);
+ message.append(
+ "FAILURE: Test failed on "
+ + vm
+ + " after compiling with "
+ + compilerUnderTest
+ + ", error:\n"
+ + error.getMessage()
+ + "\n");
+ }
+
+ private void addFailure(TestRuntime vm) {
+ if (message == null) {
+ message = new StringBuilder();
+ }
+ failedVms.add(vm);
+ }
+ }
+
protected void runJctfTest(
CompilerUnderTest compilerUnderTest, String classFilePath, String fullClassName)
throws IOException, CompilationFailedException {
+ VmErrors vmErrors = runJctfTestCore(compilerUnderTest, classFilePath, fullClassName);
+ if (vmErrors.message != null) {
+ throw new RuntimeException(vmErrors.message.toString());
+ }
+ }
+
+ private VmErrors runJctfTestCore(
+ CompilerUnderTest compilerUnderTest, String classFilePath, String fullClassName)
+ throws IOException, CompilationFailedException {
+ VmErrors vmErrors = new VmErrors();
List<TestRuntime> vms = new ArrayList<>();
if (compilerUnderTest == CompilerUnderTest.R8CF) {
for (CfVm vm : TestParametersBuilder.getAvailableCfVms()) {
@@ -1890,7 +1935,7 @@
}
if (vmSpecs.isEmpty()) {
- return;
+ return vmErrors;
}
File classFile = new File(JCTF_TESTS_PREFIX + "/" + classFilePath);
@@ -1959,7 +2004,7 @@
runJctfTestDoRunOnJava(
fileNames, vmSpec.spec, fullClassName, compilationMode, vmSpec.vm.asCf().getVm());
}
- return;
+ return vmErrors;
}
CompilationOptions compilationOptions = null;
@@ -1981,17 +2026,31 @@
Files.copy(
compiledDir.toPath().resolve("classes.dex"),
vmSpec.spec.directory.toPath().resolve("classes.dex"));
- runJctfTestDoRunOnArt(fileNames, vmSpec.spec, fullClassName, vmSpec.vm.asDex().getVm());
+
+ AssertionError vmError = null;
+ try {
+ runJctfTestDoRunOnArt(fileNames, vmSpec.spec, fullClassName, vmSpec.vm.asDex().getVm());
+ } catch (AssertionError e) {
+ vmError = e;
+ }
+ if (vmSpec.spec.failsOnRun && vmError == null) {
+ vmErrors.addShouldHaveFailedError(firstCompilerUnderTest, vmSpec.vm);
+ } else if (!vmSpec.spec.failsOnRun && vmError != null) {
+ vmErrors.addFailedOnRunError(firstCompilerUnderTest, vmSpec.vm, vmError);
+ }
}
if (compilerUnderTest != CompilerUnderTest.R8_AFTER_D8) {
- return;
+ return vmErrors;
}
// Second pass (R8), if R8_AFTER_D8.
CompilationOptions r8CompilationOptions = null;
File r8CompiledDir = temp.newFolder();
for (VmSpec vmSpec : vmSpecs) {
+ if (vmSpec.spec.failsOnRun || vmErrors.failedVms.contains(vmSpec.vm)) {
+ continue;
+ }
File r8ResultDir = temp.newFolder("r8-output-" + vmSpec.vm.toString());
TestSpecification specification =
JctfTestSpecifications.getExpectedOutcome(
@@ -2019,8 +2078,13 @@
Files.copy(
r8CompiledDir.toPath().resolve("classes.dex"),
specification.directory.toPath().resolve("classes.dex"));
- runJctfTestDoRunOnArt(fileNames, specification, fullClassName, vmSpec.vm.asDex().getVm());
+ try {
+ runJctfTestDoRunOnArt(fileNames, specification, fullClassName, vmSpec.vm.asDex().getVm());
+ } catch (AssertionError e) {
+ vmErrors.addFailedOnRunError(CompilerUnderTest.R8, vmSpec.vm, e);
+ }
}
+ return vmErrors;
}
private void runJctfTestDoRunOnArt(
@@ -2061,10 +2125,6 @@
builder.setMainClass(JUNIT_TEST_RUNNER);
builder.appendProgramArgument(fullClassName);
- if (specification.failsOnRun) {
- expectException(AssertionError.class);
- }
-
try {
ToolHelper.runArt(builder);
} catch (AssertionError e) {
@@ -2072,9 +2132,6 @@
specification.resolveFile("classes.dex"), e);
throw e;
}
- if (specification.failsOnRun) {
- System.err.println("Should have failed run with art.");
- }
}
private void runJctfTestDoRunOnJava(
diff --git a/src/test/java/com/android/tools/r8/cf/BootstrapCurrentEqualityTest.java b/src/test/java/com/android/tools/r8/cf/BootstrapCurrentEqualityTest.java
index fc00afb..d96d999 100644
--- a/src/test/java/com/android/tools/r8/cf/BootstrapCurrentEqualityTest.java
+++ b/src/test/java/com/android/tools/r8/cf/BootstrapCurrentEqualityTest.java
@@ -13,6 +13,8 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.ExternalR8TestCompileResult;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.FileUtils;
@@ -25,17 +27,22 @@
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
/**
* This test relies on a freshly built build/libs/r8lib_with_deps.jar. If this test fails remove
* build directory and rebuild r8lib_with_deps by calling test.py or gradle r8libWithdeps.
*/
+@RunWith(Parameterized.class)
public class BootstrapCurrentEqualityTest extends TestBase {
private static final Path MAIN_KEEP = Paths.get("src/main/keep.txt");
@@ -54,8 +61,19 @@
@BeforeClass
public static void beforeAll() throws Exception {
- r8R8Debug = compileR8(CompilationMode.DEBUG);
- r8R8Release = compileR8(CompilationMode.RELEASE);
+ if (data().stream().count() > 0) {
+ r8R8Debug = compileR8(CompilationMode.DEBUG);
+ r8R8Release = compileR8(CompilationMode.RELEASE);
+ }
+ }
+
+ @Parameters
+ public static TestParametersCollection data() {
+ return getTestParameters().withCfRuntimes().build();
+ }
+
+ public BootstrapCurrentEqualityTest(TestParameters parameters) {
+ // TODO: use parameters to run on the right java.
}
private static Pair<Path, Path> compileR8(CompilationMode mode) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/cf/BootstrapTest.java b/src/test/java/com/android/tools/r8/cf/BootstrapTest.java
index fc24ed3..883c2c6 100644
--- a/src/test/java/com/android/tools/r8/cf/BootstrapTest.java
+++ b/src/test/java/com/android/tools/r8/cf/BootstrapTest.java
@@ -13,6 +13,8 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.FileUtils;
@@ -23,7 +25,11 @@
import java.util.Collections;
import java.util.List;
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 BootstrapTest extends TestBase {
private static final Path R8_STABLE_JAR = Paths.get("third_party/r8/r8.jar");
@@ -56,6 +62,15 @@
}
}
+ @Parameters
+ public static TestParametersCollection data() {
+ return getTestParameters().withCfRuntimes().build();
+ }
+
+ public BootstrapTest(TestParameters parameters) {
+ // TODO: use parameters to fork the right Java.
+ }
+
@Test
public void test() throws Exception {
// Run hello.jar to ensure it exists and is valid.
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 5d4f802..ef53f73 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -20,6 +20,8 @@
import com.android.tools.r8.R8Command;
import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.dex.ApplicationWriter;
import com.android.tools.r8.dex.Constants;
@@ -79,6 +81,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -95,7 +98,11 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public class MainDexListTests extends TestBase {
private static final int MAX_METHOD_COUNT = Constants.U16BIT_MAX;
@@ -106,6 +113,15 @@
private static final int MANY_CLASSES_MULTI_DEX_METHODS_PER_CLASS = 10;
private static List<String> MANY_CLASSES;
+ @Parameters
+ public static TestParametersCollection data() {
+ return getTestParameters().withCfRuntimes().build();
+ }
+
+ public MainDexListTests(TestParameters parameters) {
+ // We ignore the paramters, but only run once instead of running on every vm
+ }
+
interface Runner {
void run(DiagnosticsHandler handler) throws Throwable;
}
@@ -117,6 +133,9 @@
// Generate the test applications in a @BeforeClass method, as they are used by several tests.
@BeforeClass
public static void generateTestApplications() throws Throwable {
+ if (data().stream().count() == 0) {
+ return;
+ }
ImmutableList.Builder<String> builder = ImmutableList.builder();
for (int i = 0; i < MANY_CLASSES_COUNT; ++i) {
String pkg = i % 2 == 0 ? "a" : "b";
diff --git a/tools/archive.py b/tools/archive.py
index 25e6a4f..9213cc2 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -138,7 +138,7 @@
version = GetGitHash()
destination = GetVersionDestination('gs://', version, is_master)
- if utils.cloud_storage_exists(destination):
+ if utils.cloud_storage_exists(destination) and not options.dry_run:
raise Exception('Target archive directory %s already exists' % destination)
with utils.TempDir() as temp:
version_file = os.path.join(temp, 'r8-version.properties')
diff --git a/tools/as_utils.py b/tools/as_utils.py
index a5bfffe..83d0d15 100644
--- a/tools/as_utils.py
+++ b/tools/as_utils.py
@@ -171,12 +171,13 @@
def MoveProfileReportTo(dest_dir, build_stdout, quiet=False):
html_file = None
profile_message = 'See the profiling report at: '
+ # We are not interested in the profiling report for buildSrc.
for line in build_stdout:
- if profile_message in line:
+ if (profile_message in line) and ('buildSrc' not in line):
+ assert not html_file, "Only one report should be created"
html_file = line[len(profile_message):]
if html_file.startswith('file://'):
html_file = html_file[len('file://'):]
- break
if not html_file:
return
diff --git a/tools/run_on_as_app.py b/tools/run_on_as_app.py
index bb6ac32..5596cd5 100755
--- a/tools/run_on_as_app.py
+++ b/tools/run_on_as_app.py
@@ -250,7 +250,6 @@
'module': '',
'flavor': 'play',
'main_dex_rules': 'multidex-config.pro',
- 'releaseTarget': 'assemblePlayRelease',
'signed_apk_name': 'Signal-play-release-4.32.7.apk'
})
]
@@ -679,8 +678,7 @@
app, repo, options, checkout_dir, temp_dir, shrinker, proguard_config_file):
recompilation_results = []
- # Build app with gradle using -D...keepRuleSynthesisForRecompilation=
- # true.
+ # Build app with gradle using -D...keepRuleSynthesisForRecompilation=true.
out_dir = os.path.join(checkout_dir, 'out', shrinker + '-1')
(apk_dest, profile_dest_dir, ext_proguard_config_file) = \
BuildAppWithShrinker(
@@ -1071,10 +1069,10 @@
else:
# Make a copy of r8.jar and r8lib.jar such that they stay the same for
# the entire execution of this script.
- if 'r8-nolib' in options.shrinker:
+ if 'r8-nolib' in options.shrinker or 'r8-nolib-full' in options.shrinker:
assert os.path.isfile(utils.R8_JAR), 'Cannot build without r8.jar'
shutil.copyfile(utils.R8_JAR, os.path.join(temp_dir, 'r8.jar'))
- if 'r8' in options.shrinker:
+ if 'r8' in options.shrinker or 'r8-full' in options.shrinker:
assert os.path.isfile(utils.R8LIB_JAR), 'Cannot build without r8lib.jar'
shutil.copyfile(utils.R8LIB_JAR, os.path.join(temp_dir, 'r8lib.jar'))