blob: e727904b4b0d3d32d794704d78d6ac28a0b15ee3 [file] [log] [blame]
// 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.ir.optimize;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class MemberValuePropagationTest {
private static final String PACKAGE_NAME = "write_only_field";
private static final String QUALIFIED_CLASS_NAME = PACKAGE_NAME + ".WriteOnlyCls";
private static final Path EXAMPLE_JAR =
Paths.get(ToolHelper.EXAMPLES_BUILD_DIR).resolve(PACKAGE_NAME + FileUtils.JAR_EXTENSION);
private static final Path EXAMPLE_KEEP =
Paths.get(ToolHelper.EXAMPLES_DIR).resolve(PACKAGE_NAME).resolve("keep-rules.txt");
private static final Path DONT_OPTIMIZE =
Paths.get(ToolHelper.EXAMPLES_DIR)
.resolve(PACKAGE_NAME)
.resolve("keep-rules-dontoptimize.txt");
private Backend backend;
@Parameterized.Parameters(name = "Backend: {0}")
public static Collection<TestBase.Backend> data() {
return Arrays.asList(TestBase.Backend.values());
}
public MemberValuePropagationTest(TestBase.Backend backend) {
this.backend = backend;
}
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
@Test
public void testWriteOnlyField_putObject_gone() throws Exception {
List<Path> processedApp = runR8(EXAMPLE_KEEP);
CodeInspector inspector = new CodeInspector(processedApp, null, o -> o.enableCfFrontend = true);
ClassSubject clazz = inspector.clazz(QUALIFIED_CLASS_NAME);
clazz.forAllMethods(
methodSubject -> {
Iterator<InstructionSubject> iterator = methodSubject.iterateInstructions();
while (iterator.hasNext()) {
InstructionSubject instruction = iterator.next();
assertFalse(instruction.isInstancePut() || instruction.isStaticPut());
}
});
}
@Test
public void testWriteOnlyField_dontoptimize() throws Exception {
List<Path> processedApp = runR8(DONT_OPTIMIZE);
CodeInspector inspector = new CodeInspector(processedApp, null, o -> o.enableCfFrontend = true);
ClassSubject clazz = inspector.clazz(QUALIFIED_CLASS_NAME);
assert backend == Backend.DEX || backend == Backend.CF;
clazz.forAllMethods(
methodSubject -> {
Iterator<InstructionSubject> iterator = methodSubject.iterateInstructions();
if (methodSubject.isClassInitializer()) {
int numPuts = 0;
while (iterator.hasNext()) {
if (iterator.next().isStaticPut()) {
++numPuts;
}
}
assertEquals(1, numPuts);
}
if (methodSubject.isInstanceInitializer()) {
int numPuts = 0;
while (iterator.hasNext()) {
if (iterator.next().isInstancePut()) {
++numPuts;
}
}
assertEquals(1, numPuts);
}
});
}
private List<Path> runR8(Path proguardConfig) throws IOException, CompilationFailedException {
Path outputDir = temp.newFolder().toPath();
assert backend == Backend.DEX || backend == Backend.CF;
ToolHelper.runR8(
R8Command.builder()
.setOutput(
outputDir, backend == Backend.DEX ? OutputMode.DexIndexed : OutputMode.ClassFile)
.addProgramFiles(EXAMPLE_JAR)
.addLibraryFiles(TestBase.runtimeJar(backend))
.addProguardConfigurationFiles(proguardConfig)
.setDisableMinification(true)
.build(),
o -> {
o.enableClassInlining = false;
});
return backend == Backend.DEX
? Collections.singletonList(outputDir.resolve(Paths.get("classes.dex")))
: Arrays.stream(
outputDir
.resolve(PACKAGE_NAME)
.toFile()
.listFiles(f -> f.toString().endsWith(".class")))
.map(File::toPath)
.collect(Collectors.toList());
}
}