| // 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.assertTrue; |
| |
| import com.android.tools.r8.CompilationFailedException; |
| import com.android.tools.r8.OutputMode; |
| import com.android.tools.r8.R8Command; |
| import com.android.tools.r8.ToolHelper; |
| import com.android.tools.r8.code.Const4; |
| import com.android.tools.r8.code.InvokeDirect; |
| import com.android.tools.r8.code.IputObject; |
| import com.android.tools.r8.code.NewInstance; |
| import com.android.tools.r8.code.ReturnVoid; |
| import com.android.tools.r8.code.SputObject; |
| import com.android.tools.r8.graph.DexCode; |
| import com.android.tools.r8.graph.DexEncodedMethod; |
| import com.android.tools.r8.utils.DexInspector; |
| import com.android.tools.r8.utils.DexInspector.ClassSubject; |
| import com.android.tools.r8.utils.FileUtils; |
| import java.io.IOException; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.rules.TemporaryFolder; |
| |
| public class MemberValuePropagationTest { |
| private static final String WRITE_ONLY_FIELD = "write_only_field"; |
| private static final Path EXAMPLE_JAR = Paths.get(ToolHelper.EXAMPLES_BUILD_DIR) |
| .resolve(WRITE_ONLY_FIELD + FileUtils.JAR_EXTENSION); |
| private static final Path EXAMPLE_KEEP = Paths.get(ToolHelper.EXAMPLES_DIR) |
| .resolve(WRITE_ONLY_FIELD).resolve("keep-rules.txt"); |
| private static final Path DONT_OPTIMIZE = Paths.get(ToolHelper.EXAMPLES_DIR) |
| .resolve(WRITE_ONLY_FIELD).resolve("keep-rules-dontoptimize.txt"); |
| |
| @Rule |
| public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest(); |
| |
| @Test |
| public void testWriteOnlyField_putObject_gone() throws Exception { |
| Path processedApp = runR8(EXAMPLE_KEEP); |
| DexInspector inspector = new DexInspector(processedApp); |
| ClassSubject clazz = inspector.clazz(WRITE_ONLY_FIELD + ".WriteOnlyCls"); |
| clazz.forAllMethods( |
| methodSubject -> { |
| if (methodSubject.isClassInitializer()) { |
| DexEncodedMethod encodedMethod = methodSubject.getMethod(); |
| DexCode code = encodedMethod.getCode().asDexCode(); |
| assertEquals(4, code.instructions.length); |
| assertTrue(code.instructions[0] instanceof NewInstance); |
| assertTrue(code.instructions[1] instanceof Const4); |
| assertTrue(code.instructions[2] instanceof InvokeDirect); |
| assertTrue(code.instructions[3] instanceof ReturnVoid); |
| } |
| if (methodSubject.isInstanceInitializer()) { |
| DexEncodedMethod encodedMethod = methodSubject.getMethod(); |
| DexCode code = encodedMethod.getCode().asDexCode(); |
| assertEquals(4, code.instructions.length); |
| assertTrue(code.instructions[0] instanceof InvokeDirect); |
| assertTrue(code.instructions[1] instanceof NewInstance); |
| assertTrue(code.instructions[2] instanceof InvokeDirect); |
| assertTrue(code.instructions[3] instanceof ReturnVoid); |
| } |
| }); |
| } |
| |
| @Test |
| public void testWriteOnlyField_dontoptimize() throws Exception { |
| Path processedApp = runR8(DONT_OPTIMIZE); |
| DexInspector inspector = new DexInspector(processedApp); |
| ClassSubject clazz = inspector.clazz(WRITE_ONLY_FIELD + ".WriteOnlyCls"); |
| clazz.forAllMethods( |
| methodSubject -> { |
| if (methodSubject.isClassInitializer()) { |
| DexEncodedMethod encodedMethod = methodSubject.getMethod(); |
| DexCode code = encodedMethod.getCode().asDexCode(); |
| assertEquals(5, code.instructions.length); |
| assertTrue(code.instructions[0] instanceof NewInstance); |
| assertTrue(code.instructions[1] instanceof Const4); |
| assertTrue(code.instructions[2] instanceof InvokeDirect); |
| assertTrue(code.instructions[3] instanceof SputObject); |
| assertTrue(code.instructions[4] instanceof ReturnVoid); |
| } |
| if (methodSubject.isInstanceInitializer()) { |
| DexEncodedMethod encodedMethod = methodSubject.getMethod(); |
| DexCode code = encodedMethod.getCode().asDexCode(); |
| assertEquals(5, code.instructions.length); |
| assertTrue(code.instructions[0] instanceof InvokeDirect); |
| assertTrue(code.instructions[1] instanceof NewInstance); |
| assertTrue(code.instructions[2] instanceof InvokeDirect); |
| assertTrue(code.instructions[3] instanceof IputObject); |
| assertTrue(code.instructions[4] instanceof ReturnVoid); |
| } |
| }); |
| } |
| |
| private Path runR8(Path proguardConfig) throws IOException, CompilationFailedException { |
| Path dexOutputDir = temp.newFolder().toPath(); |
| ToolHelper.runR8( |
| R8Command.builder() |
| .setOutput(dexOutputDir, OutputMode.DexIndexed) |
| .addProgramFiles(EXAMPLE_JAR) |
| .addLibraryFiles(ToolHelper.getDefaultAndroidJar()) |
| .addProguardConfigurationFiles(proguardConfig) |
| .setDisableMinification(true) |
| .build(), |
| o -> o.enableClassInlining = false); |
| return dexOutputDir.resolve("classes.dex"); |
| } |
| } |